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/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..c7a3515 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ +###### Fixes issue #. +- [ ] This pull request follows the coding standards + +###### This PR changes: + - \ No newline at end of file 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..7d2e635 --- /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.1.2 + 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/.travis.yml b/.travis.yml deleted file mode 100644 index 761abcc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -# reference: http://www.objc.io/issue-6/travis-ci.html - -language: objective-c - -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 new file mode 100644 index 0000000..9f668f7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,842 @@ +# Changelog + +## [1.3.0](https://github.com/dogo/SCLAlertView/tree/1.3.0) (2023-12-20) + +[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:** + +- Tap inside the alert will dismiss the alert when using new window and shouldDissmissOnTapOutside=YES [\#211](https://github.com/dogo/SCLAlertView/issues/211) +- crash on - \(void\)disableInteractivePopGesture [\#137](https://github.com/dogo/SCLAlertView/issues/137) + +**Closed issues:** + +- is it possible to change the text colour of title and subtitle of the alert??? [\#260](https://github.com/dogo/SCLAlertView/issues/260) +- not supporting for Swift 4.0 [\#257](https://github.com/dogo/SCLAlertView/issues/257) +- How to replace the latest SCLAlertView? [\#187](https://github.com/dogo/SCLAlertView/issues/187) +- UIWindow is not removed when alert showed and hided using new window [\#185](https://github.com/dogo/SCLAlertView/issues/185) +- Some issues with combination of device rotations. [\#182](https://github.com/dogo/SCLAlertView/issues/182) +- buttons from previous alertViews being displayed [\#167](https://github.com/dogo/SCLAlertView/issues/167) +- pop-up from pop-up enhancement [\#162](https://github.com/dogo/SCLAlertView/issues/162) + +**Merged pull requests:** + +- Fix VoiceOver accessibility [\#261](https://github.com/dogo/SCLAlertView/pull/261) ([tmm1](https://github.com/tmm1)) +- Fix for using as a carthage framework. [\#251](https://github.com/dogo/SCLAlertView/pull/251) ([hankinsoft](https://github.com/hankinsoft)) +- 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:** + +- support NSMutableAttributedString? [\#247](https://github.com/dogo/SCLAlertView/issues/247) +- SCLAlertview in a new window. \(No UIViewController\) : The window cannot be closed [\#246](https://github.com/dogo/SCLAlertView/issues/246) +- help add SCLAlertView in theos ??? [\#245](https://github.com/dogo/SCLAlertView/issues/245) +- SCLAlertView should build without warnings [\#243](https://github.com/dogo/SCLAlertView/issues/243) +- Access a Button [\#242](https://github.com/dogo/SCLAlertView/issues/242) +- window does not disappear when use hideView on first app run [\#237](https://github.com/dogo/SCLAlertView/issues/237) +- 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:** + +- delegate 应该使用weak修饰,否则会造成循环引用 SCLAlertView.swift Line 76 [\#240](https://github.com/dogo/SCLAlertView/issues/240) +- amazing ,but if we can custom button corlor not only custom main corlor [\#236](https://github.com/dogo/SCLAlertView/issues/236) +- XCode 8.2 language error [\#235](https://github.com/dogo/SCLAlertView/issues/235) +- Update CocoaPods [\#233](https://github.com/dogo/SCLAlertView/issues/233) +- Orientation issue in landscape when UIViewcontroller lock orientation in Portrait [\#168](https://github.com/dogo/SCLAlertView/issues/168) + +**Merged pull requests:** + +- added show animation completion block [\#241](https://github.com/dogo/SCLAlertView/pull/241) ([hydr93](https://github.com/hydr93)) +- 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:** + +- Not centered vertically when presented in navigation controller [\#231](https://github.com/dogo/SCLAlertView/issues/231) +- Differentiate color of close/cancel button [\#228](https://github.com/dogo/SCLAlertView/issues/228) +- \[Request\] initial text and 'x' button in text entry [\#227](https://github.com/dogo/SCLAlertView/issues/227) +- One of the two will be used. Which one is undefined. [\#225](https://github.com/dogo/SCLAlertView/issues/225) + +**Merged pull requests:** + +- 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:** + +- Table title overlay of SCLAlertView [\#206](https://github.com/dogo/SCLAlertView/issues/206) + +**Closed issues:** + +- Keyboard pushes up the SCAlertView with IQKeyboardManager [\#223](https://github.com/dogo/SCLAlertView/issues/223) +- Space, when no Title, SubTitle and Image. [\#218](https://github.com/dogo/SCLAlertView/issues/218) +- carthage update fail for special platform [\#217](https://github.com/dogo/SCLAlertView/issues/217) +- Border color [\#216](https://github.com/dogo/SCLAlertView/issues/216) +- Conflict with the IQKeyboardManager [\#215](https://github.com/dogo/SCLAlertView/issues/215) +- Can't set selected on SCLSwitchView [\#214](https://github.com/dogo/SCLAlertView/issues/214) +- is it possible to change subtitle text while alert is showing? [\#213](https://github.com/dogo/SCLAlertView/issues/213) +- Execute block while 'showWaiting' running [\#197](https://github.com/dogo/SCLAlertView/issues/197) +- UIAppearance [\#72](https://github.com/dogo/SCLAlertView/issues/72) + +**Merged pull requests:** + +- Added missing setter in SCLSwitchView [\#226](https://github.com/dogo/SCLAlertView/pull/226) ([acerbetti](https://github.com/acerbetti)) +- 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:** + +- SCLAlert view not covering Navigation or TabBar [\#219](https://github.com/dogo/SCLAlertView/issues/219) +- Button height support [\#212](https://github.com/dogo/SCLAlertView/issues/212) +- Statusbar Visible when showing the SCLAlertView [\#208](https://github.com/dogo/SCLAlertView/issues/208) +- Custom button height [\#207](https://github.com/dogo/SCLAlertView/issues/207) + +**Merged pull requests:** + +- 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:** + +- alert view not work [\#205](https://github.com/dogo/SCLAlertView/issues/205) +- Custom Button Color? [\#204](https://github.com/dogo/SCLAlertView/issues/204) +- 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:** + +- Alerts all placed on top of the nav bar [\#196](https://github.com/dogo/SCLAlertView/issues/196) +- View Hangs after SCLAlert is dismissed when alert is initiated from an action sheet button. [\#173](https://github.com/dogo/SCLAlertView/issues/173) +- After scrolling uitabelview SCLAlertView not working & multiple alert window show [\#169](https://github.com/dogo/SCLAlertView/issues/169) + +**Merged pull requests:** + +- New Feature: Horizontal alignment for buttons. [\#203](https://github.com/dogo/SCLAlertView/pull/203) ([jaespinmora](https://github.com/jaespinmora)) +- 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:** + +- Is SCLAlertView version indicated? [\#188](https://github.com/dogo/SCLAlertView/issues/188) +- Add DSL for simple setup [\#186](https://github.com/dogo/SCLAlertView/issues/186) +- second button no working [\#184](https://github.com/dogo/SCLAlertView/issues/184) +- when I pop multi-SCLAlertViews at the same time,then the window will become entirely black. [\#159](https://github.com/dogo/SCLAlertView/issues/159) + +**Merged pull requests:** + +- fluent: show block added [\#195](https://github.com/dogo/SCLAlertView/pull/195) ([lolgear](https://github.com/lolgear)) +- Fluent style support extension [\#194](https://github.com/dogo/SCLAlertView/pull/194) ([lolgear](https://github.com/lolgear)) +- Devlop [\#190](https://github.com/dogo/SCLAlertView/pull/190) ([changcode](https://github.com/changcode)) +- 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:** + +- 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:** + +- 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:** + +- Tickbox enhancement [\#40](https://github.com/dogo/SCLAlertView/issues/40) +- Switch Alert feature [\#177](https://github.com/dogo/SCLAlertView/pull/177) ([andre-felipe](https://github.com/andre-felipe)) + +**Closed issues:** + +- Anyway to set the popup position? Like height to top? [\#180](https://github.com/dogo/SCLAlertView/issues/180) +- Show alert while running a block [\#176](https://github.com/dogo/SCLAlertView/issues/176) +- Button actionBlocks not working [\#175](https://github.com/dogo/SCLAlertView/issues/175) +- Lag when showing view for first time [\#174](https://github.com/dogo/SCLAlertView/issues/174) +- title width enhancement? [\#166](https://github.com/dogo/SCLAlertView/issues/166) +- Dismiss method? [\#157](https://github.com/dogo/SCLAlertView/issues/157) + +**Merged pull requests:** + +- 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:** + +- 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:** + +- Subtitle does not appear if title is set to nil or empty [\#99](https://github.com/dogo/SCLAlertView/issues/99) + +**Closed issues:** + +- when iOS8,use [\#172](https://github.com/dogo/SCLAlertView/issues/172) +- No Subtitle visible with iOS8.1 [\#164](https://github.com/dogo/SCLAlertView/issues/164) +- 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:** + +- iPad pro split screen support [\#149](https://github.com/dogo/SCLAlertView/issues/149) + +**Closed issues:** + +- Adding a new SCLAlertViewStyle: Question [\#161](https://github.com/dogo/SCLAlertView/issues/161) +- alignment of BodyText.. [\#160](https://github.com/dogo/SCLAlertView/issues/160) +- Is this compatible with retina displays? [\#156](https://github.com/dogo/SCLAlertView/issues/156) +- keyboard bug [\#155](https://github.com/dogo/SCLAlertView/issues/155) +- How do I add SCLAlertView to TheOs project? [\#151](https://github.com/dogo/SCLAlertView/issues/151) +- Make the bounce animation a separate animation [\#150](https://github.com/dogo/SCLAlertView/issues/150) +- SCLAlertView is not working!!!!!!! [\#148](https://github.com/dogo/SCLAlertView/issues/148) +- background does not update if rotate device [\#145](https://github.com/dogo/SCLAlertView/issues/145) + +**Merged pull requests:** + +- Fix for \#164 no Subtitles with iOS8 [\#165](https://github.com/dogo/SCLAlertView/pull/165) ([jusefjames](https://github.com/jusefjames)) +- 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)) + +## [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:** + +- Keyboard & rotation [\#52](https://github.com/dogo/SCLAlertView/issues/52) + +**Closed issues:** + +- Get rid of the icon [\#147](https://github.com/dogo/SCLAlertView/issues/147) +- Strong reference [\#126](https://github.com/dogo/SCLAlertView/issues/126) + +**Merged pull requests:** + +- Added status bar customization [\#146](https://github.com/dogo/SCLAlertView/pull/146) ([D-32](https://github.com/D-32)) +- 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:** + +- AlertView created by initWithNewWindow does not dismiss when touch outside [\#143](https://github.com/dogo/SCLAlertView/issues/143) +- Prepopulate alertview [\#138](https://github.com/dogo/SCLAlertView/issues/138) +- 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:** + +- Adding a countdown to a default button [\#113](https://github.com/dogo/SCLAlertView/issues/113) + +**Merged pull requests:** + +- Feature/countdown timer [\#140](https://github.com/dogo/SCLAlertView/pull/140) ([yatryan](https://github.com/yatryan)) +- 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:** + +- Parenthesis missing in SCLAlertView.m [\#133](https://github.com/dogo/SCLAlertView/issues/133) +- I can't see the added button [\#132](https://github.com/dogo/SCLAlertView/issues/132) +- Subtitle issue not showing properly - urgent [\#131](https://github.com/dogo/SCLAlertView/issues/131) +- adding more control method [\#130](https://github.com/dogo/SCLAlertView/issues/130) +- Swift use [\#129](https://github.com/dogo/SCLAlertView/issues/129) +- How to change default button label? [\#128](https://github.com/dogo/SCLAlertView/issues/128) +- Alertview without the round circle above. [\#125](https://github.com/dogo/SCLAlertView/issues/125) +- previous alert won't go away if new 1 appears [\#124](https://github.com/dogo/SCLAlertView/issues/124) +- when i rename AppDelegate.m to app AppDelegate.mm build error [\#121](https://github.com/dogo/SCLAlertView/issues/121) +- Unable to move alertView so keyboard covers the fields on the alert. [\#118](https://github.com/dogo/SCLAlertView/issues/118) +- with textfield how to set ok button status to disable when the textfiled input not valid [\#115](https://github.com/dogo/SCLAlertView/issues/115) + +**Merged pull requests:** + +- fix bug [\#135](https://github.com/dogo/SCLAlertView/pull/135) ([HuylensHu](https://github.com/HuylensHu)) +- 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:** + +- 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:** + +- Long texts truncated when using custom font [\#84](https://github.com/dogo/SCLAlertView/issues/84) + +**Closed issues:** + +- Pod Install [\#114](https://github.com/dogo/SCLAlertView/issues/114) +- Using SCLAlertView with Swift [\#110](https://github.com/dogo/SCLAlertView/issues/110) +- XCode 6.3 Warning: roperty access is using 'setSubTitleHeight:' method which is deprecated [\#105](https://github.com/dogo/SCLAlertView/issues/105) +- Enhancement: Support iOS 8 Widget frame position [\#102](https://github.com/dogo/SCLAlertView/issues/102) + +**Merged pull requests:** + +- restore interactivePopGesture to previous state \#2 [\#120](https://github.com/dogo/SCLAlertView/pull/120) ([crowriot](https://github.com/crowriot)) +- 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:** + +- SlideInFromCenter show animation with blur UI issue [\#92](https://github.com/dogo/SCLAlertView/issues/92) + +**Closed issues:** + +- When presenting with textField and 2 buttons keyboard cuts off bottom bottom. [\#108](https://github.com/dogo/SCLAlertView/issues/108) +- Using SCLAlert as HUD [\#106](https://github.com/dogo/SCLAlertView/issues/106) +- Does not work on iOS 8 App Extension - 2 Errors [\#101](https://github.com/dogo/SCLAlertView/issues/101) +- EXC\_BAD\_ACCESS [\#100](https://github.com/dogo/SCLAlertView/issues/100) +- Navigation bar not hiding [\#95](https://github.com/dogo/SCLAlertView/issues/95) +- Alert is behind the keyboard [\#80](https://github.com/dogo/SCLAlertView/issues/80) + +**Merged pull requests:** + +- Fix Crash for iOS 7 [\#104](https://github.com/dogo/SCLAlertView/pull/104) ([imkevinxu](https://github.com/imkevinxu)) +- 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:** + +- shouldDismissOnTapOutside not working [\#87](https://github.com/dogo/SCLAlertView/issues/87) +- Custom Icon Image's size is too small [\#86](https://github.com/dogo/SCLAlertView/issues/86) +- Rotate - rotate on Ipad [\#82](https://github.com/dogo/SCLAlertView/issues/82) +- SCLAlertView's button does not show up on iOS 7 [\#81](https://github.com/dogo/SCLAlertView/issues/81) + +**Closed issues:** + +- "use of @import when modules are disabled error" [\#77](https://github.com/dogo/SCLAlertView/issues/77) + +**Merged pull requests:** + +- 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) + +## [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:** + +- 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:** + +- Crash in background thread [\#76](https://github.com/dogo/SCLAlertView/issues/76) +- Add button feature - button type [\#75](https://github.com/dogo/SCLAlertView/issues/75) +- 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:** + +- 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:** + +- Execute block on dismissal [\#69](https://github.com/dogo/SCLAlertView/issues/69) + +**Merged pull requests:** + +- 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:** + +- 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) +- Add custom view [\#62](https://github.com/dogo/SCLAlertView/issues/62) +- SCLAlertView color [\#57](https://github.com/dogo/SCLAlertView/issues/57) +- Long texts truncated [\#38](https://github.com/dogo/SCLAlertView/issues/38) + +**Fixed bugs:** + +- 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:** + +- Alert Moves Upwards When Switching Keyboards [\#45](https://github.com/dogo/SCLAlertView/issues/45) + +**Closed issues:** + +- 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:** + +- background none [\#54](https://github.com/dogo/SCLAlertView/issues/54) + +**Closed issues:** + +- 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:** + +- Without SubTitle? [\#18](https://github.com/dogo/SCLAlertView/issues/18) + +**Fixed bugs:** + +- Device rotations support [\#51](https://github.com/dogo/SCLAlertView/issues/51) + +**Closed issues:** + +- how to customize buttons separately? [\#55](https://github.com/dogo/SCLAlertView/issues/55) +- 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:** + +- 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:** + +- 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:** + +- iPad vs iPhone NavigationBar [\#46](https://github.com/dogo/SCLAlertView/issues/46) +- 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:** + +- Can i write the code anywhere? [\#49](https://github.com/dogo/SCLAlertView/issues/49) +- 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:** + +- iPad landscape orientation for iOS \< 8 is not supported [\#41](https://github.com/dogo/SCLAlertView/issues/41) + +**Closed issues:** + +- Alert Moves After Keyboard Dismisses [\#44](https://github.com/dogo/SCLAlertView/issues/44) +- Change Edit Alert Color [\#43](https://github.com/dogo/SCLAlertView/issues/43) + +**Merged pull requests:** + +- 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:** + +- Improvement: progress dialog [\#15](https://github.com/dogo/SCLAlertView/issues/15) + +**Closed issues:** + +- 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:** + +- Auto window height by subtitle height [\#29](https://github.com/dogo/SCLAlertView/issues/29) + +**Merged pull requests:** + +- New features [\#37](https://github.com/dogo/SCLAlertView/pull/37) ([michalciolek](https://github.com/michalciolek)) +- Last fix [\#35](https://github.com/dogo/SCLAlertView/pull/35) ([ancloid](https://github.com/ancloid)) +- 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:** + +- Alert Positioning in TableView [\#32](https://github.com/dogo/SCLAlertView/issues/32) +- slow [\#31](https://github.com/dogo/SCLAlertView/issues/31) +- Backbutton while SCLAlertView is shown causes zombie views [\#25](https://github.com/dogo/SCLAlertView/issues/25) + +**Merged pull requests:** + +- 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:** + +- typedef ValidationBlock name conflicting [\#27](https://github.com/dogo/SCLAlertView/issues/27) + +**Closed issues:** + +- Now broken on iOS6 [\#30](https://github.com/dogo/SCLAlertView/issues/30) +- 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:** + +- 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:** + +- Alert view keep on moving upwards on different UIKeyboardType [\#23](https://github.com/dogo/SCLAlertView/issues/23) + +**Closed issues:** + +- 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:** + +- Is possible to bind action on default button? [\#4](https://github.com/dogo/SCLAlertView/issues/4) + +**Fixed bugs:** + +- typedef ActionBlock name confliction [\#16](https://github.com/dogo/SCLAlertView/issues/16) +- crash on ios6.1 [\#13](https://github.com/dogo/SCLAlertView/issues/13) + +**Closed issues:** + +- hi, a suggestion of one line about subTitle's height [\#24](https://github.com/dogo/SCLAlertView/issues/24) +- Add image to Alertview? [\#21](https://github.com/dogo/SCLAlertView/issues/21) +- Position not always correct [\#20](https://github.com/dogo/SCLAlertView/issues/20) +- Issue when displaying alert view in landscape [\#14](https://github.com/dogo/SCLAlertView/issues/14) + +**Merged pull requests:** + +- 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:** + +- 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:** + +- Podfile update? [\#12](https://github.com/dogo/SCLAlertView/issues/12) +- is possible to move top when keyboard show? [\#5](https://github.com/dogo/SCLAlertView/issues/5) + +**Merged pull requests:** + +- 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:** + +- Fade animation for 'Done' button... [\#3](https://github.com/dogo/SCLAlertView/issues/3) + +**Merged pull requests:** + +- Button dismiss fade bug [\#8](https://github.com/dogo/SCLAlertView/pull/8) ([mamaral](https://github.com/mamaral)) +- Easier form navigation [\#7](https://github.com/dogo/SCLAlertView/pull/7) ([mamaral](https://github.com/mamaral)) +- 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:** + +- Within UINavigationController [\#2](https://github.com/dogo/SCLAlertView/issues/2) +- 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 Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..43b9b81 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at diautilio@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..501a7d8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Process + +1. Ensure any install or build dependencies are removed before the end of the layer when doing a + build. +2. Update the README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5bc1f49 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true +source "https://rubygems.org" + +ruby "3.1.2" + +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..dba6404 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,119 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.7) + base64 + nkf + rexml + activesupport (7.2.2.2) + 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) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.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.4.1) + bigdecimal (3.3.0) + 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.5) + connection_pool (2.5.4) + drb (2.2.3) + escape (0.0.4) + ethon (0.15.0) + ffi (>= 1.15.0) + ffi (1.17.2-arm64-darwin) + ffi (1.17.2-x86_64-darwin) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.9.0) + mutex_m + i18n (1.14.7) + concurrent-ruby (~> 1.0) + json (2.15.1) + logger (1.7.0) + minitest (5.25.5) + molinillo (0.8.0) + mutex_m (0.3.0) + nanaimo (0.4.0) + nap (1.1.0) + netrc (0.11.0) + nkf (0.2.0) + public_suffix (4.0.7) + rexml (3.4.4) + ruby-macho (2.5.1) + securerandom (0.4.1) + typhoeus (1.5.0) + ethon (>= 0.9.0, < 0.16.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 + arm64-darwin-22 + x86_64-darwin-23 + +DEPENDENCIES + cocoapods + +RUBY VERSION + ruby 3.1.2p20 + +BUNDLED WITH + 2.3.7 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 d7c9bb8..001df7c 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ 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) ![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png)_ ![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png) @@ -15,22 +16,60 @@ Animated Alert View written in Swift but ported to Objective-C, which can be use ![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot6.png) ![BackgroundImage](https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot7.png) -###Modern +### Fluent style ```Objective-C -//Fluent style SCLAlertViewBuilder *builder = [SCLAlertViewBuilder new] .addButtonWithActionBlock(@"Send", ^{ /*work here*/ }); SCLAlertViewShowBuilder *showBuilder = [SCLAlertViewShowBuilder new] -.style(Warning) +.style(SCLAlertViewStyleWarning) .title(@"Title") .subTitle(@"Subtitle") .duration(0); [showBuilder showAlertView:builder.alertView onViewController:self.window.rootViewController]; +// or even +showBuilder.show(builder.alertView, self.window.rootViewController); ``` -###Easy to use +#### Complex +```Objective-C + NSString *title = @"Title"; + NSString *message = @"Message"; + NSString *cancel = @"Cancel"; + NSString *done = @"Done"; + + SCLALertViewTextFieldBuilder *textField = [SCLALertViewTextFieldBuilder new].title(@"Code"); + SCLALertViewButtonBuilder *doneButton = [SCLALertViewButtonBuilder new].title(done) + .validationBlock(^BOOL{ + NSString *code = [textField.textField.text copy]; + return [code isVisible]; + }) + .actionBlock(^{ + NSString *code = [textField.textField.text copy]; + [self confirmPhoneNumberWithCode:code]; + }); + + SCLAlertViewBuilder *builder = [SCLAlertViewBuilder new] + .showAnimationType(SCLAlertViewShowAnimationFadeIn) + .hideAnimationType(SCLAlertViewHideAnimationFadeOut) + .shouldDismissOnTapOutside(NO) + .addTextFieldWithBuilder(textField) + .addButtonWithBuilder(doneButton); + + SCLAlertViewShowBuilder *showBuilder = [SCLAlertViewShowBuilder new] + .style(SCLAlertViewStyleCustom) + .image([SCLAlertViewStyleKit imageOfInfo]) + .color([UIColor blueColor]) + .title(title) + .subTitle(message) + .closeButtonTitle(cancel) + .duration(0.0f); + + [showBuilder showAlertView:builder.alertView onViewController:self]; +``` + +### Easy to use ```Objective-C // Get started SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -52,7 +91,7 @@ SCLAlertView *alert = [[SCLAlertView alloc] init]; SCLAlertView *alert = [[SCLAlertView alloc] initWithWindowWidth:300.0f]; ``` -###SCLAlertview in a new window. (No UIViewController) +### SCLAlertview in a new window. (No UIViewController) ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; @@ -73,11 +112,7 @@ 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 +### Add buttons ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -101,7 +136,7 @@ SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert showSuccess:self title:@"Button View" subTitle:@"This alert view has buttons" closeButtonTitle:@"Done" duration:0.0f]; ``` -###Add button timer +### Add button timer ```Objective-C //The index of the button to add the timer display to. [alert addTimerToButtonIndex:0 reverse:NO]; @@ -116,7 +151,7 @@ SCLAlertView *alert = [[SCLAlertView alloc] init]; ``` -###Add Text Attributes +### Add Text Attributes ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -139,11 +174,11 @@ alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) [alert showSuccess:self title:@"Button View" subTitle:@"Attributed string operation successfully completed." closeButtonTitle:@"Done" duration:0.0f]; ``` -###Add a text field +### Add a text field ```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); @@ -152,13 +187,14 @@ UITextField *textField = [alert addTextField:@"Enter your name"]; [alert showEdit:self title:@"Edit View" subTitle:@"This alert view shows a text box" closeButtonTitle:@"Done" duration:0.0f]; ``` -###Indeterminate progress +### Indeterminate progress ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert showWaiting:self title:@"Waiting..." subTitle:@"Blah de blah de blah, blah. Blah de blah de" closeButtonTitle:nil duration:5.0f]; ``` -###Add a switch button + +### Add a switch button ```Objective-C SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -172,19 +208,31 @@ switchView.tintColor = [UIColor brownColor]; [alert showCustom:self image:[UIImage imageNamed:@"switch"] color:[UIColor brownColor] title:kInfoTitle subTitle:kSubtitle closeButtonTitle:nil duration:0.0f]; ``` -###SCLAlertView properties +### Add custom view +```Objective-C +SCLAlertView *alert = [[SCLAlertView alloc] init]; + +UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 215.0f, 80.0f)]; +customView.backgroundColor = [UIColor redColor]; + +[alert addCustomView:customView]; + +[alert showNotice:self title:@"Title" subTitle:@"This alert view shows a custom view" closeButtonTitle:@"Done" duration:0.0f]; +``` + +### SCLAlertView properties ```Objective-C //Dismiss on tap outside (Default is NO) alert.shouldDismissOnTapOutside = YES; -//Hide animation type (Default is FadeOut) -alert.hideAnimationType = SlideOutToBottom; +//Hide animation type (Default is SCLAlertViewHideAnimationFadeOut) +alert.hideAnimationType = SCLAlertViewHideAnimationSlideOutToBottom; -//Show animation type (Default is SlideInFromTop) -alert.showAnimationType = SlideInFromLeft; +//Show animation type (Default is SCLAlertViewShowAnimationSlideInFromTop) +alert.showAnimationType = SCLAlertViewShowAnimationSlideInFromLeft; -//Set background type (Default is Shadow) -alert.backgroundType = Blur; +//Set background type (Default is SCLAlertViewBackgroundShadow) +alert.backgroundType = SCLAlertViewBackgroundBlur; //Overwrite SCLAlertView (Buttons, top circle and borders) colors alert.customViewColor = [UIColor purpleColor]; @@ -213,7 +261,7 @@ alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_an ``` -###Helpers +### Helpers ```Objective-C //Receiving information that SCLAlertView is dismissed [alert alertIsDismissed:^{ @@ -221,74 +269,88 @@ alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_an }]; ``` -####Alert View Styles +#### Alert View Styles ```Objective-C typedef NS_ENUM(NSInteger, SCLAlertViewStyle) { - Success, - Error, - Notice, - Warning, - Info, - Edit, - Waiting, - Question, - Custom + SCLAlertViewStyleSuccess, + SCLAlertViewStyleError, + SCLAlertViewStyleNotice, + SCLAlertViewStyleWarning, + SCLAlertViewStyleInfo, + SCLAlertViewStyleEdit, + SCLAlertViewStyleWaiting, + SCLAlertViewStyleQuestion, + SCLAlertViewStyleCustom }; ``` -####Alert View hide animation styles +#### Alert View hide animation styles ```Objective-C typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) { - FadeOut, - SlideOutToBottom, - SlideOutToTop, - SlideOutToLeft, - SlideOutToRight, - SlideOutToCenter, - SlideOutFromCenter + SCLAlertViewHideAnimationFadeOut, + SCLAlertViewHideAnimationSlideOutToBottom, + SCLAlertViewHideAnimationSlideOutToTop, + SCLAlertViewHideAnimationSlideOutToLeft, + SCLAlertViewHideAnimationSlideOutToRight, + SCLAlertViewHideAnimationSlideOutToCenter, + SCLAlertViewHideAnimationSlideOutFromCenter, + SCLAlertViewHideAnimationSimplyDisappear }; ``` -####Alert View show animation styles +#### Alert View show animation styles ```Objective-C typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) { - FadeIn, - SlideInFromBottom, - SlideInFromTop, - SlideInFromLeft, - SlideInFromRight, - SlideInFromCenter, - SlideInToCenter + SCLAlertViewShowAnimationFadeIn, + SCLAlertViewShowAnimationSlideInFromBottom, + SCLAlertViewShowAnimationSlideInFromTop, + SCLAlertViewShowAnimationSlideInFromLeft, + SCLAlertViewShowAnimationSlideInFromRight, + SCLAlertViewShowAnimationSlideInFromCenter, + SCLAlertViewShowAnimationSlideInToCenter, + SCLAlertViewShowAnimationSimplyAppear }; ``` -####Alert View background styles +#### Alert View background styles ```Objective-C typedef NS_ENUM(NSInteger, SCLAlertViewBackground) { - Shadow, - Blur, - Transparent + SCLAlertViewBackgroundShadow, + SCLAlertViewBackgroundBlur, + SCLAlertViewBackgroundTransparent }; ``` ### Installation +SCLAlertView-Objective-C is available through : -SCLAlertView-Objective-C is available through [CocoaPods](http://cocoapods.org). +### [CocoaPods](https://cocoapods.org) To install add the following line to your Podfile: pod 'SCLAlertView-Objective-C' + +### [Carthage](https://github.com/Carthage/Carthage) + +``` +github "dogo/SCLAlertView" +``` ### Collaboration I tried to build an easy to use API, while beeing flexible enough for multiple variations, but I'm sure there are ways of improving and adding more features, so feel free to collaborate with ideas, issues and/or pull requests. -###Incoming improvements +### Incoming improvements - More animations - Performance tests - Remove some hardcode values +### Plugin integrations + +- [nativescript-fancyalert for NativeScript](https://github.com/NathanWalker/nativescript-fancyalert) + - Use SCLAlertView with [NativeScript](https://www.nativescript.org/) + ### Thanks to the original team - Design [@SherzodMx](https://twitter.com/SherzodMx) Sherzod Max - Development [@hackua](https://twitter.com/hackua) Viktor Radchenko diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index 4be9550..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 = "0.9.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 a25884a..fa74768 100644 --- a/SCLAlertView.xcodeproj/project.pbxproj +++ b/SCLAlertView.xcodeproj/project.pbxproj @@ -8,6 +8,10 @@ /* Begin PBXBuildFile section */ 572BB1471B8383B3002DEE38 /* SCLTimerDisplay.m in Sources */ = {isa = PBXBuildFile; fileRef = 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */; }; + 726C8FA61EF803310060F33B /* SCLAlertView.h in Headers */ = {isa = PBXBuildFile; fileRef = DDB15FD819D5B98800173158 /* SCLAlertView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 726C8FA71EF805520060F33B /* SCLButton.h in Headers */ = {isa = PBXBuildFile; fileRef = DDB15FD919D5BAA000173158 /* SCLButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 726C8FA81EF805620060F33B /* SCLTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = DD24453A1BAC383600892117 /* SCLTextView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 726C8FA91EF805650060F33B /* SCLSwitchView.h in Headers */ = {isa = PBXBuildFile; fileRef = CF6FB1221C5926FC009715F3 /* SCLSwitchView.h */; settings = {ATTRIBUTES = (Public, ); }; }; CF6FB1241C5926FC009715F3 /* SCLSwitchView.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6FB1231C5926FC009715F3 /* SCLSwitchView.m */; }; DD06C22D1C64EAE500E6F6B0 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD06C22C1C64EAE500E6F6B0 /* UIKit.framework */; }; DD06C22F1C64EAF600E6F6B0 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD06C22E1C64EAF600E6F6B0 /* AudioToolbox.framework */; }; @@ -15,17 +19,31 @@ DD06C2371C64EB9200E6F6B0 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD06C2361C64EB9200E6F6B0 /* CoreGraphics.framework */; }; DD24453C1BAC383600892117 /* SCLTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD24453B1BAC383600892117 /* SCLTextView.m */; }; 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 */; }; + 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 */; }; 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 */; }; 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 */; }; DDB15FDB19D5BAA000173158 /* SCLButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FDA19D5BAA000173158 /* SCLButton.m */; }; DDB15FDE19D5BCF400173158 /* SCLAlertViewResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FDD19D5BCF400173158 /* SCLAlertViewResponder.m */; }; DDB15FE119D5D85B00173158 /* SCLAlertViewStyleKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FE019D5D85B00173158 /* SCLAlertViewStyleKit.m */; }; + DDB2BA1B1E55D4260009DAC9 /* comic-sans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = DDB2BA1A1E55D4260009DAC9 /* comic-sans.ttf */; }; + EF994B151D47AB4A00619DFF /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */; }; + EF994B161D47AB4A00619DFF /* SCLAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FD619D5B96500173158 /* SCLAlertView.m */; }; + EF994B171D47AB4A00619DFF /* SCLButton.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FDA19D5BAA000173158 /* SCLButton.m */; }; + EF994B181D47AB4A00619DFF /* SCLAlertViewResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FDD19D5BCF400173158 /* SCLAlertViewResponder.m */; }; + EF994B191D47AB4A00619DFF /* SCLAlertViewStyleKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FE019D5D85B00173158 /* SCLAlertViewStyleKit.m */; }; + EF994B1A1D47AB4A00619DFF /* SCLTimerDisplay.m in Sources */ = {isa = PBXBuildFile; fileRef = 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */; }; + EF994B1B1D47AB4A00619DFF /* SCLTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = DD24453B1BAC383600892117 /* SCLTextView.m */; }; + EF994B1C1D47AB4A00619DFF /* SCLSwitchView.m in Sources */ = {isa = PBXBuildFile; fileRef = CF6FB1231C5926FC009715F3 /* SCLSwitchView.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,6 +57,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 44E430DB1D889255002FE849 /* SCLAlertViewFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCLAlertViewFramework.h; sourceTree = ""; }; 572BB1451B8383B3002DEE38 /* SCLTimerDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCLTimerDisplay.h; sourceTree = ""; }; 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCLTimerDisplay.m; sourceTree = ""; }; CF6FB1221C5926FC009715F3 /* SCLSwitchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCLSwitchView.h; sourceTree = ""; }; @@ -57,15 +76,19 @@ 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; }; 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 = ""; }; @@ -76,6 +99,9 @@ DDB15FDD19D5BCF400173158 /* SCLAlertViewResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewResponder.m; sourceTree = ""; }; DDB15FDF19D5D85B00173158 /* SCLAlertViewStyleKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCLAlertViewStyleKit.h; sourceTree = ""; }; DDB15FE019D5D85B00173158 /* SCLAlertViewStyleKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewStyleKit.m; sourceTree = ""; }; + DDB2BA1A1E55D4260009DAC9 /* comic-sans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "comic-sans.ttf"; sourceTree = ""; }; + EF994B081D47AB1400619DFF /* SCLAlertViewFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SCLAlertViewFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EF994B0C1D47AB1400619DFF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,6 +123,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EF994B041D47AB1400619DFF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -122,12 +155,43 @@ 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 = ( DDB15FD519D5B96500173158 /* SCLAlertView */, DDB15F9F19D5B7C600173158 /* SCLAlertViewExample */, DDB15FB919D5B7C600173158 /* SCLAlertViewTests */, + EF994B091D47AB1400619DFF /* SCLAlertViewFramework */, DDB15F9E19D5B7C600173158 /* Products */, DD06C2381C64EC5D00E6F6B0 /* Frameworks */, ); @@ -138,6 +202,7 @@ children = ( DDB15F9D19D5B7C600173158 /* SCLAlertView.app */, DDB15FB619D5B7C600173158 /* SCLAlertViewTests.xctest */, + EF994B081D47AB1400619DFF /* SCLAlertViewFramework.framework */, ); name = Products; sourceTree = ""; @@ -146,12 +211,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; @@ -163,6 +227,7 @@ DDB15FD319D5B8DB00173158 /* main.m */, DD4BA9C219DEDD8E008D73EB /* SCLAlertView-Objective-C-prefix.pch */, DD0D295B19D902DA00881F53 /* Info.plist */, + DDB2BA191E55D4260009DAC9 /* Fonts */, DD4BA9BF19DED8EF008D73EB /* Sounds */, ); name = "Supporting Files"; @@ -188,29 +253,65 @@ 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 = ""; }; + DDB2BA191E55D4260009DAC9 /* Fonts */ = { + isa = PBXGroup; + children = ( + DDB2BA1A1E55D4260009DAC9 /* comic-sans.ttf */, + ); + name = Fonts; + path = SCLAlertViewExample/Fonts; + sourceTree = SOURCE_ROOT; + }; + EF994B091D47AB1400619DFF /* SCLAlertViewFramework */ = { + isa = PBXGroup; + children = ( + EF994B0C1D47AB1400619DFF /* Info.plist */, + 44E430DB1D889255002FE849 /* SCLAlertViewFramework.h */, + ); + path = SCLAlertViewFramework; + sourceTree = ""; + }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + EF994B051D47AB1400619DFF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 726C8FA61EF803310060F33B /* SCLAlertView.h in Headers */, + 726C8FA91EF805650060F33B /* SCLSwitchView.h in Headers */, + 726C8FA81EF805620060F33B /* SCLTextView.h in Headers */, + 726C8FA71EF805520060F33B /* SCLButton.h in Headers */, + DD4B77E41D8C580B00CF97C7 /* SCLAlertViewFramework.h in Headers */, + DD5F3E112E954CB700E91C60 /* SCLAlertView+WindowResolver.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ DDB15F9C19D5B7C600173158 /* SCLAlertView */ = { isa = PBXNativeTarget; @@ -247,27 +348,49 @@ productReference = DDB15FB619D5B7C600173158 /* SCLAlertViewTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + EF994B071D47AB1400619DFF /* SCLAlertViewFramework */ = { + isa = PBXNativeTarget; + buildConfigurationList = EF994B131D47AB1400619DFF /* Build configuration list for PBXNativeTarget "SCLAlertViewFramework" */; + buildPhases = ( + EF994B031D47AB1400619DFF /* Sources */, + EF994B041D47AB1400619DFF /* Frameworks */, + EF994B051D47AB1400619DFF /* Headers */, + EF994B061D47AB1400619DFF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SCLAlertViewFramework; + productName = SCLAlertViewFramework; + productReference = EF994B081D47AB1400619DFF /* SCLAlertViewFramework.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DDB15F9519D5B7C600173158 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0700; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = "AnyKey Entertainment"; TargetAttributes = { DDB15F9C19D5B7C600173158 = { CreatedOnToolsVersion = 6.0.1; + LastSwiftMigration = 1200; }; DDB15FB519D5B7C600173158 = { CreatedOnToolsVersion = 6.0.1; TestTargetID = DDB15F9C19D5B7C600173158; }; + EF994B071D47AB1400619DFF = { + CreatedOnToolsVersion = 7.3.1; + }; }; }; buildConfigurationList = DDB15F9819D5B7C600173158 /* Build configuration list for PBXProject "SCLAlertView" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -280,6 +403,7 @@ targets = ( DDB15F9C19D5B7C600173158 /* SCLAlertView */, DDB15FB519D5B7C600173158 /* SCLAlertViewTests */, + EF994B071D47AB1400619DFF /* SCLAlertViewFramework */, ); }; /* End PBXProject section */ @@ -292,6 +416,7 @@ DD4BA9C119DED8EF008D73EB /* right_answer.mp3 in Resources */, DDB15FD019D5B8BF00173158 /* Images.xcassets in Resources */, DD7282B919D6087C00077F54 /* Storyboard.storyboard in Resources */, + DDB2BA1B1E55D4260009DAC9 /* comic-sans.ttf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -302,6 +427,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EF994B061D47AB1400619DFF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -309,16 +441,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; @@ -331,6 +465,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EF994B031D47AB1400619DFF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + 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 */, + EF994B171D47AB4A00619DFF /* SCLButton.m in Sources */, + EF994B1B1D47AB4A00619DFF /* SCLTextView.m in Sources */, + EF994B151D47AB4A00619DFF /* UIImage+ImageEffects.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -361,13 +511,24 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 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; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -376,6 +537,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -388,7 +550,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; @@ -404,13 +566,24 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 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; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -418,13 +591,14 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -437,11 +611,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; }; @@ -450,11 +627,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; }; @@ -471,6 +650,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)"; @@ -487,6 +667,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)"; @@ -494,6 +675,59 @@ }; name = Release; }; + EF994B111D47AB1400619DFF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + 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 = ""; + }; + name = Debug; + }; + EF994B121D47AB1400619DFF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + 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 = ""; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -524,6 +758,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + EF994B131D47AB1400619DFF /* Build configuration list for PBXNativeTarget "SCLAlertViewFramework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EF994B111D47AB1400619DFF /* Debug */, + EF994B121D47AB1400619DFF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = DDB15F9519D5B7C600173158 /* Project object */; 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..5e094fc --- /dev/null +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme new file mode 100644 index 0000000..bc11bcf --- /dev/null +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertViewFramework.xcscheme @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SCLAlertView/SCLAlertView+WindowResolver.h b/SCLAlertView/SCLAlertView+WindowResolver.h new file mode 100644 index 0000000..ade6576 --- /dev/null +++ b/SCLAlertView/SCLAlertView+WindowResolver.h @@ -0,0 +1,24 @@ +// +// SCLAlertView+WindowResolver.h +// SCLAlertView +// +// Created by Diogo Autilio on 07/10/25. +// Copyright (c) 2025 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SCLAlertView (WindowResolver) + +/// Active window (iOS 13+ compatible with UIScene) ++ (nullable UIWindow *)scl_currentKeyWindow; + +/// Resolves the best app view for snapshot/blur. +/// If there is no valid window, returns the provided `fallback`. ++ (nullable UIView *)scl_resolveAppViewWithFallback:(nullable UIView *)fallback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLAlertView+WindowResolver.m b/SCLAlertView/SCLAlertView+WindowResolver.m new file mode 100644 index 0000000..ede91a7 --- /dev/null +++ b/SCLAlertView/SCLAlertView+WindowResolver.m @@ -0,0 +1,45 @@ +// +// SCLAlertView+WindowResolver.m +// SCLAlertView +// +// Created by Diogo Autilio on 07/10/25. +// Copyright (c) 2025 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView+WindowResolver.h" +#import + +@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 8ee366a..2b88841 100755 --- a/SCLAlertView/SCLAlertView.h +++ b/SCLAlertView/SCLAlertView.h @@ -3,459 +3,464 @@ // 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. // -#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) { - Success, - Error, - Notice, - Warning, - Info, - Edit, - Waiting, - Question, - Custom + SCLAlertViewStyleSuccess, + SCLAlertViewStyleError, + SCLAlertViewStyleNotice, + SCLAlertViewStyleWarning, + SCLAlertViewStyleInfo, + SCLAlertViewStyleEdit, + SCLAlertViewStyleWaiting, + SCLAlertViewStyleQuestion, + SCLAlertViewStyleCustom }; -/** Alert hide animation styles - * - * Set SCLAlertView hide animation type. - */ +/** Hide animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) { - FadeOut, - SlideOutToBottom, - SlideOutToTop, - SlideOutToLeft, - SlideOutToRight, - SlideOutToCenter, - SlideOutFromCenter + SCLAlertViewHideAnimationFadeOut, + SCLAlertViewHideAnimationSlideOutToBottom, + SCLAlertViewHideAnimationSlideOutToTop, + SCLAlertViewHideAnimationSlideOutToLeft, + SCLAlertViewHideAnimationSlideOutToRight, + SCLAlertViewHideAnimationSlideOutToCenter, + SCLAlertViewHideAnimationSlideOutFromCenter, + SCLAlertViewHideAnimationSimplyDisappear }; -/** Alert show animation styles - * - * Set SCLAlertView show animation type. - */ +/** Show animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) { - FadeIn, - SlideInFromBottom, - SlideInFromTop, - SlideInFromLeft, - SlideInFromRight, - SlideInFromCenter, - SlideInToCenter + SCLAlertViewShowAnimationFadeIn, + SCLAlertViewShowAnimationSlideInFromBottom, + SCLAlertViewShowAnimationSlideInFromTop, + SCLAlertViewShowAnimationSlideInFromLeft, + SCLAlertViewShowAnimationSlideInFromRight, + SCLAlertViewShowAnimationSlideInFromCenter, + SCLAlertViewShowAnimationSlideInToCenter, + SCLAlertViewShowAnimationSimplyAppear }; -/** Alert background styles - * - * Set SCLAlertView background type. - */ +/** Background styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) { - Shadow, - Blur, - Transparent + SCLAlertViewBackgroundShadow, + SCLAlertViewBackgroundBlur, + 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) - */ -@property BOOL tintTopCircle; +/// 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) - */ -@property BOOL useLargerIcon; - -/** Title Label - * - * The text displayed as title. - */ -@property UILabel *labelTitle; +/// Whether to use a larger icon in the top circle. (Default: NO) +@property (assign, nonatomic) BOOL useLargerIcon; -/** Text view with the body message - * - * Holds the textview. - */ -@property UITextView *viewText; +/// Title label displayed at the top of the alert. +@property (strong, nonatomic, nullable) UILabel *labelTitle; -/** Activity Indicator - * - * Holds the activityIndicator. - */ -@property 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) - */ -@property (nonatomic, assign) BOOL shouldDismissOnTapOutside; +/// Activity indicator used for Waiting style. +@property (strong, nonatomic, nullable) UIActivityIndicatorView *activityIndicatorView; -/** Sound URL - * - * Holds the sound NSURL path. - */ -@property (nonatomic, strong) NSURL *soundURL; +/// If YES, tapping outside the alert dismisses it. (Default: NO) +@property (assign, nonatomic) BOOL shouldDismissOnTapOutside; -/** Set text attributed format block - * - * Holds the attributed string. - */ -@property (nonatomic, copy) SCLAttributedFormatBlock attributedFormatBlock; +/// URL of the sound to play. +@property (strong, nonatomic, nullable) NSURL *soundURL; -/** Set Complete button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (nonatomic, copy) CompleteButtonFormatBlock completeButtonFormatBlock; +/// Provides an attributed string for the body text. +@property (copy, nonatomic, nullable) SCLAttributedFormatBlock attributedFormatBlock; -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (nonatomic, copy) ButtonFormatBlock buttonFormatBlock; +/// Provides full button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; -/** Set force hide block. - * - * When set force hideview method invocation. - */ -@property (nonatomic, copy) SCLForceHideBlock forceHideBlock; +/// Provides button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; -/** Hide animation type - * - * Holds the hide animation type. - * (Default: FadeOut) - */ +/// If set, calling this property triggers hideView. +@property (copy, nonatomic, nullable) SCLForceHideBlock forceHideBlock; + +/// 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 (nonatomic, strong) 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 (nonatomic, strong) UIColor *backgroundViewColor; +/// Custom background view color. +@property (strong, nonatomic, nullable) UIColor *backgroundViewColor; -/** Set custom tint color for icon image. - * - * SCLAlertView icon tint color - */ -@property (nonatomic, strong) 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; -/** Initialize SCLAlertView using a new window. - * - * Init with new window +/// If YES, buttons are laid out horizontally instead of vertically. +@property (nonatomic) BOOL horizontalButtons; + +#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; -/** Hide SCLAlertView - * - * Hide SCLAlertView using animation and removing from super view. +/** + Sets a block to be called when the dismiss animation completes. + + @param dismissAnimationCompletionBlock The completion block. + */ +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock; + +/** + Sets a block to be called when the show animation completes. + + @param showAnimationCompletionBlock The completion block. + */ +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock; + +#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 + +/** + Adds a circular timer to a button. -/** Add Timer Display - * - * @param buttonIndex The index of the button to add the timer display to. - * @param reverse Convert timer to countdown. + @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 -@interface SCLAlertViewShowBuilder : NSObject +@protocol SCLItemsBuilder__Protocol__Fluent +- (void)setupFluent; +@end + +@interface SCLAlertViewBuilder__WithFluent: NSObject @end + +@interface SCLAlertViewShowBuilder : SCLAlertViewBuilder__WithFluent -@property(strong, 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(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(copy, nonatomic, readonly) NSString *parameterCloseButtonTitle; @property(assign, nonatomic, readonly) NSTimeInterval parameterDuration; #pragma mark - Setters @@ -470,10 +475,35 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^duration)(NSTimeInterval duration); - (void)showAlertView:(SCLAlertView *)alertView; -- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController *)controller; +- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController * _Nullable)controller; +@property(copy, nonatomic, readonly) void (^show)(SCLAlertView *view, UIViewController * _Nullable controller); @end -@interface SCLAlertViewBuilder : NSObject +@interface SCLALertViewTextFieldBuilder : SCLAlertViewBuilder__WithFluent + +#pragma mark - Available later after adding +@property(weak, nonatomic, readonly, nullable) SCLTextView *textField; + +#pragma mark - Setters +@property(copy, nonatomic, readonly) SCLALertViewTextFieldBuilder *(^title) (NSString *title); + +@end + +@interface SCLALertViewButtonBuilder : SCLAlertViewBuilder__WithFluent + +#pragma mark - Available later after adding +@property(weak, nonatomic, readonly, nullable) SCLButton *button; + +#pragma mark - Setters +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^title) (NSString *title); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^target) (id target); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^selector) (SEL selector); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^actionBlock) (void(^actionBlock)(void)); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^validationBlock) (BOOL(^validationBlock)(void)); + +@end + +@interface SCLAlertViewBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Parameters @property (strong, nonatomic, readonly) SCLAlertView *alertView; @@ -509,11 +539,13 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) #pragma mark - Custom Setters @property(copy, nonatomic) SCLAlertViewBuilder *(^alertIsDismissed) (SCLDismissBlock dismissBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^alertDismissAnimationIsCompleted) (SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock); +@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); @@ -522,4 +554,10 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithValidationBlock)(NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action); @property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithTarget)(NSString *title, id target, SEL selector); -@end \ No newline at end of file +#pragma mark - Builders +@property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithBuilder)(SCLALertViewButtonBuilder *builder); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addTextFieldWithBuilder)(SCLALertViewTextFieldBuilder *builder); + +@end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index f348852..5c7db95 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -3,62 +3,62 @@ // 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 "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 @interface SCLAlertView () -@property (nonatomic, strong) NSMutableArray *inputs; -@property (nonatomic, strong) NSMutableArray *customViews; -@property (nonatomic, strong) NSMutableArray *buttons; -@property (nonatomic, strong) UIImageView *circleIconImageView; -@property (nonatomic, strong) UIView *circleView; -@property (nonatomic, strong) UIView *circleViewBackground; -@property (nonatomic, strong) UIView *contentView; -@property (nonatomic, strong) UIImageView *backgroundView; -@property (nonatomic, strong) UITapGestureRecognizer *gestureRecognizer; -@property (nonatomic, strong) NSString *titleFontFamily; -@property (nonatomic, strong) NSString *bodyTextFontFamily; -@property (nonatomic, strong) NSString *buttonsFontFamily; -@property (nonatomic, strong) UIWindow *previousWindow; -@property (nonatomic, strong) UIWindow *SCLAlertWindow; -@property (nonatomic, copy) SCLDismissBlock dismissBlock; -@property (nonatomic, assign) SystemSoundID soundID; -@property (nonatomic, weak) UIViewController *rootViewController; -@property (nonatomic, weak) id restoreInteractivePopGestureDelegate; -@property (nonatomic) BOOL canAddObservers; -@property (nonatomic) BOOL keyboardIsVisible; -@property (nonatomic) BOOL usingNewWindow; -@property (nonatomic) BOOL restoreInteractivePopGestureEnabled; +@property (strong, nonatomic) NSMutableArray *inputs; +@property (strong, nonatomic) NSMutableArray *customViews; +@property (strong, nonatomic) NSMutableArray *buttons; +@property (strong, nonatomic) UIImageView *circleIconImageView; +@property (strong, nonatomic) UIView *circleView; +@property (strong, nonatomic) UIView *circleViewBackground; +@property (strong, nonatomic) UIView *contentView; +@property (strong, nonatomic) UIImageView *backgroundView; +@property (strong, nonatomic) UITapGestureRecognizer *gestureRecognizer; +@property (strong, nonatomic) NSString *titleFontFamily; +@property (strong, nonatomic) NSString *bodyTextFontFamily; +@property (strong, nonatomic) NSString *buttonsFontFamily; +@property (strong, nonatomic) UIWindow *previousWindow; +@property (strong, nonatomic) UIWindow *SCLAlertWindow; +@property (copy, nonatomic) SCLDismissBlock dismissBlock; +@property (copy, nonatomic) SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock; +@property (copy, nonatomic) SCLShowAnimationCompletionBlock showAnimationCompletionBlock; +@property (weak, nonatomic) UIViewController *rootViewController; +@property (weak, nonatomic) id restoreInteractivePopGestureDelegate; +@property (assign, nonatomic) SystemSoundID soundID; +@property (assign, nonatomic) BOOL canAddObservers; +@property (assign, nonatomic) BOOL keyboardIsVisible; +@property (assign, nonatomic) BOOL usingNewWindow; +@property (assign, nonatomic) BOOL restoreInteractivePopGestureEnabled; @property (nonatomic) CGFloat backgroundOpacity; @property (nonatomic) CGFloat titleFontSize; @property (nonatomic) CGFloat bodyFontSize; @property (nonatomic) CGFloat buttonsFontSize; @property (nonatomic) CGFloat windowHeight; @property (nonatomic) CGFloat windowWidth; +@property (nonatomic) CGFloat titleHeight; @property (nonatomic) CGFloat subTitleHeight; @property (nonatomic) CGFloat subTitleY; +@property (nonatomic) CGPoint tmpContentViewFrameOrigin; +@property (nonatomic) CGPoint tmpCircleViewFrameOrigin; + @end @implementation SCLAlertView @@ -69,7 +69,6 @@ @implementation SCLAlertView CGFloat kCircleHeightBackground; CGFloat kActivityIndicatorHeight; CGFloat kTitleTop; -CGFloat kTitleHeight; // Timer NSTimer *durationTimer; @@ -94,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]; @@ -114,6 +123,11 @@ - (instancetype)initWithNewWindow return self; } ++ (instancetype)alertWithNewWindow +{ + return [[self alloc] initWithNewWindow]; +} + - (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth { self = [self initWithWindowWidth:windowWidth]; @@ -130,6 +144,8 @@ - (void)dealloc [self restoreInteractivePopGesture]; } +#pragma mark - Observers + - (void)addObservers { if(_canAddObservers) @@ -146,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 { @@ -155,8 +171,8 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth kCircleHeight = 56.0f; kCircleHeightBackground = 62.0f; kActivityIndicatorHeight = 40.0f; - kTitleTop = 24.0f; - kTitleHeight = 40.0f; + kTitleTop = 30.0f; + self.titleHeight = 40.0f; self.subTitleY = 70.0f; self.subTitleHeight = 90.0f; self.circleIconHeight = 20.0f; @@ -166,11 +182,12 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth self.usingNewWindow = NO; self.canAddObservers = YES; self.keyboardIsVisible = NO; - self.hideAnimationType = FadeOut; - self.showAnimationType = SlideInFromTop; - self.backgroundType = Shadow; + self.hideAnimationType = SCLAlertViewHideAnimationFadeOut; + self.showAnimationType = SCLAlertViewShowAnimationSlideInFromTop; + self.backgroundType = SCLAlertViewBackgroundShadow; + self.tintTopCircle = YES; - // Font + // Fonts _titleFontFamily = @"HelveticaNeue"; _bodyTextFontFamily = @"HelveticaNeue"; _buttonsFontFamily = @"HelveticaNeue-Bold"; @@ -181,93 +198,114 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth // Init _labelTitle = [[UILabel alloc] init]; _viewText = [[UITextView alloc] init]; + _viewText.accessibilityTraits = UIAccessibilityTraitStaticText; _contentView = [[UIView alloc] init]; _circleView = [[UIView alloc] init]; _circleViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, kCircleHeightBackground, kCircleHeightBackground)]; _circleIconImageView = [[UIImageView alloc] init]; - _backgroundView = [[UIImageView alloc]initWithFrame:[self mainScreenFrame]]; + _backgroundView = [[UIImageView alloc] initWithFrame:[self mainScreenFrame]]; _buttons = [[NSMutableArray alloc] init]; _inputs = [[NSMutableArray alloc] init]; _customViews = [[NSMutableArray alloc] init]; + self.view.accessibilityViewIsModal = YES; - // Add Subviews + // Add subviews [self.view addSubview:_contentView]; [self.view addSubview:_circleViewBackground]; - // Circle View - _tintTopCircle = YES; - _circleViewBackground.backgroundColor = [UIColor whiteColor]; - _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; + // 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 + _circleViewBackground.backgroundColor = [UIColor whiteColor]; + _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; x = (kCircleHeight - _circleIconHeight) / 2; + + // Circle image view _circleIconImageView.frame = CGRectMake(x, x, _circleIconHeight, _circleIconHeight); - _circleIconImageView.contentMode = UIViewContentModeScaleAspectFill; + _circleIconImageView.contentMode = UIViewContentModeScaleAspectFill; + [_circleViewBackground addSubview:_circleView]; [_circleView addSubview:_circleIconImageView]; - // Background View + // Background view _backgroundView.userInteractionEnabled = YES; // Title - _labelTitle.numberOfLines = 1; + _labelTitle.numberOfLines = 2; + _labelTitle.lineBreakMode = NSLineBreakByWordWrapping; _labelTitle.textAlignment = NSTextAlignmentCenter; _labelTitle.font = [UIFont fontWithName:_titleFontFamily size:_titleFontSize]; - _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, kTitleHeight); + _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]; - - CGRect position = [self.contentView convertRect:self.labelTitle.frame toView:self.view]; - _labelTitle.frame = position; - [self.view addSubview:_labelTitle]; + [_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 { - // Create a new one to show the alert + // 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 = self; + 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; } #pragma mark - Modal Validation -- (BOOL)isModal -{ +- (BOOL)isModal { return (_rootViewController != nil && _rootViewController.presentingViewController); } -#pragma mark - View Cycle +#pragma mark - View Lifecycle - (void)viewWillLayoutSubviews { @@ -279,114 +317,94 @@ - (void)viewWillLayoutSubviews if (_useLargerIcon) { // Adjust icon _circleIconHeight = 70.0f; - _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; // Adjust coordinate variables for larger sized top circle kCircleBackgroundTopPosition = -61.0f; kCircleHeight = 106.0f; kCircleHeightBackground = 122.0f; - kTitleTop = _tintTopCircle ? kCircleHeightBackground / 2: _circleIconHeight / 2 + 8.0f; // Reposition inner circle appropriately CGFloat x = (kCircleHeightBackground - kCircleHeight) / 2; _circleView.frame = CGRectMake(x, x, kCircleHeight, kCircleHeight); + if (_labelTitle.text == nil) { + kTitleTop = kCircleHeightBackground / 2; + } } else { kCircleBackgroundTopPosition = -(kCircleHeightBackground / 2); } - // Check if the rootViewController is modal, if so we need to get the modal size not the main screen size - if([self isModal] && !_usingNewWindow) - { + // 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 main frame + CGRect r; + if (self.view.superview != nil) { + // View is showing, position at center of screen + r = CGRectMake((sz.width-_windowWidth)/2, (sz.height-_windowHeight)/2, _windowWidth, _windowHeight); + } else { + // View is not visible, position outside screen bounds + r = CGRectMake((sz.width-_windowWidth)/2, -_windowHeight, _windowWidth, _windowHeight); } + self.view.frame = r; - if(!_usingNewWindow) - { - // Set new background frame - CGRect newBackgroundFrame = self.backgroundView.frame; - newBackgroundFrame.size = sz; - self.backgroundView.frame = newBackgroundFrame; - - // Set new main frame - CGRect r; - if (self.view.superview != nil) - { - // View is showing, position at center of screen - r = CGRectMake((sz.width-_windowWidth)/2, (sz.height-_windowHeight)/2, _windowWidth, _windowHeight); - } - else - { - // View is not visible, position outside screen bounds - r = CGRectMake((sz.width-_windowWidth)/2, -_windowHeight, _windowWidth, _windowHeight); - } - - // Set frames - self.view.frame = r; - _contentView.frame = CGRectMake(0.0f, 0.0f, _windowWidth, _windowHeight); - _circleViewBackground.frame = CGRectMake(_windowWidth / 2 - kCircleHeightBackground / 2, kCircleBackgroundTopPosition, kCircleHeightBackground, kCircleHeightBackground); - _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; - _circleIconImageView.frame = CGRectMake(kCircleHeight / 2 - _circleIconHeight / 2, kCircleHeight / 2 - _circleIconHeight / 2, _circleIconHeight, _circleIconHeight); - kTitleTop = _useLargerIcon ? kTitleTop : kTitleTop + 4.0f; - _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, kTitleHeight); - } - else - { - CGFloat x = (sz.width - _windowWidth) / 2; - CGFloat y = (sz.height - _windowHeight - (kCircleHeight / 8)) / 2; - - _contentView.frame = CGRectMake(x, y, _windowWidth, _windowHeight); - y -= kCircleHeightBackground / 2; - x = (sz.width - kCircleHeightBackground) / 2; - _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; - _circleViewBackground.frame = CGRectMake(x, y, kCircleHeightBackground, kCircleHeightBackground); - _circleIconImageView.frame = CGRectMake(kCircleHeight / 2 - _circleIconHeight / 2, kCircleHeight / 2 - _circleIconHeight / 2, _circleIconHeight, _circleIconHeight); - kTitleTop = _useLargerIcon ? kTitleTop : kTitleTop + 4.0f; - _labelTitle.frame = CGRectMake(12.0f + self.contentView.frame.origin.x, kTitleTop + self.contentView.frame.origin.y, _windowWidth - 24.0f, kTitleHeight); - } + // Background frame + CGRect newBackgroundFrame = self.backgroundView.frame; + newBackgroundFrame.size = sz; + self.backgroundView.frame = newBackgroundFrame; + + // 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; + _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; + _circleIconImageView.frame = CGRectMake(kCircleHeight / 2 - _circleIconHeight / 2, kCircleHeight / 2 - _circleIconHeight / 2, _circleIconHeight, _circleIconHeight); + _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, _titleHeight); // Text fields - CGFloat y = (_labelTitle.text == nil) ? kTitleTop : kTitleTop + _labelTitle.frame.size.height; + CGFloat y = (_labelTitle.text == nil) ? kTitleTop : (_titleHeight - 10.0f) + _labelTitle.frame.size.height; _viewText.frame = CGRectMake(12.0f, y, _windowWidth - 24.0f, _subTitleHeight); + + if (!_labelTitle && !_viewText) { + y = 0.0f; + } + y += _subTitleHeight + 14.0f; - for (SCLTextView *textField in _inputs) - { + for (SCLTextView *textField in _inputs) { textField.frame = CGRectMake(12.0f, y, _windowWidth - 24.0f, textField.frame.size.height); textField.layer.cornerRadius = 3.0f; y += textField.frame.size.height + 10.0f; } // Custom views - for (UIView *view in _customViews) - { + for (UIView *view in _customViews) { view.frame = CGRectMake(12.0f, y, view.frame.size.width, view.frame.size.height); y += view.frame.size.height + 10.0f; } // Buttons - for (SCLButton *btn in _buttons) - { - btn.frame = CGRectMake(12.0f, y, btn.frame.size.width, btn.frame.size.height); - y += btn.frame.size.height + 10.0f; + CGFloat x = 12.0f; + for (SCLButton *btn in _buttons) { + btn.frame = CGRectMake(x, y, btn.frame.size.width, btn.frame.size.height); + + // Add horizontal or vertical offset according to _horizontalButtons + if (_horizontalButtons) { + x += btn.frame.size.width + 10.0f; + } else { + y += btn.frame.size.height + 10.0f; + } } // Adapt window height according to icon size 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 { @@ -398,7 +416,7 @@ - (UIStatusBarStyle)preferredStatusBarStyle return self.statusBarStyle; } -#pragma mark - Handle gesture +#pragma mark - Gesture Handling - (void)handleTap:(UITapGestureRecognizer *)gesture { @@ -408,14 +426,17 @@ - (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]; hide = NO; } } - if(hide)[self hideView]; + if(hide) + { + [self hideView]; + } } } @@ -426,10 +447,12 @@ - (void)setShouldDismissOnTapOutside:(BOOL)shouldDismissOnTapOutside if(_shouldDismissOnTapOutside) { self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; - [_usingNewWindow ? _SCLAlertWindow : _backgroundView addGestureRecognizer:_gestureRecognizer]; + [_backgroundView addGestureRecognizer:_gestureRecognizer]; } } +#pragma mark - Navigation Gesture + - (void)disableInteractivePopGesture { UINavigationController *navigationController; @@ -443,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; @@ -466,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; @@ -512,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); } @@ -528,7 +551,7 @@ - (void)setSubTitleHeight:(CGFloat)value _subTitleHeight = value; } -#pragma mark - ActivityIndicator +#pragma mark - Activity Indicator - (void)addActivityIndicatorView { @@ -538,7 +561,7 @@ - (void)addActivityIndicatorView [_circleView addSubview:_activityIndicatorView]; } -#pragma mark - UICustomView +#pragma mark - Custom View - (UIView *)addCustomView:(UIView *)customView { @@ -551,7 +574,7 @@ - (UIView *)addCustomView:(UIView *)customView return customView; } -#pragma mark - SwitchView +#pragma mark - Switch View - (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label { @@ -572,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]; @@ -590,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]; @@ -613,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]; @@ -628,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]; @@ -642,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 @@ -676,12 +751,24 @@ - (SCLButton *)addButton:(NSString *)title [btn setTitle:title forState:UIControlStateNormal]; btn.titleLabel.font = [UIFont fontWithName:_buttonsFontFamily size:_buttonsFontSize]; - // Update view height - self.windowHeight += (btn.frame.size.height + ADD_BUTTON_PADDING); - [_contentView addSubview:btn]; [_buttons addObject:btn]; + if (_horizontalButtons) { + // Update buttons width according to the number of buttons + for (SCLButton *bttn in _buttons) { + [bttn adjustWidthWithWindowWidth:self.windowWidth numberOfButtons:[_buttons count]]; + } + + // Update view height + if (!([_buttons count] > 1)) { + self.windowHeight += (btn.frame.size.height + ADD_BUTTON_PADDING); + } + } else { + // Update view height + self.windowHeight += (btn.frame.size.height + ADD_BUTTON_PADDING); + } + return btn; } @@ -736,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; } @@ -778,21 +864,19 @@ - (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse 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 { - if(_usingNewWindow) - { - // Save previous window - self.previousWindow = [UIApplication sharedApplication].keyWindow; + if(_usingNewWindow) { + self.backgroundView.frame = _SCLAlertWindow.bounds; // Add window subview - [_SCLAlertWindow addSubview:_backgroundView]; - } - else - { + [_SCLAlertWindow.rootViewController addChildViewController:self]; + [_SCLAlertWindow.rootViewController.view addSubview:_backgroundView]; + [_SCLAlertWindow.rootViewController.view addSubview:self.view]; + } else { _rootViewController = vc; [self disableInteractivePopGesture]; @@ -815,116 +899,115 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima // Icon style switch (style) { - case Success: + case SCLAlertViewStyleSuccess: viewColor = UIColorFromHEX(0x22B573); iconImage = SCLAlertViewStyleKit.imageOfCheckmark; break; - case Error: + case SCLAlertViewStyleError: viewColor = UIColorFromHEX(0xC1272D); iconImage = SCLAlertViewStyleKit.imageOfCross; break; - case Notice: + case SCLAlertViewStyleNotice: viewColor = UIColorFromHEX(0x727375); iconImage = SCLAlertViewStyleKit.imageOfNotice; break; - case Warning: + case SCLAlertViewStyleWarning: viewColor = UIColorFromHEX(0xFFD110); iconImage = SCLAlertViewStyleKit.imageOfWarning; break; - case Info: + case SCLAlertViewStyleInfo: viewColor = UIColorFromHEX(0x2866BF); iconImage = SCLAlertViewStyleKit.imageOfInfo; break; - case Edit: + case SCLAlertViewStyleEdit: viewColor = UIColorFromHEX(0xA429FF); iconImage = SCLAlertViewStyleKit.imageOfEdit; break; - case Waiting: + case SCLAlertViewStyleWaiting: viewColor = UIColorFromHEX(0x6c125d); break; - case Question: + case SCLAlertViewStyleQuestion: viewColor = UIColorFromHEX(0x727375); iconImage = SCLAlertViewStyleKit.imageOfQuestion; break; - case Custom: + case SCLAlertViewStyleCustom: viewColor = color; iconImage = image; self.circleIconHeight *= 2.0f; break; } - // Custom Alert color + // Custom alert color override if(_customViewColor) { viewColor = _customViewColor; } // Title - if([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) - { + if ([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { self.labelTitle.text = title; - } - else - { - // Title is nil, we can move the body message to center and remove it from superView + + // 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); + self.titleHeight = ht; + self.subTitleY += 20; + } + } else { + // 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) - { + if ([subTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { + if (_attributedFormatBlock == nil) { _viewText.text = subTitle; - } - else - { + } else { self.viewText.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; _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) - { + if (ht < _subTitleHeight) { self.windowHeight -= (_subTitleHeight - ht); self.subTitleHeight = ht; - } - else - { + } else { self.windowHeight += (ht - _subTitleHeight); self.subTitleHeight = ht; } - _viewText.frame = CGRectMake(12.0f, _subTitleY, _windowWidth - 24.0f, _subTitleHeight); - } - else - { - // Subtitle is nil, we can move the title to center and remove it from superView + } else { + // No subtitle: center title and remove body view self.subTitleHeight = 0.0f; self.windowHeight -= _viewText.frame.size.height; [_viewText removeFromSuperview]; + _viewText = nil; // Move up - _labelTitle.frame = CGRectMake(12.0f, 37.0f, _windowWidth - 24.0f, kTitleHeight); + _labelTitle.frame = CGRectMake(12.0f, 37.0f, _windowWidth - 24.0f, _titleHeight); + } + + if (!_labelTitle && !_viewText) { + self.windowHeight -= kTitleTop; } - // Add button, if necessary + // Add button if needed if(completeText != nil) { [self addDoneButtonWithTitle:completeText]; @@ -933,7 +1016,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima // Alert view color and images self.circleView.backgroundColor = self.tintTopCircle ? viewColor : _backgroundViewColor; - if (style == Waiting) + if (style == SCLAlertViewStyleWaiting) { [self.activityIndicatorView startAnimating]; } @@ -953,7 +1036,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima for (SCLButton *btn in _buttons) { - if (style == Warning) + if (style == SCLAlertViewStyleWarning) { [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; } @@ -972,7 +1055,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima } } - // Adding duration + // Duration if (duration > 0) { [durationTimer invalidate]; @@ -981,8 +1064,9 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima { SCLButton *btn = _buttons[buttonTimer.buttonIndex]; btn.timer = buttonTimer; + __weak __typeof(self) weakSelf = self; [buttonTimer startTimerWithTimeLimit:duration completed:^{ - [self buttonTapped:btn]; + [weakSelf buttonTapped:btn]; }]; } else @@ -1003,7 +1087,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima // Show the alert view [self showView]; - // Chainable objects + // Chainable responder return [[SCLAlertViewResponder alloc] init:self]; } @@ -1011,32 +1095,32 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima - (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Success]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleSuccess]; } - (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Error]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleError]; } - (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Notice]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleNotice]; } - (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Warning]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWarning]; } - (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Info]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleInfo]; } - (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Edit]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleEdit]; } - (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration @@ -1046,51 +1130,50 @@ - (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSStr - (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Custom]; + [self showTitle:vc image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleCustom]; } - (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { [self addActivityIndicatorView]; - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Waiting]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWaiting]; } - (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Question]; + [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 { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Success]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleSuccess]; } - (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Error]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleError]; } - (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Notice]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleNotice]; } - (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Warning]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWarning]; } - (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Info]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleInfo]; } - (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Edit]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleEdit]; } - (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration @@ -1100,18 +1183,18 @@ - (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAler - (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Custom]; + [self showTitle:nil image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleCustom]; } - (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { [self addActivityIndicatorView]; - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Waiting]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWaiting]; } - (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration { - [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:Question]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleQuestion]; } #pragma mark - Visibility @@ -1132,6 +1215,16 @@ - (void)alertIsDismissed:(SCLDismissBlock)dismissBlock self.dismissBlock = dismissBlock; } +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock +{ + self.dismissAnimationCompletionBlock = dismissAnimationCompletionBlock; +} + +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock +{ + self.showAnimationCompletionBlock = showAnimationCompletionBlock; +} + - (SCLForceHideBlock)forceHideBlock:(SCLForceHideBlock)forceHideBlock { _forceHideBlock = forceHideBlock; @@ -1145,7 +1238,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 @@ -1165,15 +1258,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; - _backgroundView.image = blurSnapshotImage; + // Final fallback in case it still comes as nil + if (!appView) { + appView = [SCLAlertView scl_resolveAppViewWithFallback:fallbackView]; + } + + [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; } @@ -1190,89 +1297,97 @@ - (void)setBackground { switch (_backgroundType) { - case Shadow: + case SCLAlertViewBackgroundShadow: [self makeShadowBackground]; break; - case Blur: + case SCLAlertViewBackgroundBlur: [self makeBlurBackground]; break; - case Transparent: + case SCLAlertViewBackgroundTransparent: [self makeTransparentBackground]; break; } } -#pragma mark - Show Alert +#pragma mark - Show Alert (Animations) - (void)showView { switch (_showAnimationType) { - case FadeIn: + case SCLAlertViewShowAnimationFadeIn: [self fadeIn]; break; - case SlideInFromBottom: + case SCLAlertViewShowAnimationSlideInFromBottom: [self slideInFromBottom]; break; - case SlideInFromTop: + case SCLAlertViewShowAnimationSlideInFromTop: [self slideInFromTop]; break; - case SlideInFromLeft: + case SCLAlertViewShowAnimationSlideInFromLeft: [self slideInFromLeft]; break; - case SlideInFromRight: + case SCLAlertViewShowAnimationSlideInFromRight: [self slideInFromRight]; break; - case SlideInFromCenter: + case SCLAlertViewShowAnimationSlideInFromCenter: [self slideInFromCenter]; break; - case SlideInToCenter: + case SCLAlertViewShowAnimationSlideInToCenter: [self slideInToCenter]; break; + + case SCLAlertViewShowAnimationSimplyAppear: + [self simplyAppear]; + break; } } -#pragma mark - Hide Alert +#pragma mark - Hide Alert (Animations) - (void)hideView { switch (_hideAnimationType) { - case FadeOut: + case SCLAlertViewHideAnimationFadeOut: [self fadeOut]; break; - case SlideOutToBottom: + case SCLAlertViewHideAnimationSlideOutToBottom: [self slideOutToBottom]; break; - case SlideOutToTop: + case SCLAlertViewHideAnimationSlideOutToTop: [self slideOutToTop]; break; - case SlideOutToLeft: + case SCLAlertViewHideAnimationSlideOutToLeft: [self slideOutToLeft]; break; - case SlideOutToRight: + case SCLAlertViewHideAnimationSlideOutToRight: [self slideOutToRight]; break; - case SlideOutToCenter: + case SCLAlertViewHideAnimationSlideOutToCenter: [self slideOutToCenter]; break; - case SlideOutFromCenter: + case SCLAlertViewHideAnimationSlideOutFromCenter: [self slideOutFromCenter]; break; + + case SCLAlertViewHideAnimationSimplyDisappear: + [self simplyDisappear]; + break; } if (_activityIndicatorView) @@ -1280,6 +1395,11 @@ - (void)hideView [_activityIndicatorView stopAnimating]; } + if (durationTimer) + { + [durationTimer invalidate]; + } + if (self.dismissBlock) { self.dismissBlock(); @@ -1287,7 +1407,7 @@ - (void)hideView if (_usingNewWindow) { - // Restore previous window + // Restore the previous key window after hiding the alert [self.previousWindow makeKeyAndVisible]; self.previousWindow = nil; } @@ -1304,21 +1424,26 @@ - (void)hideView - (void)fadeOut { - [UIView animateWithDuration:0.3f animations:^{ + [self fadeOutWithDuration:0.3f]; +} + +- (void)fadeOutWithDuration:(NSTimeInterval)duration +{ + [UIView animateWithDuration:duration animations:^{ self.backgroundView.alpha = 0.0f; self.view.alpha = 0.0f; } completion:^(BOOL completed) { [self.backgroundView removeFromSuperview]; - if (_usingNewWindow) - { - // Remove current window + [self.view removeFromSuperview]; + [self removeFromParentViewController]; + + if (self.usingNewWindow) { + // Remove current alert window [self.SCLAlertWindow setHidden:YES]; self.SCLAlertWindow = nil; } - else - { - [self.view removeFromSuperview]; - [self removeFromParentViewController]; + if ( self.dismissAnimationCompletionBlock ){ + self.dismissAnimationCompletionBlock(); } }]; } @@ -1391,6 +1516,16 @@ - (void)slideOutFromCenter }]; } +- (void)simplyDisappear +{ + 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(), ^{ + [self fadeOutWithDuration:0]; + }); +} + #pragma mark - Show Animations - (void)fadeIn @@ -1402,68 +1537,50 @@ - (void)fadeIn delay:0.0f options:UIViewAnimationOptionCurveEaseIn animations:^{ - self.backgroundView.alpha = _backgroundOpacity; + self.backgroundView.alpha = self.backgroundOpacity; self.view.alpha = 1.0f; } - completion:nil]; + completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; } - (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; - }]; - }]; - } - 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) { - // nothing - }]; - } + 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; @@ -1471,22 +1588,26 @@ - (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 ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } }]; }]; } - (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; @@ -1494,22 +1615,26 @@ - (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 ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } }]; }]; } - (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; @@ -1517,55 +1642,173 @@ - (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 ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } }]; }]; } - (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 ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } }]; }]; } - (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 ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } }]; }]; } +- (void)simplyAppear +{ + self.backgroundView.alpha = 0.0f; + 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 = self.backgroundOpacity; + self.view.alpha = 1.0f; + 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 +- (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 +@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); +@property(copy, nonatomic) BOOL(^parameterValidationBlock)(void); + +#pragma mark - Available later after adding +@property(weak, nonatomic) SCLButton *button; + +#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)); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^validationBlock) (BOOL(^validationBlock)(void)); + +@end + +@implementation SCLALertViewButtonBuilder +- (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 + + @interface SCLAlertViewBuilder() @property (strong, nonatomic) SCLAlertView *alertView; @@ -1574,7 +1817,180 @@ @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 { self = [super init]; if (self) { @@ -1597,373 +2013,19 @@ - (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 *(^) (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; -} - @end @interface SCLAlertViewShowBuilder() -@property(strong, nonatomic) UIViewController *parameterViewController; + +@property(weak, nonatomic) UIViewController *parameterViewController; @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(assign, nonatomic) SCLAlertViewStyle parameterStyle; @property(copy, nonatomic) NSString *parameterCloseButtonTitle; +@property(assign, nonatomic) SCLAlertViewStyle parameterStyle; @property(assign, nonatomic) NSTimeInterval parameterDuration; #pragma mark - Setters @@ -1976,105 +2038,72 @@ @interface SCLAlertViewShowBuilder() @property(copy, nonatomic) SCLAlertViewShowBuilder *(^style)(SCLAlertViewStyle style); @property(copy, nonatomic) SCLAlertViewShowBuilder *(^closeButtonTitle)(NSString *closeButtonTitle); @property(copy, nonatomic) SCLAlertViewShowBuilder *(^duration)(NSTimeInterval duration); + +#pragma mark - Show +@property(copy, nonatomic) void (^show)(SCLAlertView *view, UIViewController *controller); @end @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 *(^)(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]; } - (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController *)controller { + UIViewController *targetController = controller ? controller : self.parameterViewController; + if (self.parameterImage || self.parameterColor) { - [alertView showTitle:controller image:self.parameterImage color:self.parameterColor title:self.parameterTitle subTitle:self.parameterSubTitle duration:self.parameterDuration completeText:@"" style:self.parameterStyle]; + [alertView showTitle:targetController image:self.parameterImage color:self.parameterColor title:self.parameterTitle subTitle:self.parameterSubTitle duration:self.parameterDuration completeText:self.parameterCloseButtonTitle style:self.parameterStyle]; } else { - [alertView showTitle:controller title:self.parameterTitle subTitle:self.parameterSubTitle style:self.parameterStyle closeButtonTitle:self.parameterCloseButtonTitle duration:self.parameterDuration]; + [alertView showTitle:targetController title:self.parameterTitle subTitle:self.parameterSubTitle style:self.parameterStyle closeButtonTitle:self.parameterCloseButtonTitle duration:self.parameterDuration]; } } @end + diff --git a/SCLAlertView/SCLAlertViewResponder.h b/SCLAlertView/SCLAlertViewResponder.h index a705de6..148a1fc 100644 --- a/SCLAlertView/SCLAlertViewResponder.h +++ b/SCLAlertView/SCLAlertViewResponder.h @@ -3,28 +3,24 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// 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 d7a28a3..2318c53 100644 --- a/SCLAlertView/SCLAlertViewResponder.m +++ b/SCLAlertView/SCLAlertViewResponder.m @@ -3,40 +3,43 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. // #import "SCLAlertViewResponder.h" @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.h b/SCLAlertView/SCLAlertViewStyleKit.h index 5fbb243..9d7cc05 100644 --- a/SCLAlertView/SCLAlertViewStyleKit.h +++ b/SCLAlertView/SCLAlertViewStyleKit.h @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. // #if defined(__has_feature) && __has_feature(modules) @@ -22,43 +22,43 @@ * * TODO */ -+ (UIImage*)imageOfCheckmark; ++ (UIImage *)imageOfCheckmark; /** TODO * * TODO */ -+ (UIImage*)imageOfCross; ++ (UIImage *)imageOfCross; /** TODO * * TODO */ -+ (UIImage*)imageOfNotice; ++ (UIImage *)imageOfNotice; /** TODO * * TODO */ -+ (UIImage*)imageOfWarning; ++ (UIImage *)imageOfWarning; /** TODO * * TODO */ -+ (UIImage*)imageOfInfo; ++ (UIImage *)imageOfInfo; /** TODO * * TODO */ -+ (UIImage*)imageOfEdit; ++ (UIImage *)imageOfEdit; /** TODO * * TODO */ -+ (UIImage*)imageOfQuestion; ++ (UIImage *)imageOfQuestion; /** TODO * diff --git a/SCLAlertView/SCLAlertViewStyleKit.m b/SCLAlertView/SCLAlertViewStyleKit.m index 7fc0973..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-2016 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 old mode 100644 new mode 100755 index 8a46e46..33ebf92 --- a/SCLAlertView/SCLButton.h +++ b/SCLAlertView/SCLButton.h @@ -3,14 +3,12 @@ // 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. // -#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,73 +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 (nonatomic, copy) 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 (nonatomic, copy) 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 (nonatomic, copy) CompleteButtonFormatBlock completeButtonFormatBlock; +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** + Button format block. -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor + Provides button styling. + + Supported keys: + - backgroundColor (UIColor) + - borderWidth (NSNumber/CGFloat) + - borderColor (UIColor) + - textColor (UIColor) */ -@property (nonatomic, copy) ButtonFormatBlock buttonFormatBlock; +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; + +/** + Default background color for the button. -/** Set SCLButton color. - * - * Set SCLButton color. + @note UI_APPEARANCE_SELECTOR is supported. */ -@property (nonatomic, strong) UIColor *defaultBackgroundColor; +@property (strong, nonatomic, nullable) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; -/** Set Target object. - * - * Target is an object that holds the information necessary to send a message to another object when an event occurs. +/** + Target for selector-based actions. + + @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; + +/** + Applies configuration returned by a format block. -/** Parse button configuration - * - * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. - * Set keys : backgroundColor, borderWidth, borderColor, textColor + @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 (nonatomic) SCLTimerDisplay *timer; +@property (strong, nonatomic, nullable) SCLTimerDisplay *timer; + +/** + Designated initializer for SCLButton. -/** Init method - * + @param windowWidth The width of the alert window used to size the button. + @return An initialized SCLButton instance. */ - (instancetype)initWithWindowWidth:(CGFloat)windowWidth; +/** + 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 old mode 100644 new mode 100755 index 6e8f3d0..b4a966d --- a/SCLAlertView/SCLButton.m +++ b/SCLAlertView/SCLButton.m @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. // #import "SCLButton.h" @@ -63,6 +63,14 @@ - (void)setupWithWindowWidth:(CGFloat)windowWidth self.layer.cornerRadius = 3.0f; } +- (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons +{ + CGFloat allButtonsWidth = windowWidth - (MARGIN_BUTTON * 2); + CGFloat buttonWidth = (allButtonsWidth - ((numberOfButtons - 1) * 10)) / numberOfButtons; + + self.frame = CGRectMake(0.0f, 0.0f, buttonWidth, MIN_HEIGHT); +} + - (void)setTitle:(NSString *)title forState:(UIControlState)state { [super setTitle:title forState:state]; @@ -71,6 +79,9 @@ - (void)setTitle:(NSString *)title forState:(UIControlState)state // Update title frame. [self.titleLabel sizeToFit]; + // Update button frame + [self layoutIfNeeded]; + // Get height needed to display title label completely CGFloat buttonHeight = MAX(self.titleLabel.frame.size.height, MIN_HEIGHT); @@ -92,7 +103,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; } @@ -122,6 +135,11 @@ - (void)parseConfig:(NSDictionary *)buttonConfig { self.layer.borderWidth = [buttonConfig[@"borderWidth"] floatValue]; } + + // Add Button custom font with buttonConfig parameters + if (buttonConfig[@"font"]) { + self.titleLabel.font = buttonConfig[@"font"]; + } } #pragma mark - Helpers @@ -129,23 +147,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 5e05c87..5d6be5d 100644 --- a/SCLAlertView/SCLMacros.h +++ b/SCLAlertView/SCLMacros.h @@ -3,17 +3,28 @@ // SCLAlertView // // Created by Diogo Autilio on 10/03/15. -// Copyright (c) 2015 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 4ebd3dc..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 © 2016 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; -@property (strong, nonatomic) UIColor *labelColor; -@property (strong, nonatomic) UIFont *labelFont; -@property (strong, nonatomic) NSString *labelText; +/// 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 44c0fd5..50addfc 100644 --- a/SCLAlertView/SCLSwitchView.m +++ b/SCLAlertView/SCLSwitchView.m @@ -3,12 +3,14 @@ // SCLAlertView // // Created by André Felipe Santos on 27/01/16. -// Copyright © 2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. // #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,71 +56,112 @@ - (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; +- (UIColor *)tintColor +{ + return self.switchKnob.onTintColor; } -- (UIColor *)labelColor { +- (UIColor *)labelColor +{ return self.switchLabel.textColor; } -- (UIFont *)labelFont { +- (UIFont *)labelFont +{ return self.switchLabel.font; } -- (NSString *)labelText { +- (NSString *)labelText +{ return self.switchLabel.text; } -- (BOOL)isSelected { +- (BOOL)isSelected +{ return self.switchKnob.isOn; } #pragma mark - Setters -- (void)setTintColor:(UIColor *)tintColor { +- (void)setTintColor:(UIColor *)tintColor +{ + [super setTintColor:tintColor]; self.switchKnob.onTintColor = tintColor; } -- (void)setLabelColor:(UIColor *)labelColor { +- (void)setLabelColor:(UIColor *)labelColor +{ self.switchLabel.textColor = labelColor; } -- (void)setLabelFont:(UIFont *)labelFont { +- (void)setLabelFont:(UIFont *)labelFont +{ self.switchLabel.font = labelFont; + [self setNeedsLayout]; } -- (void)setLabelText:(NSString *)labelText { +- (void)setLabelText:(NSString *)labelText +{ self.switchLabel.text = labelText; + [self setNeedsLayout]; +} + +- (void)setSelected:(BOOL)selected +{ + self.switchKnob.on = selected; } @end diff --git a/SCLAlertView/SCLTextView.h b/SCLAlertView/SCLTextView.h index 4f91486..4cb4b65 100644 --- a/SCLAlertView/SCLTextView.h +++ b/SCLAlertView/SCLTextView.h @@ -3,15 +3,17 @@ // SCLAlertView // // Created by Diogo Autilio on 9/18/15. -// Copyright © 2015 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 4d5ad69..8fa0271 100644 --- a/SCLAlertView/SCLTextView.m +++ b/SCLAlertView/SCLTextView.m @@ -3,54 +3,82 @@ // SCLAlertView // // Created by Diogo Autilio on 9/18/15. -// Copyright © 2015 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. // #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 = UITextAutocapitalizationTypeWords; 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 cff2d7a..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 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // // Taken from https://stackoverflow.com/questions/11783439/uibutton-with-timer @@ -14,7 +14,7 @@ #endif #import "SCLButton.h" -@interface SCLTimerDisplay : UIView{ +@interface SCLTimerDisplay : UIView { CGFloat currentAngle; CGFloat currentTime; CGFloat timerLimit; @@ -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; -@property (nonatomic) UIColor *color; -@property (nonatomic) BOOL reverse; +/// 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 cb055e4..47a99c2 100644 --- a/SCLAlertView/SCLTimerDisplay.m +++ b/SCLAlertView/SCLTimerDisplay.m @@ -3,23 +3,22 @@ // SCLAlertView // // Created by Taylor Ryan on 8/18/15. -// Copyright (c) 2015 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. // #import "SCLTimerDisplay.h" +#import "SCLMacros.h" @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 @implementation SCLTimerDisplay -#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180) -#define TIMER_STEP .01 -#define START_DEGREE_OFFSET -90 - @synthesize currentAngle; - (instancetype)initWithFrame:(CGRect)frame @@ -29,6 +28,9 @@ - (instancetype)initWithFrame:(CGRect)frame { self.backgroundColor = [UIColor clearColor]; currentAngle = 0.0f; + _color = [UIColor whiteColor]; + running = NO; + pausedElapsed = 0; } return self; } @@ -44,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; @@ -74,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) @@ -83,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/Base.lproj/Storyboard.storyboard b/SCLAlertViewExample/Base.lproj/Storyboard.storyboard index 7c01a6e..e016d6d 100644 --- a/SCLAlertViewExample/Base.lproj/Storyboard.storyboard +++ b/SCLAlertViewExample/Base.lproj/Storyboard.storyboard @@ -1,8 +1,12 @@ - - + + + + + - + + @@ -14,196 +18,254 @@ - + - - + + - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + - + - - - - + + + + - - - + + - + 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/Fonts/comic-sans.ttf b/SCLAlertViewExample/Fonts/comic-sans.ttf new file mode 100644 index 0000000..d17e1be Binary files /dev/null and b/SCLAlertViewExample/Fonts/comic-sans.ttf differ diff --git a/SCLAlertViewExample/Info.plist b/SCLAlertViewExample/Info.plist index 422cdf3..457ae3b 100644 --- a/SCLAlertViewExample/Info.plist +++ b/SCLAlertViewExample/Info.plist @@ -37,6 +37,10 @@ UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortraitUpsideDown + UIAppFonts + + comic-sans.ttf + UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait diff --git a/SCLAlertViewExample/ViewController.m b/SCLAlertViewExample/ViewController.m deleted file mode 100644 index c3e8e2a..0000000 --- a/SCLAlertViewExample/ViewController.m +++ /dev/null @@ -1,300 +0,0 @@ -// -// ViewController.m -// SCLAlertView -// -// Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. -// - -#import "ViewController.h" -#import "SCLAlertView.h" - -@interface ViewController () - -@property (nonatomic, weak) IBOutlet UIScrollView *scrollView; - -@end - -NSString *kSuccessTitle = @"Congratulations"; -NSString *kErrorTitle = @"Connection error"; -NSString *kNoticeTitle = @"Notice"; -NSString *kWarningTitle = @"Warning"; -NSString *kInfoTitle = @"Info"; -NSString *kSubtitle = @"You've just displayed this awesome Pop Up View"; -NSString *kButtonTitle = @"Done"; -NSString *kAttributeTitle = @"Attributed string operation successfully completed."; - -@implementation ViewController - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - // auto size UIScrollView to fit the content - CGRect contentRect = CGRectZero; - for (UIView *view in self.scrollView.subviews) { - contentRect = CGRectUnion(contentRect, view.frame); - } - self.scrollView.contentSize = contentRect.size; -} - -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; -} - -- (IBAction)showSuccess:(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]; - - return buttonConfig; - }; - - [alert addButton:@"Second Button" actionBlock:^(void) { - NSLog(@"Second button tapped"); - }]; - - alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_answer.mp3", [NSBundle mainBundle].resourcePath]]; - - [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; -} - -- (IBAction)showError:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - [alert showError:self title:@"Hold On..." - 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, blah." - closeButtonTitle:@"OK" duration:0.0f]; -} - -- (IBAction)showNotice:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - alert.backgroundType = Blur; - - [alert showNotice:self title:kNoticeTitle subTitle:@"You've just displayed this awesome Pop Up View with blur effect" closeButtonTitle:kButtonTitle duration:0.0f]; -} - -- (IBAction)showWarning:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - [alert showWarning:self title:kWarningTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; -} - -- (IBAction)showInfo:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - alert.shouldDismissOnTapOutside = YES; - - [alert alertIsDismissed:^{ - NSLog(@"SCLAlertView dismissed!"); - }]; - - [alert showInfo:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; -} - -- (IBAction)showEdit:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - SCLTextView *textField = [alert addTextField:@"Enter your name"]; - - [alert addButton:@"Show Name" actionBlock:^(void) { - NSLog(@"Text value: %@", textField.text); - }]; - - [alert showEdit:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; -} - -- (IBAction)showAdvanced:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - alert.backgroundViewColor = [UIColor cyanColor]; - - [alert setTitleFontFamily:@"Superclarendon" withSize:20.0f]; - [alert setBodyTextFontFamily:@"TrebuchetMS" withSize:14.0f]; - [alert setButtonsTextFontFamily:@"Baskerville" withSize:14.0f]; - - [alert addButton:@"First Button" target:self selector:@selector(firstButton)]; - - [alert addButton:@"Second Button" actionBlock:^(void) { - NSLog(@"Second button tapped"); - }]; - - SCLTextView *textField = [alert addTextField:@"Enter your name"]; - - [alert addButton:@"Show Name" actionBlock:^(void) { - NSLog(@"Text value: %@", textField.text); - }]; - - 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]; - - NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; - [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; - - NSRange greenRange = [value rangeOfString:@"successfully" options:NSCaseInsensitiveSearch]; - [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor brownColor] range:greenRange]; - - NSRange underline = [value rangeOfString:@"completed" options:NSCaseInsensitiveSearch]; - [subTitle addAttributes:@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)} range:underline]; - - return subTitle; - }; - - [alert showTitle:self title:@"Congratulations" subTitle:kAttributeTitle style:Success closeButtonTitle:@"Done" duration:0.0f]; -} - -- (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]; -} - -- (IBAction)showCustom:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - UIColor *color = [UIColor colorWithRed:65.0/255.0 green:64.0/255.0 blue:144.0/255.0 alpha:1.0]; - [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]; -} - -- (IBAction)showValidation:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - SCLTextView *evenField = [alert addTextField:@"Enter an even number"]; - evenField.keyboardType = UIKeyboardTypeNumberPad; - - SCLTextView *oddField = [alert addTextField:@"Enter an odd number"]; - oddField.keyboardType = UIKeyboardTypeNumberPad; - - [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]; - 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]; - return NO; - } - - NSInteger evenFieldEntry = (evenField.text).integerValue; - BOOL evenFieldPassedValidation = evenFieldEntry % 2 == 0; - - if (!evenFieldPassedValidation) - { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an even number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [evenField becomeFirstResponder]; - return NO; - } - - NSInteger oddFieldEntry = (oddField.text).integerValue; - BOOL oddFieldPassedValidation = oddFieldEntry % 2 == 1; - - if (!oddFieldPassedValidation) - { - [[[UIAlertView alloc] initWithTitle:@"Whoops!" message:@"That is not an odd number." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - [oddField becomeFirstResponder]; - return NO; - } - return YES; - } actionBlock:^{ - [[[UIAlertView alloc] initWithTitle:@"Great Job!" message:@"Thanks for playing." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - }]; - - [alert showEdit:self title:@"Validation" subTitle:@"Ensure the data is correct before dismissing!" closeButtonTitle:@"Cancel" duration:0]; -} - -- (IBAction)showWaiting:(id)sender -{ - SCLAlertView *alert = [[SCLAlertView alloc] init]; - - alert.showAnimationType = SlideInToCenter; - alert.hideAnimationType = SlideOutFromCenter; - - alert.backgroundType = Transparent; - - [alert showWaiting:self title:@"Waiting..." - subTitle:@"You've just displayed this awesome Pop Up View with transparent background" - closeButtonTitle:nil duration:5.0f]; -} - -- (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]; -} - -- (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 { - SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; - alert.tintTopCircle = NO; - alert.iconTintColor = [UIColor brownColor]; - alert.useLargerIcon = YES; - alert.cornerRadius = 13.0f; - - SCLSwitchView *switchView = [alert addSwitchViewWithLabel:@"Don't show again".uppercaseString]; - switchView.tintColor = [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]; -} - -- (void)firstButton -{ - NSLog(@"First button tapped"); -} -@end diff --git a/SCLAlertViewExample/ViewController.h b/SCLAlertViewExample/ViewController/ViewController.h similarity index 70% rename from SCLAlertViewExample/ViewController.h rename to SCLAlertViewExample/ViewController/ViewController.h index 81de180..8aff9e1 100644 --- a/SCLAlertViewExample/ViewController.h +++ b/SCLAlertViewExample/ViewController/ViewController.h @@ -11,13 +11,17 @@ @interface ViewController : UIViewController - (IBAction)showSuccess:(id)sender; +- (IBAction)showSuccessWithHorizontalButtons:(id)sender; - (IBAction)showError:(id)sender; - (IBAction)showNotice:(id)sender; - (IBAction)showWarning:(id)sender; - (IBAction)showInfo:(id)sender; - (IBAction)showEdit:(id)sender; +- (IBAction)showEditWithHorizontalButtons:(id)sender; +- (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender; - (IBAction)showCustom:(id)sender; - (IBAction)showValidation:(id)sender; +- (IBAction)showValidationWithHorizontalButtons:(id)sender; - (IBAction)showWaiting:(id)sender; @end diff --git a/SCLAlertViewExample/ViewController/ViewController.m b/SCLAlertViewExample/ViewController/ViewController.m new file mode 100644 index 0000000..d5811e6 --- /dev/null +++ b/SCLAlertViewExample/ViewController/ViewController.m @@ -0,0 +1,494 @@ +// +// ViewController.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// 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"; +NSString *kWarningTitle = @"Warning"; +NSString *kInfoTitle = @"Info"; +NSString *kSubtitle = @"You've just displayed this awesome Pop Up View"; +NSString *kButtonTitle = @"Done"; +NSString *kAttributeTitle = @"Attributed string operation successfully completed."; + +@implementation ViewController + +#pragma mark - Success + +- (IBAction)showSuccess:(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]; + return buttonConfig; + }; + + [alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); + }]; + + alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_answer.mp3", [NSBundle mainBundle].resourcePath]]; + + [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; +} + +- (IBAction)showSuccessWithHorizontalButtons:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; + [alert setHorizontalButtons:YES]; + + 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]; + return buttonConfig; + }; + + [alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); + }]; + + alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_answer.mp3", [NSBundle mainBundle].resourcePath]]; + + [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 ..." + 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]; +} + +#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]; +} + +#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]; + + alert.shouldDismissOnTapOutside = YES; + [alert alertIsDismissed:^{ + NSLog(@"SCLAlertView dismissed!"); + }]; + + [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" setDefaultText:nil]; + [alert addButton:@"Show Name" actionBlock:^(void) { + NSLog(@"Text value: %@", textField.text); + }]; + + [alert showEdit:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; +} + +- (IBAction)showEditWithHorizontalButtons:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] init]; + [alert setHorizontalButtons:YES]; + + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; + alert.hideAnimationType = SCLAlertViewHideAnimationSimplyDisappear; + [alert addButton:@"Show Name" actionBlock:^(void) { + NSLog(@"Text value: %@", textField.text); + }]; + + [alert showEdit:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; +} + +#pragma mark - Advanced + +- (IBAction)showAdvanced:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] init]; + + alert.backgroundViewColor = [UIColor cyanColor]; + + [alert setTitleFontFamily:@"Superclarendon" withSize:20.0f]; + [alert setBodyTextFontFamily:@"TrebuchetMS" withSize:14.0f]; + [alert setButtonsTextFontFamily:@"Baskerville" withSize:14.0f]; + + [alert addButton:@"First Button" target:self selector:@selector(firstButton)]; + + [alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); + }]; + + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; + + [alert addButton:@"Show Name" actionBlock:^(void) { + NSLog(@"Text value: %@", textField.text); + }]; + + 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]; + + NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; + + NSRange greenRange = [value rangeOfString:@"successfully" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor brownColor] range:greenRange]; + + NSRange underline = [value rangeOfString:@"completed" options:NSCaseInsensitiveSearch]; + [subTitle addAttributes:@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)} range:underline]; + + return subTitle; + }; + + [alert showTitle:self title:@"Congratulations" subTitle:kAttributeTitle style:SCLAlertViewStyleSuccess closeButtonTitle:@"Done" duration:0.0f]; +} + +- (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] init]; + [alert setHorizontalButtons:YES]; + + alert.backgroundViewColor = [UIColor cyanColor]; + + [alert setTitleFontFamily:@"Superclarendon" withSize:20.0f]; + [alert setBodyTextFontFamily:@"TrebuchetMS" withSize:14.0f]; + [alert setButtonsTextFontFamily:@"Baskerville" withSize:14.0f]; + + [alert addButton:@"First Button" target:self selector:@selector(firstButton)]; + + [alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); + }]; + + SCLTextView *textField = [alert addTextField:@"Enter your name" setDefaultText:nil]; + + [alert addButton:@"Show Name" actionBlock:^(void) { + NSLog(@"Text value: %@", textField.text); + }]; + + 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]; + + NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; + + NSRange greenRange = [value rangeOfString:@"successfully" options:NSCaseInsensitiveSearch]; + [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor brownColor] range:greenRange]; + + NSRange underline = [value rangeOfString:@"completed" options:NSCaseInsensitiveSearch]; + [subTitle addAttributes:@{NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)} range:underline]; + + return subTitle; + }; + + [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]; + + UIColor *color = [UIColor colorWithRed:65.0/255.0 green:64.0/255.0 blue:144.0/255.0 alpha:1.0]; + [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" setDefaultText:nil]; + evenField.keyboardType = UIKeyboardTypeNumberPad; + + 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) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; + return NO; + } + + if (oddField.text.length == 0) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; + return NO; + } + + NSInteger evenFieldEntry = (evenField.text).integerValue; + BOOL evenFieldPassedValidation = evenFieldEntry % 2 == 0; + + if (!evenFieldPassedValidation) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; + return NO; + } + + NSInteger oddFieldEntry = (oddField.text).integerValue; + BOOL oddFieldPassedValidation = oddFieldEntry % 2 == 1; + + if (!oddFieldPassedValidation) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; + return NO; + } + return YES; + } actionBlock:^{ + [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]; +} + +- (IBAction)showValidationWithHorizontalButtons:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] init]; + [alert setHorizontalButtons:YES]; + + SCLTextView *evenField = [alert addTextField:@"Enter an even number" setDefaultText:nil]; + evenField.keyboardType = UIKeyboardTypeNumberPad; + + 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) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; + return NO; + } + + if (oddField.text.length == 0) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"You forgot to add an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; + return NO; + } + + NSInteger evenFieldEntry = (evenField.text).integerValue; + BOOL evenFieldPassedValidation = evenFieldEntry % 2 == 0; + + if (!evenFieldPassedValidation) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an even number." actionBlock:^{ + [evenField becomeFirstResponder]; + }]; + return NO; + } + + NSInteger oddFieldEntry = (oddField.text).integerValue; + BOOL oddFieldPassedValidation = oddFieldEntry % 2 == 1; + + if (!oddFieldPassedValidation) + { + [weakSelf showAlertWithTitle:@"Whoops!" message:@"That is not an odd number." actionBlock:^{ + [oddField becomeFirstResponder]; + }]; + return NO; + } + return YES; + } actionBlock:^{ + [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 = 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]; +} + +#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]; +} + +#pragma mark - Question + +- (IBAction)showQuestion:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] init]; + [alert showQuestion:self title:@"Question?" subTitle:kSubtitle closeButtonTitle:@"Dismiss" duration:0.0f]; +} + +#pragma mark - Switch + +- (IBAction)showSwitch:(id)sender +{ + SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; + alert.tintTopCircle = NO; + alert.iconTintColor = [UIColor brownColor]; + alert.useLargerIcon = YES; + alert.cornerRadius = 13.0f; + + [alert addSwitchViewWithLabel:@"Don't show again".uppercaseString]; + [[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; + }; + + [alert addButton:@"Second Button" actionBlock:^(void) { + NSLog(@"Second button tapped"); + }]; + + alert.soundURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/right_answer.mp3", [NSBundle mainBundle].resourcePath]]; + + [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; +} + +@end diff --git a/SCLAlertViewFramework/Info.plist b/SCLAlertViewFramework/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/SCLAlertViewFramework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/SCLAlertViewFramework/SCLAlertViewFramework.h b/SCLAlertViewFramework/SCLAlertViewFramework.h new file mode 100644 index 0000000..e4576ca --- /dev/null +++ b/SCLAlertViewFramework/SCLAlertViewFramework.h @@ -0,0 +1,17 @@ +// +// SCLAlertViewFramework.h +// SCLAlertView +// +// Created by Eugene Tulusha on 9/13/16. +// Copyright © 2016-2025 AnyKey Entertainment. All rights reserved. +// + +@import Foundation; + +//! Project version number for CryptoSwift. +FOUNDATION_EXPORT double SCLAlertViewFrameworkVersionNumber; + +//! Project version string for CryptoSwift. +FOUNDATION_EXPORT const unsigned char SCLAlertViewFrameworkVersionString[]; + +#import "SCLAlertView.h" diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..fc4993b --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +ruby = "3.1.2"