├── Screenshots
├── screenshot-1.png
├── screenshot-2.png
├── screenshot-3.png
└── screenshot-4.png
├── TBRepeatPicker
├── Resources
│ ├── Icons
│ │ ├── TBRP-Checkmark@2x.png
│ │ └── TBRP-Checkmark@3x.png
│ └── Localizations
│ │ ├── zh-Hant.lproj
│ │ └── TBRPLocalizable.strings
│ │ ├── zh-Hans.lproj
│ │ └── TBRPLocalizable.strings
│ │ ├── ja.lproj
│ │ └── TBRPLocalizable.strings
│ │ ├── ko.lproj
│ │ └── TBRPLocalizable.strings
│ │ └── en.lproj
│ │ └── TBRPLocalizable.strings
├── Array+TBRPAddition.swift
├── String+TBRPAddition.swift
├── RangeReplaceableCollectionType+TBRPAddition.swift
├── UIColor+TBRPAddition.swift
├── NSCalendar+TBRPAddition.swift
├── TBRPCollectionViewLayout.swift
├── TBRPInternationalControl.swift
├── TBRPSwitchCell.swift
├── TBRepeatPicker.swift
├── TBRPCollectionItem.swift
├── TBRPCustomRepeatCell.swift
├── TBRPPickerViewCell.swift
├── TBRPCollectionViewCell.swift
├── TBRPPresetRepeatController.swift
├── TBRecurrence.swift
├── TBRPHelper.swift
└── TBRPCustomRepeatController.swift
├── Example
├── TBRepeatPicker.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── hongxin.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── xcschememanagement.plist
│ │ │ └── TBRepeatPicker.xcscheme
│ └── project.pbxproj
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── AppDelegate.swift
├── SwitchLanguageViewController.swift
└── DemoViewController.swift
├── TBRepeatPicker.podspec
├── LICENSE.txt
└── README.md
/Screenshots/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/Screenshots/screenshot-1.png
--------------------------------------------------------------------------------
/Screenshots/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/Screenshots/screenshot-2.png
--------------------------------------------------------------------------------
/Screenshots/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/Screenshots/screenshot-3.png
--------------------------------------------------------------------------------
/Screenshots/screenshot-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/Screenshots/screenshot-4.png
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Icons/TBRP-Checkmark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/TBRepeatPicker/Resources/Icons/TBRP-Checkmark@2x.png
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Icons/TBRP-Checkmark@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hongxinhope/TBRepeatPicker/HEAD/TBRepeatPicker/Resources/Icons/TBRP-Checkmark@3x.png
--------------------------------------------------------------------------------
/Example/TBRepeatPicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Array+TBRPAddition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+TBRPAddition.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/10/8.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Array where Element : Hashable {
12 | var unique: [Element] {
13 | return Array(Set(self))
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TBRepeatPicker/String+TBRPAddition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+TBRPAddition.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/10/8.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension String {
12 | mutating func removeSubstring(substring: String) {
13 | self = self.stringByReplacingOccurrencesOfString(substring, withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TBRepeatPicker/RangeReplaceableCollectionType+TBRPAddition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RangeReplaceableCollectionType+TBRPAddition.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/9/27.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension RangeReplaceableCollectionType where Generator.Element: Equatable {
12 | mutating func removeObject(object : Generator.Element) {
13 | if let index = self.indexOf(object) {
14 | self.removeAtIndex(index)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Example/TBRepeatPicker.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | TBRepeatPicker.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D3A7C1EA1BB26EAD000605DF
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/TBRepeatPicker/UIColor+TBRPAddition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+TBRPAddition.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/10/9.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIColor {
12 | var rgbComponents:(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
13 | var redValue:CGFloat = 0
14 | var greenValue:CGFloat = 0
15 | var blueValue:CGFloat = 0
16 | var alphaValue:CGFloat = 0
17 |
18 | getRed(&redValue, green: &greenValue, blue: &blueValue, alpha: &alphaValue)
19 |
20 | let bit: CGFloat = 255.0
21 | redValue *= bit
22 | greenValue *= bit
23 | blueValue *= bit
24 |
25 | return (redValue, greenValue, blueValue, alphaValue)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/TBRepeatPicker.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "TBRepeatPicker"
4 | s.version = "1.1.1"
5 | s.summary = "An event repeat rule picker similar to iOS system calendar."
6 | s.homepage = "https://github.com/hongxinhope/TBRepeatPicker"
7 | s.license = { :type => 'MIT', :file => 'LICENSE.txt' }
8 | s.author = { "Xin Hong" => "xin@teambition.com" }
9 | s.source = { :git => "https://github.com/hongxinhope/TBRepeatPicker.git", :tag => s.version.to_s }
10 | s.platform = :ios, '8.0'
11 | s.requires_arc = true
12 | s.source_files = "TBRepeatPicker/*.swift"
13 | s.resource_bundles = { 'TBRepeatPicker' => ['TBRepeatPicker/Resources/*/*.png', 'TBRepeatPicker/Resources/*/*.lproj'] }
14 | s.frameworks = "Foundation", "UIKit"
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/TBRepeatPicker/NSCalendar+TBRPAddition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSCalendar+TBRPAddition.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/9/27.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSCalendar {
12 | class func dayIndexInWeek(date: NSDate) -> Int {
13 | return components(date).weekday
14 | }
15 |
16 | class func dayIndexInMonth(date: NSDate) -> Int {
17 | return components(date).day
18 | }
19 |
20 | class func monthIndexInYear(date: NSDate) -> Int {
21 | return components(date).month
22 | }
23 |
24 | private class func components(date: NSDate) -> NSDateComponents {
25 | let calendar = NSCalendar.currentCalendar()
26 | calendar.locale = NSLocale.currentLocale()
27 | let components = calendar.components([.Month, .Weekday, .Day], fromDate: date)
28 |
29 | return components
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPCollectionViewLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPCollectionViewLayout.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/25.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TBRPCollectionViewLayout: UICollectionViewFlowLayout {
12 | private var mode: TBRPCollectionMode?
13 |
14 | convenience init(mode: TBRPCollectionMode) {
15 | self.init()
16 |
17 | self.mode = mode
18 | if mode == .Days {
19 | itemSize = CGSizeMake(TBRPDaysItemWidth, TBRPDaysItemHeight)
20 | } else {
21 | itemSize = CGSizeMake(TBRPMonthsItemWidth, TBRPMonthsItemHeight)
22 | }
23 | minimumInteritemSpacing = 0
24 | minimumLineSpacing = 0
25 | }
26 |
27 | override func collectionViewContentSize() -> CGSize {
28 | if mode == .Days {
29 | return CGSizeMake(TBRPScreenWidth, TBRPDaysCollectionHeight)
30 | } else {
31 | return CGSizeMake(TBRPScreenWidth, TBRPMonthsCollectionHeight)
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Teambition
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.1.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 5
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPInternationalControl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPInternationalControl.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/30.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TBRPInternationalControl: NSObject {
12 | var language: TBRPLanguage = .English
13 |
14 | convenience init(language: TBRPLanguage!) {
15 | self.init()
16 |
17 | self.language = language
18 | }
19 |
20 | private func localizedForKey(key: String!) -> String? {
21 | let path = NSBundle.mainBundle().pathForResource(TBRPInternationalControl.languageKey(language), ofType: "lproj")
22 | if let _ = path {
23 | let bundle = NSBundle(path: path!)
24 | return bundle!.localizedStringForKey(key, value: nil, table: "TBRPLocalizable")
25 | } else {
26 | return nil
27 | }
28 | }
29 |
30 | func localized(key: String!, comment: String!) -> String {
31 | if let localizedString = localizedForKey(key) as String? {
32 | if localizedString == key {
33 | return comment
34 | }
35 | return localizedString
36 | }
37 | return comment
38 | }
39 |
40 | class func languageKey(language: TBRPLanguage) -> String {
41 | let languageKeys = ["en", "zh-Hans", "zh-Hant", "ko", "ja"]
42 |
43 | return languageKeys[language.rawValue]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPSwitchCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPSwitchCell.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/25.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let SwitchTrailingSpace: CGFloat = 15.0
12 |
13 | protocol TBRPSwitchCellDelegate {
14 | func didSwitch(sender: AnyObject)
15 | }
16 |
17 | class TBRPSwitchCell: TBRPCustomRepeatCell {
18 | var weekSwitch: UISwitch?
19 | var delegate: TBRPSwitchCellDelegate?
20 |
21 | override func awakeFromNib() {
22 | super.awakeFromNib()
23 |
24 | }
25 |
26 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
27 | super.init(style: style, reuseIdentifier: reuseIdentifier)
28 |
29 | weekSwitch = UISwitch()
30 | weekSwitch?.frame.origin.x = TBRPScreenWidth - (weekSwitch?.bounds.size.width)! - SwitchTrailingSpace
31 | weekSwitch?.frame.origin.y = contentView.bounds.size.height / 2 - (weekSwitch?.bounds.size.height)! / 2
32 | weekSwitch?.addTarget(self, action: "switchAction:", forControlEvents: .ValueChanged)
33 | contentView.addSubview(weekSwitch!)
34 | }
35 |
36 | required init?(coder aDecoder: NSCoder) {
37 | fatalError("init(coder:) has not been implemented")
38 | }
39 |
40 | func switchAction(sender: AnyObject) {
41 | if let _ = delegate {
42 | delegate?.didSwitch(sender)
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRepeatPicker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRepeatPicker.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/23.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /*
12 | enum TBRPLanguage: String {
13 | case English = "en"
14 | case SimplifiedChinese = "zh-Hans"
15 | case TraditionalChinese = "zh-Hant"
16 | case Korean = "ko"
17 | case Japanese = "ja"
18 | }
19 | */
20 |
21 | /*
22 | To support Objective-C, we have to use integer enum.
23 | */
24 | @objc enum TBRPLanguage: Int {
25 | case English = 0
26 | case SimplifiedChinese = 1
27 | case TraditionalChinese = 2
28 | case Korean = 3
29 | case Japanese = 4
30 | }
31 |
32 | class TBRepeatPicker: TBRPPresetRepeatController {
33 |
34 | /** Return an initialized repeat picker object.
35 |
36 | - Parameter occurrenceDate: The occurrence date of event. For repeat event, it's the occurrence date of this time. This property will be used for creating weekly/bi-weekly/monthly/yearly/custom recurrence, or judging the type of a recurrence.
37 | - Parameter language: Language of the picker, must be one of the following 5 supported languages:
38 | * TBRPLanguage.English
39 | * TBRPLanguage.SimplifiedChinese
40 | * TBRPLanguage.TraditionalChinese
41 | * TBRPLanguage.Korean
42 | * TBRPLanguage.Japanese
43 | - Parameter tintColor: A tint color which will be used in navigation bar, tableView, and the highlighted items.
44 |
45 | - Returns: An initialized repeat picker object.
46 | */
47 | class func initPicker(occurrenceDate: NSDate, language: TBRPLanguage, tintColor: UIColor) -> TBRepeatPicker {
48 | let repeatPicker = TBRepeatPicker.init(style: .Grouped)
49 |
50 | repeatPicker.occurrenceDate = occurrenceDate
51 | repeatPicker.language = language
52 | repeatPicker.tintColor = tintColor
53 |
54 | return repeatPicker
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/23.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #TBRepeatPicker
2 | TBRepeatPicker is an event repeat rule picker similar to iOS system calendar. You can easily apply it in your project and you'll be happy to do it!
3 |
4 | 
5 |
6 | 
7 |
8 | 
9 |
10 | ##How To Get Started
11 |
12 | ### Podfile
13 | ```ruby
14 | platform :ios, '8.0'
15 | pod "TBRepeatPicker"
16 | ```
17 |
18 | ###Usage
19 | ##### 1. Create and present TBRepeatPicker
20 | ```objective-c
21 | // give the occurrence date of event
22 | let dateFormatter = NSDateFormatter()
23 | dateFormatter.dateFormat = "yyyy-MM-dd"
24 | occurrenceDate = dateFormatter.dateFromString("2015-09-25")!
25 |
26 | // init picker
27 | let repeatPicker = TBRepeatPicker.initPicker(occurrenceDate, language: .English, tintColor: UIColor.blueColor())
28 |
29 | // assign a recurrence to the picker, you can pass nil or do nothing here when the repeat rule is "Never".
30 | repeatPicker.recurrence = TBRecurrence.initMonthly(1, selectedMonthdays: [3, 17], occurrenceDate: occurrenceDate)
31 |
32 | // set delegate
33 | repeatPicker.delegate = self
34 |
35 | // push picker
36 | navigationController?.pushViewController(repeatPicker, animated: true)
37 | ```
38 | Note: You should always use push segue here to present the picker, TBRepeatPicker doesn't support other segues such as modal.
39 |
40 | ##### 2. Implement didPickRecurrence delegate
41 | ```objective-c
42 | func didPickRecurrence(recurrence: TBRecurrence?, repeatPicker: TBRepeatPicker) {
43 | // do something
44 | }
45 | ```
46 |
47 | ## Minimum Requirement
48 | iOS 8.0
49 |
50 | ## Localization
51 | TBRepeatPicker supports 5 languages: English, SimplifiedChinese, TraditionalChinese, Korean, Japanese. You can set the language when init.
52 |
53 | ## Swift and Objective-C
54 | TBRepeatPicker support both Swift and Objective-C.
55 |
56 | in Objective-C, you just need to import a header like this:
57 | ```objective-c
58 | #import "MyApp-Swift.h"
59 | ```
60 |
61 | ## Release Notes
62 | * [Release Notes](https://github.com/hongxinhope/TBRepeatPicker/releases)
63 |
64 | ## License
65 | TBRepeatPicker is released under the MIT license. See [LICENSE](https://github.com/hongxinhope/TBRepeatPicker/blob/master/LICENSE.txt) for details.
66 |
67 | ## More Info
68 | Have a question? Please [open an issue](https://github.com/hongxinhope/TBRepeatPicker/issues/new)!
69 |
70 |
--------------------------------------------------------------------------------
/Example/SwitchLanguageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwitchLanguageViewController.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/10/9.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let SwitchLanguageViewControllerCellID = "SwitchLanguageViewControllerCell"
12 |
13 | protocol SwitchLanguageViewControllerDelegate {
14 | func donePickingLanguage(language: TBRPLanguage)
15 | }
16 |
17 | class SwitchLanguageViewController: UITableViewController {
18 | var language: TBRPLanguage = .English
19 | var delegate: SwitchLanguageViewControllerDelegate?
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .Plain, target: self, action: "cancelPressed")
25 | }
26 |
27 | func cancelPressed() {
28 | dismissViewControllerAnimated(true, completion: nil)
29 | }
30 |
31 | // MARK: - Table view data source
32 | override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
33 | return 1
34 | }
35 |
36 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
37 | return 5
38 | }
39 |
40 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
41 | var cell = tableView.dequeueReusableCellWithIdentifier(SwitchLanguageViewControllerCellID)
42 | if cell == nil {
43 | cell = UITableViewCell.init(style: .Default, reuseIdentifier: SwitchLanguageViewControllerCellID)
44 | }
45 |
46 | cell?.textLabel?.text = languageStrings[indexPath.row]
47 |
48 | if language == languages[indexPath.row] {
49 | cell?.accessoryType = .Checkmark
50 | } else {
51 | cell?.accessoryType = .None
52 | }
53 |
54 | return cell!
55 | }
56 |
57 | override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
58 | tableView.deselectRowAtIndexPath(indexPath, animated: true)
59 |
60 | language = languages[indexPath.row]
61 | tableView.reloadData()
62 |
63 | if let _ = delegate {
64 | dismissViewControllerAnimated(true, completion: { () -> Void in
65 | self.delegate?.donePickingLanguage(self.language)
66 | })
67 | }
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Localizations/zh-Hant.lproj/TBRPLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TBRepeatPicker
4 |
5 | Created by hongxin on 15/9/30.
6 | Copyright © 2015年 Teambition. All rights reserved.
7 | */
8 |
9 | "TBRPHelper.frequencies.daily" = "每天";
10 | "TBRPHelper.frequencies.weekly" = "每週";
11 | "TBRPHelper.frequencies.monthly" = "每月";
12 | "TBRPHelper.frequencies.yearly" = "每年";
13 |
14 | "TBRPHelper.units.day" = "天";
15 | "TBRPHelper.units.week" = "週";
16 | "TBRPHelper.units.month" = "月";
17 | "TBRPHelper.units.year" = "年";
18 |
19 | "TBRPHelper.pluralUnits.days" = "天";
20 | "TBRPHelper.pluralUnits.weeks" = "週";
21 | "TBRPHelper.pluralUnits.months" = "個月";
22 | "TBRPHelper.pluralUnits.years" = "年";
23 |
24 | "TBRPHelper.presetRepeat.never" = "永不";
25 | "TBRPHelper.presetRepeat.everyDay" = "每天";
26 | "TBRPHelper.presetRepeat.everyWeek" = "每週";
27 | "TBRPHelper.presetRepeat.everyTwoWeeks" = "每兩週";
28 | "TBRPHelper.presetRepeat.everyMonth" = "每月";
29 | "TBRPHelper.presetRepeat.everyYear" = "每年";
30 |
31 | "TBRPHelper.numbersInWeekPicker.first" = "第一個";
32 | "TBRPHelper.numbersInWeekPicker.second" = "第二個";
33 | "TBRPHelper.numbersInWeekPicker.third" = "第三個";
34 | "TBRPHelper.numbersInWeekPicker.fourth" = "第四個";
35 | "TBRPHelper.numbersInWeekPicker.fifth" = "第五個";
36 | "TBRPHelper.numbersInWeekPicker.last" = "最後一個";
37 |
38 | "TBRPHelper.daysInWeekPicker.day" = "日子";
39 | "TBRPHelper.daysInWeekPicker.weekday" = "平日";
40 | "TBRPHelper.daysInWeekPicker.weekendDay" = "週末";
41 |
42 | "TBRPPresetRepeatController.navigation.title" = "重複";
43 | "TBRPPresetRepeatController.textLabel.custom" = "自定";
44 |
45 | "TBRPCustomRepeatController.textLabel.frequency" = "頻率";
46 | "TBRPCustomRepeatController.textLabel.interval" = "每";
47 | "TBRPCustomRepeatController.textLabel.date" = "日期";
48 | "TBRPCustomRepeatController.weekCell.onThe" = "星期";
49 | "TBRPCustomRepeatController.weekCell.daysOfWeek" = "星期";
50 |
51 | "RecurrenceString.presetRepeat" = "行程每%@重複一次。";
52 | "RecurrenceString.element.on.weekly" = "的";
53 | "RecurrenceString.element.on.monthly" = "的";
54 | "RecurrenceString.element.on.yearlyMonths" = "的";
55 | "RecurrenceString.element.on.yearlyMonths.byWeekNo" = "的";
56 | "RecurrenceString.element.on.yearlyWeekString" = "的";
57 | "RecurrenceString.element.and" = "和";
58 | "RecurrenceString.element.comma" = "、";
59 | "RecurrenceString.element.day" = "%d日";
60 | "RecurrenceString.specifiedDaysOrMonths" = "行程每%@%@重複一次。";
61 | "RecurrenceString.yearlyByWeekNoString" = "行程每%@%@%@重複一次。";
62 | "RecurrenceString.weekdayRecurrence" = "行程每週一到週五重複一次。";
63 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Localizations/zh-Hans.lproj/TBRPLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TBRepeatPicker
4 |
5 | Created by hongxin on 15/9/30.
6 | Copyright © 2015年 Teambition. All rights reserved.
7 | */
8 |
9 | "TBRPHelper.frequencies.daily" = "每天";
10 | "TBRPHelper.frequencies.weekly" = "每周";
11 | "TBRPHelper.frequencies.monthly" = "每月";
12 | "TBRPHelper.frequencies.yearly" = "每年";
13 |
14 | "TBRPHelper.units.day" = "天";
15 | "TBRPHelper.units.week" = "周";
16 | "TBRPHelper.units.month" = "月";
17 | "TBRPHelper.units.year" = "年";
18 |
19 | "TBRPHelper.pluralUnits.days" = "天";
20 | "TBRPHelper.pluralUnits.weeks" = "周";
21 | "TBRPHelper.pluralUnits.months" = "个月";
22 | "TBRPHelper.pluralUnits.years" = "年";
23 |
24 | "TBRPHelper.presetRepeat.never" = "永不";
25 | "TBRPHelper.presetRepeat.everyDay" = "每天";
26 | "TBRPHelper.presetRepeat.everyWeek" = "每周";
27 | "TBRPHelper.presetRepeat.everyTwoWeeks" = "每两周";
28 | "TBRPHelper.presetRepeat.everyMonth" = "每月";
29 | "TBRPHelper.presetRepeat.everyYear" = "每年";
30 |
31 | "TBRPHelper.numbersInWeekPicker.first" = "第一个";
32 | "TBRPHelper.numbersInWeekPicker.second" = "第二个";
33 | "TBRPHelper.numbersInWeekPicker.third" = "第三个";
34 | "TBRPHelper.numbersInWeekPicker.fourth" = "第四个";
35 | "TBRPHelper.numbersInWeekPicker.fifth" = "第五个";
36 | "TBRPHelper.numbersInWeekPicker.last" = "最后一个";
37 |
38 | "TBRPHelper.daysInWeekPicker.day" = "自然日";
39 | "TBRPHelper.daysInWeekPicker.weekday" = "工作日";
40 | "TBRPHelper.daysInWeekPicker.weekendDay" = "周末";
41 |
42 | "TBRPPresetRepeatController.navigation.title" = "重复";
43 | "TBRPPresetRepeatController.textLabel.custom" = "自定义";
44 |
45 | "TBRPCustomRepeatController.textLabel.frequency" = "频率";
46 | "TBRPCustomRepeatController.textLabel.interval" = "每";
47 | "TBRPCustomRepeatController.textLabel.date" = "日期";
48 | "TBRPCustomRepeatController.weekCell.onThe" = "星期";
49 | "TBRPCustomRepeatController.weekCell.daysOfWeek" = "星期";
50 |
51 | "RecurrenceString.presetRepeat" = "事件将每%@重复一次。";
52 | "RecurrenceString.element.on.weekly" = "于";
53 | "RecurrenceString.element.on.monthly" = "于";
54 | "RecurrenceString.element.on.yearlyMonths" = "于";
55 | "RecurrenceString.element.on.yearlyMonths.byWeekNo" = "于";
56 | "RecurrenceString.element.on.yearlyWeekString" = "的";
57 | "RecurrenceString.element.and" = "和";
58 | "RecurrenceString.element.comma" = "、";
59 | "RecurrenceString.element.day" = "%d日";
60 | "RecurrenceString.specifiedDaysOrMonths" = "事件将每%@%@重复一次。";
61 | "RecurrenceString.yearlyByWeekNoString" = "事件将每%@%@%@重复一次。";
62 | "RecurrenceString.weekdayRecurrence" = "事件将每个工作日重复一次。";
63 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Localizations/ja.lproj/TBRPLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TBRepeatPicker
4 |
5 | Created by hongxin on 15/9/30.
6 | Copyright © 2015年 Teambition. All rights reserved.
7 | */
8 |
9 | "TBRPHelper.frequencies.daily" = "毎日";
10 | "TBRPHelper.frequencies.weekly" = "毎週";
11 | "TBRPHelper.frequencies.monthly" = "毎月";
12 | "TBRPHelper.frequencies.yearly" = "毎年";
13 |
14 | "TBRPHelper.units.day" = "日";
15 | "TBRPHelper.units.week" = "週間";
16 | "TBRPHelper.units.month" = "カ月";
17 | "TBRPHelper.units.year" = "年";
18 |
19 | "TBRPHelper.pluralUnits.days" = "日";
20 | "TBRPHelper.pluralUnits.weeks" = "週間";
21 | "TBRPHelper.pluralUnits.months" = "カ月";
22 | "TBRPHelper.pluralUnits.years" = "年";
23 |
24 | "TBRPHelper.presetRepeat.never" = "しない";
25 | "TBRPHelper.presetRepeat.everyDay" = "毎日";
26 | "TBRPHelper.presetRepeat.everyWeek" = "毎週";
27 | "TBRPHelper.presetRepeat.everyTwoWeeks" = "2週間ごと";
28 | "TBRPHelper.presetRepeat.everyMonth" = "毎月";
29 | "TBRPHelper.presetRepeat.everyYear" = "毎年";
30 |
31 | "TBRPHelper.numbersInWeekPicker.first" = "第1";
32 | "TBRPHelper.numbersInWeekPicker.second" = "第2";
33 | "TBRPHelper.numbersInWeekPicker.third" = "第3";
34 | "TBRPHelper.numbersInWeekPicker.fourth" = "第4";
35 | "TBRPHelper.numbersInWeekPicker.fifth" = "第5";
36 | "TBRPHelper.numbersInWeekPicker.last" = "最後の";
37 |
38 | "TBRPHelper.daysInWeekPicker.day" = "日";
39 | "TBRPHelper.daysInWeekPicker.weekday" = "平日";
40 | "TBRPHelper.daysInWeekPicker.weekendDay" = "週末";
41 |
42 | "TBRPPresetRepeatController.navigation.title" = "繰り返し";
43 | "TBRPPresetRepeatController.textLabel.custom" = "カスタム";
44 |
45 | "TBRPCustomRepeatController.textLabel.frequency" = "繰り返しの単位";
46 | "TBRPCustomRepeatController.textLabel.interval" = "繰り返しの頻度";
47 | "TBRPCustomRepeatController.textLabel.date" = "毎";
48 | "TBRPCustomRepeatController.weekCell.onThe" = "指定日";
49 | "TBRPCustomRepeatController.weekCell.daysOfWeek" = "曜日";
50 |
51 | "RecurrenceString.presetRepeat" = "%@ごとにあるイベントです。";
52 | "RecurrenceString.element.on.weekly" = "に、";
53 | "RecurrenceString.element.on.monthly" = "に、";
54 | "RecurrenceString.element.on.yearlyMonths" = "に、";
55 | "RecurrenceString.element.on.yearlyMonths.byWeekNo" = "に、";
56 | "RecurrenceString.element.on.yearlyWeekString" = "の";
57 | "RecurrenceString.element.and" = "と";
58 | "RecurrenceString.element.comma" = "、";
59 | "RecurrenceString.element.day" = "%d日";
60 | "RecurrenceString.specifiedDaysOrMonths" = "%@ごと%@にあるイベントです。";
61 | "RecurrenceString.yearlyByWeekNoString" = "%@ごと%@%@にあるイベントです。";
62 | "RecurrenceString.weekdayRecurrence" = "平日に毎日あるイベントです。";
63 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Localizations/ko.lproj/TBRPLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TBRepeatPicker
4 |
5 | Created by hongxin on 15/9/30.
6 | Copyright © 2015年 Teambition. All rights reserved.
7 | */
8 |
9 | "TBRPHelper.frequencies.daily" = "매일";
10 | "TBRPHelper.frequencies.weekly" = "매주";
11 | "TBRPHelper.frequencies.monthly" = "매월";
12 | "TBRPHelper.frequencies.yearly" = "매년";
13 |
14 | "TBRPHelper.units.day" = "일";
15 | "TBRPHelper.units.week" = "주";
16 | "TBRPHelper.units.month" = "개월";
17 | "TBRPHelper.units.year" = "년";
18 |
19 | "TBRPHelper.pluralUnits.days" = "일";
20 | "TBRPHelper.pluralUnits.weeks" = "주";
21 | "TBRPHelper.pluralUnits.months" = "개월";
22 | "TBRPHelper.pluralUnits.years" = "년";
23 |
24 | "TBRPHelper.presetRepeat.never" = "안 함";
25 | "TBRPHelper.presetRepeat.everyDay" = "매일";
26 | "TBRPHelper.presetRepeat.everyWeek" = "매주";
27 | "TBRPHelper.presetRepeat.everyTwoWeeks" = "2주마다";
28 | "TBRPHelper.presetRepeat.everyMonth" = "매월";
29 | "TBRPHelper.presetRepeat.everyYear" = "매년";
30 |
31 | "TBRPHelper.numbersInWeekPicker.first" = "첫 번째";
32 | "TBRPHelper.numbersInWeekPicker.second" = "두 번째";
33 | "TBRPHelper.numbersInWeekPicker.third" = "세 번째";
34 | "TBRPHelper.numbersInWeekPicker.fourth" = "네 번째";
35 | "TBRPHelper.numbersInWeekPicker.fifth" = "다섯 번째";
36 | "TBRPHelper.numbersInWeekPicker.last" = "최근";
37 |
38 | "TBRPHelper.daysInWeekPicker.day" = "요일";
39 | "TBRPHelper.daysInWeekPicker.weekday" = "평일";
40 | "TBRPHelper.daysInWeekPicker.weekendDay" = "주말";
41 |
42 | "TBRPPresetRepeatController.navigation.title" = "반복";
43 | "TBRPPresetRepeatController.textLabel.custom" = "사용자 설정";
44 |
45 | "TBRPCustomRepeatController.textLabel.frequency" = "반복 주기";
46 | "TBRPCustomRepeatController.textLabel.interval" = "반복";
47 | "TBRPCustomRepeatController.textLabel.date" = "일자 지정";
48 | "TBRPCustomRepeatController.weekCell.onThe" = "조건 지정...";
49 | "TBRPCustomRepeatController.weekCell.daysOfWeek" = "요일";
50 |
51 | "RecurrenceString.presetRepeat" = "%@마다 이벤트 반복";
52 | "RecurrenceString.element.on.weekly" = "에";
53 | "RecurrenceString.element.on.monthly" = "에";
54 | "RecurrenceString.element.on.yearlyMonths" = "에";
55 | "RecurrenceString.element.on.yearlyMonths.byWeekNo" = "에";
56 | "RecurrenceString.element.on.yearlyWeekString" = "의";
57 | "RecurrenceString.element.and" = "및";
58 | "RecurrenceString.element.comma" = ",";
59 | "RecurrenceString.element.day" = "%d일";
60 | "RecurrenceString.specifiedDaysOrMonths" = "%@마다 %@ 이벤트 반복";
61 | "RecurrenceString.yearlyByWeekNoString" = "%@마다 %@ %@ 이벤트 반복";
62 | "RecurrenceString.weekdayRecurrence" = "매주 평일마다 이벤트 반복";
63 |
--------------------------------------------------------------------------------
/TBRepeatPicker/Resources/Localizations/en.lproj/TBRPLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TBRepeatPicker
4 |
5 | Created by hongxin on 15/9/30.
6 | Copyright © 2015年 Teambition. All rights reserved.
7 | */
8 |
9 | "TBRPHelper.frequencies.daily" = "Daily";
10 | "TBRPHelper.frequencies.weekly" = "Weekly";
11 | "TBRPHelper.frequencies.monthly" = "Monthly";
12 | "TBRPHelper.frequencies.yearly" = "Yearly";
13 |
14 | "TBRPHelper.units.day" = "Day";
15 | "TBRPHelper.units.week" = "Week";
16 | "TBRPHelper.units.month" = "Month";
17 | "TBRPHelper.units.year" = "Year";
18 |
19 | "TBRPHelper.pluralUnits.days" = "days";
20 | "TBRPHelper.pluralUnits.weeks" = "weeks";
21 | "TBRPHelper.pluralUnits.months" = "months";
22 | "TBRPHelper.pluralUnits.years" = "years";
23 |
24 | "TBRPHelper.presetRepeat.never" = "Never";
25 | "TBRPHelper.presetRepeat.everyDay" = "Every Day";
26 | "TBRPHelper.presetRepeat.everyWeek" = "Every Week";
27 | "TBRPHelper.presetRepeat.everyTwoWeeks" = "Every 2 Weeks";
28 | "TBRPHelper.presetRepeat.everyMonth" = "Every Month";
29 | "TBRPHelper.presetRepeat.everyYear" = "Every Year";
30 |
31 | "TBRPHelper.numbersInWeekPicker.first" = "first";
32 | "TBRPHelper.numbersInWeekPicker.second" = "second";
33 | "TBRPHelper.numbersInWeekPicker.third" = "third";
34 | "TBRPHelper.numbersInWeekPicker.fourth" = "fourth";
35 | "TBRPHelper.numbersInWeekPicker.fifth" = "fifth";
36 | "TBRPHelper.numbersInWeekPicker.last" = "last";
37 |
38 | "TBRPHelper.daysInWeekPicker.day" = "day";
39 | "TBRPHelper.daysInWeekPicker.weekday" = "weekday";
40 | "TBRPHelper.daysInWeekPicker.weekendDay" = "weekend day";
41 |
42 | "TBRPPresetRepeatController.navigation.title" = "Repeat";
43 | "TBRPPresetRepeatController.textLabel.custom" = "Custom";
44 |
45 | "TBRPCustomRepeatController.textLabel.frequency" = "Frequency";
46 | "TBRPCustomRepeatController.textLabel.interval" = "Every";
47 | "TBRPCustomRepeatController.textLabel.date" = "Each";
48 | "TBRPCustomRepeatController.weekCell.onThe" = "On the...";
49 | "TBRPCustomRepeatController.weekCell.daysOfWeek" = "Days of Week";
50 |
51 | "RecurrenceString.presetRepeat" = "Event will occur every %@.";
52 | "RecurrenceString.element.on.weekly" = "on";
53 | "RecurrenceString.element.on.monthly" = "on the";
54 | "RecurrenceString.element.on.yearlyMonths" = "in";
55 | "RecurrenceString.element.on.yearlyMonths.byWeekNo" = "of";
56 | "RecurrenceString.element.on.yearlyWeekString" = "on the";
57 | "RecurrenceString.element.and" = "and";
58 | "RecurrenceString.element.comma" = ",";
59 | "RecurrenceString.element.day" = "";
60 | "RecurrenceString.specifiedDaysOrMonths" = "Event will occur every %@ %@.";
61 | "RecurrenceString.yearlyByWeekNoString" = "Event will occur every %@ %@ %@.";
62 | "RecurrenceString.weekdayRecurrence" = "Event will occur every weekday.";
63 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPCollectionItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPCollectionItem.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/25.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let lineWidth: CGFloat = 0.5
12 |
13 | class TBRPCollectionItem: UICollectionViewCell {
14 | // MARK: - Public properties
15 | var textLabel: UILabel?
16 | var showTopLine = true
17 | var showBottomLine = true
18 | var showLeftLine = true
19 | var showRightLine = true
20 |
21 | // MARK: - Private properties
22 | private let topLine = CALayer()
23 | private let bottomLine = CALayer()
24 | private let leftLine = CALayer()
25 | private let rightLine = CALayer()
26 |
27 | // MARK: - View life cycle
28 | override init(frame: CGRect) {
29 | super.init(frame: frame)
30 |
31 | textLabel = UILabel(frame: CGRectMake(lineWidth, lineWidth, bounds.size.width - 2 * lineWidth, bounds.size.height - 2 * lineWidth))
32 | textLabel?.textAlignment = .Center
33 | backgroundView = textLabel
34 |
35 | // add separator line
36 | topLine.frame = CGRectMake(0, 0, bounds.size.width, lineWidth)
37 | topLine.backgroundColor = separatorColor()
38 |
39 | bottomLine.frame = CGRectMake(0, bounds.size.height - lineWidth, bounds.size.width, lineWidth)
40 | bottomLine.backgroundColor = separatorColor()
41 |
42 | leftLine.frame = CGRectMake(0, 0, lineWidth, bounds.size.height)
43 | leftLine.backgroundColor = separatorColor()
44 |
45 | rightLine.frame = CGRectMake(bounds.size.width - lineWidth, 0, lineWidth, bounds.size.height)
46 | rightLine.backgroundColor = separatorColor()
47 |
48 | layer.addSublayer(topLine)
49 | layer.addSublayer(bottomLine)
50 | layer.addSublayer(leftLine)
51 | layer.addSublayer(rightLine)
52 | }
53 |
54 | required init?(coder aDecoder: NSCoder) {
55 | fatalError("init(coder:) has not been implemented")
56 | }
57 |
58 | override func layoutSubviews() {
59 | super.layoutSubviews()
60 |
61 | topLine.hidden = !showTopLine
62 | bottomLine.hidden = !showBottomLine
63 | leftLine.hidden = !showLeftLine
64 | rightLine.hidden = !showRightLine
65 | }
66 |
67 | // MARK: - Helper
68 | private func separatorColor() -> CGColorRef {
69 | return UIColor.init(white: 187.0 / 255.0, alpha: 1.0).CGColor
70 | }
71 |
72 | func setItemSelected(selected: Bool) {
73 | if selected == true {
74 | textLabel?.backgroundColor = tintColor
75 | textLabel?.textColor = UIColor.whiteColor()
76 | } else {
77 | textLabel?.backgroundColor = UIColor.whiteColor()
78 | textLabel?.textColor = UIColor.blackColor()
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPCustomRepeatCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPCustomRepeatCell.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/29.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TBRPCustomRepeatCell: UITableViewCell {
12 | // MARK: - View life cycle
13 | override func awakeFromNib() {
14 | super.awakeFromNib()
15 |
16 | }
17 |
18 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
19 | super.init(style: style, reuseIdentifier: reuseIdentifier)
20 |
21 | addDefaultBottomSeparator()
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | override func layoutSubviews() {
29 | super.layoutSubviews()
30 |
31 | textLabel?.frame.origin.x = TBRPHelper.leadingMargin()
32 | }
33 |
34 | override func prepareForReuse() {
35 | super.prepareForReuse()
36 |
37 | resetSeparatorWithLeftX(TBRPHelper.leadingMargin())
38 | }
39 |
40 | // MARK: - Separator line
41 | func removeAllSeparators() {
42 | for sublayer in layer.sublayers! {
43 | if sublayer.name == TBRPTopSeparatorIdentifier || sublayer.name == TBRPBottomSeparatorIdentifier {
44 | sublayer.removeFromSuperlayer()
45 | }
46 | }
47 | }
48 |
49 | func removeBottomSeparators() {
50 | for sublayer in layer.sublayers! {
51 | if sublayer.name == TBRPBottomSeparatorIdentifier {
52 | sublayer.removeFromSuperlayer()
53 | }
54 | }
55 | }
56 |
57 | func addBottomSeparatorFromLeftX(leftX: CGFloat) {
58 | for sublayer in layer.sublayers! {
59 | if sublayer.name == TBRPBottomSeparatorIdentifier {
60 | sublayer.removeFromSuperlayer()
61 | }
62 | }
63 |
64 | let bottomSeparator = CALayer()
65 | bottomSeparator.name = TBRPBottomSeparatorIdentifier
66 |
67 | bottomSeparator.frame = CGRectMake(leftX, bounds.size.height - TBRPSeparatorLineWidth, TBRPScreenWidth - leftX, TBRPSeparatorLineWidth)
68 | bottomSeparator.backgroundColor = TBRPHelper.separatorColor()
69 |
70 | layer.addSublayer(bottomSeparator)
71 | }
72 |
73 | func addTopSeparatorFromLeftX(leftX: CGFloat) {
74 | for sublayer in layer.sublayers! {
75 | if sublayer.name == TBRPTopSeparatorIdentifier {
76 | sublayer.removeFromSuperlayer()
77 | }
78 | }
79 |
80 | let topSeparator = CALayer()
81 | topSeparator.name = TBRPTopSeparatorIdentifier
82 |
83 | topSeparator.frame = CGRectMake(leftX, 0,TBRPScreenWidth - leftX, TBRPSeparatorLineWidth)
84 | topSeparator.backgroundColor = TBRPHelper.separatorColor()
85 |
86 | layer.addSublayer(topSeparator)
87 | }
88 |
89 | func addDefaultBottomSeparator() {
90 | addBottomSeparatorFromLeftX(TBRPHelper.leadingMargin())
91 | }
92 |
93 | func addSectionTopSeparator() {
94 | addTopSeparatorFromLeftX(0)
95 | }
96 |
97 | func addSectionBottomSeparator() {
98 | addBottomSeparatorFromLeftX(0)
99 | }
100 |
101 | func updateBottomSeparatorWithLeftX(leftX: CGFloat) {
102 | removeBottomSeparators()
103 | addBottomSeparatorFromLeftX(leftX)
104 | }
105 |
106 | func resetSeparatorWithLeftX(leftX: CGFloat) {
107 | removeAllSeparators()
108 | addBottomSeparatorFromLeftX(leftX)
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Example/TBRepeatPicker.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/TBRepeatPicker.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Example/DemoViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoViewController.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/30.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let languageStrings = ["English", "SimplifiedChinese", "TraditionalChinese", "Korean", "Japanese"]
12 | let languages: [TBRPLanguage] = [.English, .SimplifiedChinese, .TraditionalChinese, .Korean, .Japanese]
13 |
14 | class DemoViewController: UIViewController, TBRepeatPickerDelegate, SwitchLanguageViewControllerDelegate {
15 | var occurrenceDate = NSDate()
16 | var recurrence: TBRecurrence?
17 | var language: TBRPLanguage = .English
18 |
19 | @IBOutlet weak var resultTextView: UITextView!
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | // let dateFormatter = NSDateFormatter()
25 | // dateFormatter.dateFormat = "yyyy-MM-dd"
26 | // occurrenceDate = dateFormatter.dateFromString("2015-09-14")! // 2015-09-14 Monday
27 |
28 | resultTextView.userInteractionEnabled = false
29 | updateLanguageTitle()
30 | updateResultTextView()
31 | }
32 |
33 | private func updateLanguageTitle() {
34 | let languageIndex = languages.indexOf(language)
35 | let languageTitle = languageStrings[languageIndex!]
36 | navigationItem.rightBarButtonItem = UIBarButtonItem(title: languageTitle, style: .Plain, target: self, action: "switchLanguage")
37 | }
38 |
39 | func switchLanguage() {
40 | let switchLanguageViewController = SwitchLanguageViewController.init(style: .Grouped)
41 | let navigationViewController = UINavigationController(rootViewController: switchLanguageViewController)
42 | switchLanguageViewController.language = language
43 | switchLanguageViewController.delegate = self
44 |
45 | presentViewController(navigationViewController, animated: true, completion: nil)
46 | }
47 |
48 | func donePickingLanguage(language: TBRPLanguage) {
49 | self.language = language
50 | updateLanguageTitle()
51 | updateResultTextView()
52 | }
53 |
54 | @IBAction func startPicking(sender: UIButton) {
55 | let repeatPicker = TBRepeatPicker.initPicker(occurrenceDate, language: language, tintColor: tbBlueColor())
56 | repeatPicker.delegate = self
57 |
58 | // recurrence = nil
59 | //
60 | // recurrence = TBRecurrence.initDaily(1, occurrenceDate: occurrenceDate)
61 | //
62 | // recurrence = TBRecurrence.initWeekly(1, selectedWeekdays: [], occurrenceDate: occurrenceDate)
63 | // recurrence = TBRecurrence.initWeekly(1, selectedWeekdays: [2, 2, 6], occurrenceDate: occurrenceDate)
64 | // recurrence = TBRecurrence.initWeekly(2, selectedWeekdays: [], occurrenceDate: occurrenceDate)
65 | // recurrence = TBRecurrence.initWeekly(2, selectedWeekdays: [1, 3, 5, 6, 0], occurrenceDate: occurrenceDate)
66 | //
67 | // recurrence = TBRecurrence.initMonthly(1, selectedMonthdays: [], occurrenceDate: occurrenceDate)
68 | // recurrence = TBRecurrence.initMonthly(2, selectedMonthdays: [], occurrenceDate: occurrenceDate)
69 | // recurrence = TBRecurrence.initMonthly(1, selectedMonthdays: [3, 17], occurrenceDate: occurrenceDate)
70 | // recurrence = TBRecurrence.initMonthly(3, selectedMonthdays: [5, 20], occurrenceDate: occurrenceDate)
71 | //
72 | // recurrence = TBRecurrence.initMonthlyByWeekNumber(1, pickedWeekNumber: .Second, pickedWeekday: .Day, occurrenceDate: occurrenceDate)
73 | // recurrence = TBRecurrence.initMonthlyByWeekNumber(4, pickedWeekNumber: .Third, pickedWeekday: .Weekday, occurrenceDate: occurrenceDate)
74 | //
75 | // recurrence = TBRecurrence.initYearly(1, selectedMonths: [], occurrenceDate: occurrenceDate)
76 | // recurrence = TBRecurrence.initYearly(4, selectedMonths: [], occurrenceDate: occurrenceDate)
77 | // recurrence = TBRecurrence.initYearly(1, selectedMonths: [3, 8], occurrenceDate: occurrenceDate)
78 | // recurrence = TBRecurrence.initYearly(3, selectedMonths: [7, 9], occurrenceDate: occurrenceDate)
79 | //
80 | // recurrence = TBRecurrence.initYearlyByWeekNumber(1, pickedWeekNumber: .Fifth, pickedWeekday: .Wednesday, occurrenceDate: occurrenceDate)
81 | // recurrence = TBRecurrence.initYearlyByWeekNumber(3, pickedWeekNumber: .Last, pickedWeekday: .Day, occurrenceDate: occurrenceDate)
82 | //
83 | // recurrence = TBRecurrence.dailyRecurrence(occurrenceDate)
84 | // recurrence = TBRecurrence.weeklyRecurrence(occurrenceDate)
85 | // recurrence = TBRecurrence.biWeeklyRecurrence(occurrenceDate)
86 | // recurrence = TBRecurrence.monthlyRecurrence(occurrenceDate)
87 | // recurrence = TBRecurrence.yearlyRecurrence(occurrenceDate)
88 | // recurrence = TBRecurrence.weekdayRecurrence(occurrenceDate)
89 |
90 | repeatPicker.recurrence = recurrence
91 |
92 | navigationController?.pushViewController(repeatPicker, animated: true)
93 | }
94 |
95 | func didPickRecurrence(recurrence: TBRecurrence?, repeatPicker: TBRepeatPicker) {
96 | self.recurrence = recurrence
97 |
98 | updateResultTextView()
99 | }
100 |
101 | private func updateResultTextView() {
102 | if let _ = recurrence {
103 | resultTextView.text = TBRPHelper.recurrenceString(recurrence!, occurrenceDate: occurrenceDate, language: language)
104 | } else {
105 | resultTextView.text = "Never Repeat"
106 | }
107 | }
108 |
109 | func tbBlueColor() -> UIColor {
110 | return UIColor.init(red: 3.0 / 255.0, green: 169.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0)
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPPickerViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPPickerViewCell.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/24.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum TBRPPickerStyle {
12 | case Frequency
13 | case Interval
14 | case Week
15 | }
16 |
17 | let TBRPPickerHeight: CGFloat = 215.0
18 |
19 | private let TBRPPickerRowHeight: CGFloat = 40.0
20 | private let TBRPPickerMaxRowCount = 999
21 |
22 | protocol TBRPPickerCellDelegate {
23 | func pickerDidPick(pickerView: UIPickerView, pickStyle: TBRPPickerStyle, didSelectRow row: Int, inComponent component: Int)
24 | }
25 |
26 | class TBRPPickerViewCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate {
27 | // MARK: - Public properties
28 | var language: TBRPLanguage = .English
29 | var pickerStyle: TBRPPickerStyle?
30 | var delegate: TBRPPickerCellDelegate?
31 | var unit: String? {
32 | didSet {
33 | pickerView?.reloadComponent(1)
34 | }
35 | }
36 | var frequency: TBRPFrequency? {
37 | didSet {
38 | pickerView?.selectRow((frequency?.rawValue)!, inComponent: 0, animated: true)
39 | }
40 | }
41 | var interval: Int? {
42 | didSet {
43 | pickerView?.selectRow(interval! - 1, inComponent: 0, animated: true)
44 | }
45 | }
46 | var pickedWeekNumber: TBRPWeekPickerNumber? {
47 | didSet {
48 | pickerView?.selectRow((pickedWeekNumber?.rawValue)!, inComponent: 0, animated: true)
49 | }
50 | }
51 | var pickedWeekday: TBRPWeekPickerDay? {
52 | didSet {
53 | pickerView?.selectRow((pickedWeekday?.rawValue)!, inComponent: 1, animated: true)
54 | }
55 | }
56 |
57 | // MARK: - Private properties
58 | private var pickerView: UIPickerView?
59 |
60 | // MARK: - Initialization
61 | override func awakeFromNib() {
62 | super.awakeFromNib()
63 |
64 | }
65 |
66 | override func prepareForReuse() {
67 | super.prepareForReuse()
68 |
69 | removeAllSeparators()
70 | }
71 |
72 | convenience init(style: UITableViewCellStyle, reuseIdentifier: String?, pickerStyle: TBRPPickerStyle, language: TBRPLanguage) {
73 | self.init()
74 |
75 | pickerView = UIPickerView.init(frame: CGRectMake(0, 0, TBRPScreenWidth, TBRPPickerHeight))
76 | pickerView!.dataSource = self
77 | pickerView!.delegate = self
78 |
79 | self.pickerStyle = pickerStyle
80 | if pickerStyle == .Frequency {
81 | addDefaultBottomSeparator()
82 | } else {
83 | addSectionBottomSeparator()
84 | }
85 |
86 | self.language = language
87 | contentView.addSubview(pickerView!)
88 | }
89 |
90 | // MARK: - Separator line
91 | func removeAllSeparators() {
92 | for sublayer in layer.sublayers! {
93 | if sublayer.name == TBRPTopSeparatorIdentifier || sublayer.name == TBRPBottomSeparatorIdentifier {
94 | sublayer.removeFromSuperlayer()
95 | }
96 | }
97 | }
98 |
99 | func addBottomSeparatorFromLeftX(leftX: CGFloat) {
100 | let bottomSeparator = CALayer()
101 | bottomSeparator.name = TBRPBottomSeparatorIdentifier
102 |
103 | bottomSeparator.frame = CGRectMake(leftX, TBRPPickerHeight - TBRPSeparatorLineWidth, TBRPScreenWidth - leftX, TBRPSeparatorLineWidth)
104 | bottomSeparator.backgroundColor = TBRPHelper.separatorColor()
105 |
106 | layer.addSublayer(bottomSeparator)
107 | }
108 |
109 | func addDefaultBottomSeparator() {
110 | addBottomSeparatorFromLeftX(TBRPHelper.leadingMargin())
111 | }
112 |
113 | func addSectionBottomSeparator() {
114 | addBottomSeparatorFromLeftX(0)
115 | }
116 |
117 | // MARK: - UIPickerView data source
118 | func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
119 | if pickerStyle == .Frequency {
120 | return 1
121 | } else {
122 | return 2
123 | }
124 | }
125 |
126 | func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
127 | if pickerStyle == .Frequency {
128 | return 4
129 | } else if pickerStyle == .Interval {
130 | if component == 0 {
131 | return TBRPPickerMaxRowCount
132 | } else {
133 | return 1
134 | }
135 | } else if pickerStyle == .Week {
136 | if component == 0 {
137 | return TBRPHelper.numbersInWeekPicker(language).count
138 | } else {
139 | return TBRPHelper.daysInWeekPicker(language).count
140 | }
141 | }
142 | return 0
143 | }
144 |
145 | func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
146 | return TBRPPickerRowHeight
147 | }
148 |
149 | func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
150 | return TBRPScreenWidth / 2
151 | }
152 |
153 | func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
154 | if pickerStyle == .Frequency {
155 | return TBRPHelper.frequencies(language)[row]
156 | } else if pickerStyle == .Interval {
157 | if component == 0 {
158 | return "\(row + 1)"
159 | } else {
160 | return unit?.lowercaseString
161 | }
162 | } else if pickerStyle == .Week {
163 | if component == 0 {
164 | return TBRPHelper.numbersInWeekPicker(language)[row]
165 | } else {
166 | return TBRPHelper.daysInWeekPicker(language)[row]
167 | }
168 | }
169 | return nil
170 | }
171 |
172 | // MARK: - UIPickerView delegate
173 | func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
174 | if let _ = delegate {
175 | delegate!.pickerDidPick(pickerView, pickStyle: pickerStyle!, didSelectRow: row, inComponent: component)
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPCollectionViewCell.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/25.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum TBRPCollectionMode {
12 | case Days
13 | case Months
14 | }
15 |
16 | let TBRPDaysItemWidth: CGFloat = TBRPScreenWidth / 7.0
17 | let TBRPDaysItemHeight = CGFloat((Int)(TBRPDaysItemWidth * 0.9 + 0.5))
18 | let TBRPMonthsItemWidth: CGFloat = TBRPScreenWidth / 4.0
19 | let TBRPMonthsItemHeight: CGFloat = 44.0
20 |
21 | let TBRPDaysCollectionHeight: CGFloat = TBRPDaysItemHeight * 5
22 | let TBRPMonthsCollectionHeight: CGFloat = TBRPMonthsItemHeight * 3
23 |
24 | private let TBRPCollectionItemID = "TBRPCollectionItem"
25 |
26 | protocol TBRPCollectionViewCellDelegate {
27 | func selectedMonthdaysDidChanged(days: [Int])
28 | func selectedMonthsDidChanged(months: [Int])
29 | }
30 |
31 | class TBRPCollectionViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
32 | // MARK: - Public properties
33 | var language: TBRPLanguage = .English
34 | var selectedMonthdays = [Int]()
35 | var selectedMonths = [Int]()
36 | var delegate: TBRPCollectionViewCellDelegate?
37 |
38 | // MARK: - Private properties
39 | private var collectionView: UICollectionView?
40 | private var mode: TBRPCollectionMode?
41 |
42 | // MARK: - View life cycle
43 | override func awakeFromNib() {
44 | super.awakeFromNib()
45 |
46 | }
47 |
48 | override func prepareForReuse() {
49 | super.prepareForReuse()
50 |
51 | removeAllSeparators()
52 | }
53 |
54 | convenience init(style: UITableViewCellStyle, reuseIdentifier: String?, mode: TBRPCollectionMode, language: TBRPLanguage) {
55 | self.init()
56 |
57 | separatorInset = UIEdgeInsetsMake(0, TBRPScreenWidth, 0, 0)
58 |
59 | self.mode = mode
60 | if mode == .Months {
61 | addSectionTopSeparator()
62 | addSectionBottomSeparator()
63 | }
64 |
65 | self.language = language
66 | let layout = TBRPCollectionViewLayout(mode: mode)
67 |
68 | if mode == .Days {
69 | collectionView = UICollectionView(frame: CGRectMake(0, 0, TBRPScreenWidth, TBRPDaysCollectionHeight), collectionViewLayout: layout)
70 | } else {
71 | collectionView = UICollectionView(frame: CGRectMake(0, 0, TBRPScreenWidth, TBRPMonthsCollectionHeight), collectionViewLayout: layout)
72 | }
73 |
74 | if let _ = collectionView {
75 | collectionView?.dataSource = self
76 | collectionView?.delegate = self
77 | collectionView?.registerClass(TBRPCollectionItem.self, forCellWithReuseIdentifier: TBRPCollectionItemID)
78 | collectionView?.backgroundColor = UIColor.clearColor()
79 | contentView.addSubview(collectionView!)
80 | }
81 | backgroundColor = UIColor.clearColor()
82 | }
83 |
84 | // MARK: - Separator line
85 | func removeAllSeparators() {
86 | for sublayer in layer.sublayers! {
87 | if sublayer.name == TBRPTopSeparatorIdentifier || sublayer.name == TBRPBottomSeparatorIdentifier {
88 | sublayer.removeFromSuperlayer()
89 | }
90 | }
91 | }
92 |
93 | func addBottomSeparatorFromLeftX(leftX: CGFloat) {
94 | let bottomSeparator = CALayer()
95 | bottomSeparator.name = TBRPBottomSeparatorIdentifier
96 |
97 | bottomSeparator.frame = CGRectMake(leftX, TBRPMonthsCollectionHeight - TBRPSeparatorLineWidth, TBRPScreenWidth - leftX, TBRPSeparatorLineWidth)
98 | bottomSeparator.backgroundColor = TBRPHelper.separatorColor()
99 |
100 | layer.addSublayer(bottomSeparator)
101 | }
102 |
103 | func addTopSeparatorFromLeftX(leftX: CGFloat) {
104 | let topSeparator = CALayer()
105 | topSeparator.name = TBRPTopSeparatorIdentifier
106 |
107 | topSeparator.frame = CGRectMake(leftX, 0,TBRPScreenWidth - leftX, TBRPSeparatorLineWidth)
108 | topSeparator.backgroundColor = TBRPHelper.separatorColor()
109 |
110 | layer.addSublayer(topSeparator)
111 | }
112 |
113 | func addSectionTopSeparator() {
114 | addTopSeparatorFromLeftX(0)
115 | }
116 |
117 | func addSectionBottomSeparator() {
118 | addBottomSeparatorFromLeftX(0)
119 | }
120 |
121 | // MARK: - UICollectionView data source
122 | func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
123 | return 1
124 | }
125 |
126 | func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
127 | if mode == .Days {
128 | return 31
129 | } else {
130 | return 12
131 | }
132 | }
133 |
134 | func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
135 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier(TBRPCollectionItemID, forIndexPath: indexPath) as! TBRPCollectionItem
136 | cell.tintColor = tintColor
137 |
138 | if mode == .Days {
139 | let day = indexPath.row + 1
140 |
141 | cell.textLabel!.text = "\(day)"
142 | cell.setItemSelected(selectedMonthdays.contains(day))
143 | } else {
144 | let month = indexPath.row + 1
145 |
146 | cell.textLabel!.text = TBRPHelper.yearMonths(language)[indexPath.row]
147 | cell.setItemSelected(selectedMonths.contains(month))
148 | }
149 |
150 | configureSeparatorLine(cell, indexPath: indexPath)
151 |
152 | return cell
153 | }
154 |
155 | func configureSeparatorLine(cell: TBRPCollectionItem,indexPath: NSIndexPath) {
156 | if mode == .Days {
157 | cell.showTopLine = false
158 | cell.showLeftLine = false
159 |
160 | if (indexPath.row + 1) % 7 == 0 {
161 | cell.showRightLine = false
162 | }
163 |
164 | } else if mode == .Months {
165 | cell.showBottomLine = false
166 | if indexPath.row + 1 < 5 {
167 | cell.showTopLine = false
168 | }
169 |
170 | cell.showLeftLine = false
171 | if (indexPath.row + 1) % 4 == 0 {
172 | cell.showRightLine = false
173 | }
174 | }
175 | }
176 |
177 | // MARK: - UICollectionView delegate
178 | func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
179 | let cell = collectionView.cellForItemAtIndexPath(indexPath) as! TBRPCollectionItem
180 |
181 | if mode == .Days {
182 | let day = indexPath.row + 1
183 | if selectedMonthdays.count == 1 && selectedMonthdays.contains(day) == true {
184 | return
185 | }
186 |
187 | cell.setItemSelected(!selectedMonthdays.contains(day))
188 |
189 | if selectedMonthdays.contains(day) == true {
190 | selectedMonthdays.removeObject(day)
191 | } else {
192 | selectedMonthdays.append(day)
193 | }
194 | cell.backgroundColor = UIColor.whiteColor()
195 |
196 | if let _ = delegate {
197 | delegate?.selectedMonthdaysDidChanged(selectedMonthdays)
198 | }
199 | } else if mode == .Months {
200 | let month = indexPath.row + 1
201 | if selectedMonths.count == 1 && selectedMonths.contains(month) == true {
202 | return
203 | }
204 |
205 | cell.setItemSelected(!selectedMonths.contains(month))
206 |
207 | if selectedMonths.contains(month) == true {
208 | selectedMonths.removeObject(month)
209 | } else {
210 | selectedMonths.append(month)
211 | }
212 |
213 | if let _ = delegate {
214 | delegate?.selectedMonthsDidChanged(selectedMonths)
215 | }
216 | }
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPPresetRepeatController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPPresetRepeatController.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/23.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let TBRPPresetRepeatCellID = "TBRPPresetRepeatCell"
12 |
13 | @objc protocol TBRepeatPickerDelegate {
14 | func didPickRecurrence(recurrence: TBRecurrence?, repeatPicker: TBRepeatPicker)
15 | }
16 |
17 | class TBRPPresetRepeatController: UITableViewController, TBRPCustomRepeatControllerDelegate {
18 | // MARK: - Public properties
19 | var occurrenceDate = NSDate()
20 | var tintColor = UIColor.blueColor()
21 | var language: TBRPLanguage = .English
22 | var delegate: TBRepeatPickerDelegate?
23 |
24 | var recurrence: TBRecurrence? {
25 | didSet {
26 | setupSelectedIndexPath(recurrence)
27 | }
28 | }
29 | var selectedIndexPath = NSIndexPath(forRow: 0, inSection: 0)
30 |
31 | // MARK: - Private properties
32 | private var recurrenceBackup: TBRecurrence?
33 | private var presetRepeats = [String]()
34 | private var internationalControl: TBRPInternationalControl?
35 |
36 | // MARK: - View life cycle
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 |
40 | commonInit()
41 | }
42 |
43 | private func commonInit() {
44 | internationalControl = TBRPInternationalControl(language: language)
45 | navigationItem.title = internationalControl?.localized("TBRPPresetRepeatController.navigation.title", comment: "Repeat")
46 |
47 | navigationController?.navigationBar.tintColor = tintColor
48 | tableView.tintColor = tintColor
49 |
50 | presetRepeats = TBRPHelper.presetRepeats(language)
51 |
52 | if let _ = recurrence {
53 | recurrenceBackup = recurrence!.recurrenceCopy()
54 | }
55 | }
56 |
57 | override func didMoveToParentViewController(parent: UIViewController?) {
58 | if parent == nil {
59 | // navigation was popped
60 | if TBRecurrence.isEqualRecurrence(recurrence, recurrence2: recurrenceBackup) == false {
61 | if let _ = delegate {
62 | delegate?.didPickRecurrence(recurrence, repeatPicker: self as! TBRepeatPicker)
63 | }
64 | }
65 | }
66 | }
67 |
68 | // MARK: - Helper
69 | private func setupSelectedIndexPath(recurrence: TBRecurrence?) {
70 | if recurrence == nil {
71 | selectedIndexPath = NSIndexPath(forRow: 0, inSection: 0)
72 | } else if recurrence?.isDailyRecurrence() == true {
73 | selectedIndexPath = NSIndexPath(forRow: 1, inSection: 0)
74 | } else if recurrence?.isWeeklyRecurrence(occurrenceDate) == true {
75 | selectedIndexPath = NSIndexPath(forRow: 2, inSection: 0)
76 | } else if recurrence?.isBiWeeklyRecurrence(occurrenceDate) == true {
77 | selectedIndexPath = NSIndexPath(forRow: 3, inSection: 0)
78 | } else if recurrence?.isMonthlyRecurrence(occurrenceDate) == true {
79 | selectedIndexPath = NSIndexPath(forRow: 4, inSection: 0)
80 | } else if recurrence?.isYearlyRecurrence(occurrenceDate) == true {
81 | selectedIndexPath = NSIndexPath(forRow: 5, inSection: 0)
82 | } else {
83 | selectedIndexPath = NSIndexPath(forRow: 0, inSection: 1)
84 | }
85 | }
86 |
87 | private func updateRecurrence(indexPath: NSIndexPath) {
88 | if indexPath.section == 1 {
89 | return
90 | }
91 |
92 | switch indexPath.row {
93 | case 0:
94 | recurrence = nil
95 |
96 | case 1:
97 | recurrence = TBRecurrence.dailyRecurrence(occurrenceDate)
98 |
99 | case 2:
100 | recurrence = TBRecurrence.weeklyRecurrence(occurrenceDate)
101 |
102 | case 3:
103 | recurrence = TBRecurrence.biWeeklyRecurrence(occurrenceDate)
104 |
105 | case 4:
106 | recurrence = TBRecurrence.monthlyRecurrence(occurrenceDate)
107 |
108 | case 5:
109 | recurrence = TBRecurrence.yearlyRecurrence(occurrenceDate)
110 |
111 | default:
112 | break
113 | }
114 | }
115 |
116 | private func updateFooterTitle() {
117 | let footerView = tableView.footerViewForSection(1)
118 |
119 | tableView.beginUpdates()
120 | footerView?.textLabel?.text = footerTitle()
121 | tableView.endUpdates()
122 | footerView?.setNeedsLayout()
123 | }
124 |
125 | private func footerTitle() -> String? {
126 | if let _ = recurrence {
127 | if selectedIndexPath.section == 0 {
128 | return nil
129 | }
130 | return TBRPHelper.recurrenceString(recurrence!, occurrenceDate: occurrenceDate, language: language)
131 | }
132 | return nil
133 | }
134 |
135 | // MARK: - Table view data source
136 | override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
137 | return 2
138 | }
139 |
140 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
141 | if section == 0 {
142 | return presetRepeats.count
143 | } else {
144 | return 1
145 | }
146 | }
147 |
148 | override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
149 | return 44.0
150 | }
151 |
152 | override func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
153 | if section == 1 && recurrence != nil {
154 | return footerTitle()
155 | }
156 | return nil
157 | }
158 |
159 | override func tableView(tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
160 | if view.isKindOfClass(UITableViewHeaderFooterView) {
161 | let tableViewHeaderFooterView = view as! UITableViewHeaderFooterView
162 | tableViewHeaderFooterView.textLabel?.font = UIFont.systemFontOfSize(CGFloat(13.0))
163 | }
164 | }
165 |
166 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
167 | var cell = tableView.dequeueReusableCellWithIdentifier(TBRPPresetRepeatCellID)
168 | if cell == nil {
169 | cell = UITableViewCell(style: .Default, reuseIdentifier: TBRPPresetRepeatCellID)
170 | }
171 |
172 | if indexPath.section == 1 {
173 | cell?.accessoryType = .DisclosureIndicator
174 | cell?.textLabel?.text = internationalControl?.localized("TBRPPresetRepeatController.textLabel.custom", comment: "Custom")
175 | } else {
176 | cell?.accessoryType = .None
177 | cell?.textLabel?.text = presetRepeats[indexPath.row]
178 | }
179 |
180 | cell?.imageView?.image = UIImage(named: "TBRP-Checkmark")?.imageWithRenderingMode(.AlwaysTemplate)
181 |
182 | if indexPath == selectedIndexPath {
183 | cell?.imageView?.hidden = false
184 | } else {
185 | cell?.imageView?.hidden = true
186 | }
187 |
188 | return cell!
189 | }
190 |
191 | // MARK: - Table view delegate
192 | override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
193 | let lastSelectedCell = tableView.cellForRowAtIndexPath(selectedIndexPath)
194 | let currentSelectedCell = tableView.cellForRowAtIndexPath(indexPath)
195 |
196 | lastSelectedCell?.imageView?.hidden = true
197 | currentSelectedCell?.imageView?.hidden = false
198 |
199 | selectedIndexPath = indexPath
200 |
201 | if indexPath.section == 1 {
202 | let customRepeatController = TBRPCustomRepeatController(style: .Grouped)
203 | customRepeatController.occurrenceDate = occurrenceDate
204 | customRepeatController.tintColor = tintColor
205 | customRepeatController.language = language
206 |
207 | if let _ = recurrence {
208 | customRepeatController.recurrence = recurrence!
209 | } else {
210 | customRepeatController.recurrence = TBRecurrence.dailyRecurrence(occurrenceDate)
211 | }
212 | customRepeatController.delegate = self
213 |
214 | navigationController?.pushViewController(customRepeatController, animated: true)
215 | } else {
216 | updateRecurrence(indexPath)
217 | updateFooterTitle()
218 |
219 | navigationController?.popViewControllerAnimated(true)
220 | }
221 |
222 | tableView.deselectRowAtIndexPath(indexPath, animated: true)
223 | }
224 |
225 | // MARK: - TBRPCustomRepeatController delegate
226 | func didFinishPickingCustomRecurrence(recurrence: TBRecurrence) {
227 | self.recurrence = recurrence
228 | updateFooterTitle()
229 | tableView.reloadData()
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRecurrence.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRecurrence.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by 洪鑫 on 15/10/7.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | @objc enum TBRPFrequency: Int {
12 | case Daily = 0
13 | case Weekly = 1
14 | case Monthly = 2
15 | case Yearly = 3
16 | }
17 |
18 | @objc enum TBRPWeekPickerNumber: Int {
19 | case First = 0
20 | case Second = 1
21 | case Third = 2
22 | case Fourth = 3
23 | case Fifth = 4
24 | case Last = 5
25 | }
26 |
27 | @objc enum TBRPWeekPickerDay: Int {
28 | case Sunday = 0
29 | case Monday = 1
30 | case Tuesday = 2
31 | case Wednesday = 3
32 | case Thursday = 4
33 | case Friday = 5
34 | case Saturday = 6
35 | case Day = 7
36 | case Weekday = 8
37 | case WeekendDay = 9
38 | }
39 |
40 | class TBRecurrence: NSObject {
41 | /** The frequency of recurrence, must be one of the following cases:
42 | * TBRPFrequency.Daily
43 | * TBRPFrequency.Weekly
44 | * TBRPFrequency.Monthly
45 | * TBRPFrequency.Yearly
46 | */
47 | var frequency: TBRPFrequency = .Daily
48 |
49 | /** The interval between each frequency iteration. For example, when in a daily frequency, an interval of 1 means that event will occur every day, and an interval of 3 means that event will occur every 3 days. The default interval is 1.
50 | */
51 | var interval: Int = 1
52 |
53 | /** The selected weekdays when frequency is weekly. Elements in this array are all integers in a range between 0 to 6, 0 means Sunday, which is the first day of week, and the integers from 1 to 6 respectively mean the days from Monday to Saturday. This property value is valid only for a frequency type of TBRPFrequency.Weekly.
54 | */
55 | var selectedWeekdays = [Int]() {
56 | didSet {
57 | selectedWeekdays = selectedWeekdays.sort { $0 < $1 }
58 | }
59 | }
60 |
61 | /** A boolean value decides whether the recurrence is constructed by week number or not when frequency is weekly or yearly. For example, we can get a recurrence like "Second Friday" with it. This property value is valid only for a frequency type of TBRPFrequency.Monthly or TBRPFrequency.Yearly.
62 | */
63 | var byWeekNumber = false
64 |
65 | /** The selected monthdays when frequency is monthly. Elements in this array are all integers in a range between 1 to 31, which respectively mean the days from 1st to 31st of a month. This property value is valid only for a frequency type of TBRPFrequency.Monthly.
66 | */
67 | var selectedMonthdays = [Int]() {
68 | didSet {
69 | selectedMonthdays = selectedMonthdays.sort { $0 < $1 }
70 | }
71 | }
72 |
73 | /** The selected months when frequency is yearly. Elements in this array are all integers in a range between 1 to 12, which respectively mean the months from January to December. This property value is valid only for a frequency type of TBRPFrequency.Yearly.
74 | */
75 | var selectedMonths = [Int]() {
76 | didSet {
77 | selectedMonths = selectedMonths.sort { $0 < $1 }
78 | }
79 | }
80 |
81 | /** The week number when the recurrence is constructed by week number, must be one of the following cases:
82 | * TBRPWeekPickerNumber.First
83 | * TBRPWeekPickerNumber.Second
84 | * TBRPWeekPickerNumber.Third
85 | * TBRPWeekPickerNumber.Fourth
86 | * TBRPWeekPickerNumber.Fifth
87 | * TBRPWeekPickerNumber.Last
88 |
89 | This property value is valid only for a frequency type of TBRPFrequency.Monthly or TBRPFrequency.Yearly.
90 | */
91 | var pickedWeekNumber: TBRPWeekPickerNumber = .First
92 |
93 | /** The day of week when the recurrence is constructed by week number, must be one of the following cases:
94 | * TBRPWeekPickerDay.Sunday
95 | * TBRPWeekPickerDay.Monday
96 | * TBRPWeekPickerDay.Tuesday
97 | * TBRPWeekPickerDay.Wednesday
98 | * TBRPWeekPickerDay.Thursday
99 | * TBRPWeekPickerDay.Friday
100 | * TBRPWeekPickerDay.Saturday
101 | * TBRPWeekPickerDay.Day
102 | * TBRPWeekPickerDay.Weekday
103 | * TBRPWeekPickerDay.WeekendDay
104 |
105 | This property value is valid only for a frequency type of TBRPFrequency.Monthly or TBRPFrequency.Yearly.
106 | */
107 | var pickedWeekday: TBRPWeekPickerDay = .Sunday
108 |
109 | // MARK: - Initialization
110 | convenience init(occurrenceDate: NSDate) {
111 | self.init()
112 |
113 | let occurrenceDateDayIndexInWeek = NSCalendar.dayIndexInWeek(occurrenceDate)
114 | let occurrenceDateDayIndexInMonth = NSCalendar.dayIndexInMonth(occurrenceDate)
115 | let occurrenceDateMonthIndexInYear = NSCalendar.monthIndexInYear(occurrenceDate)
116 |
117 | selectedWeekdays = [occurrenceDateDayIndexInWeek - 1]
118 | selectedMonthdays = [occurrenceDateDayIndexInMonth]
119 | selectedMonths = [occurrenceDateMonthIndexInYear]
120 | }
121 |
122 | func recurrenceCopy() -> TBRecurrence {
123 | let recurrence = TBRecurrence()
124 |
125 | recurrence.frequency = frequency
126 | recurrence.interval = interval
127 | recurrence.selectedWeekdays = selectedWeekdays
128 | recurrence.byWeekNumber = byWeekNumber
129 | recurrence.selectedMonthdays = selectedMonthdays
130 | recurrence.selectedMonths = selectedMonths
131 | recurrence.pickedWeekNumber = pickedWeekNumber
132 | recurrence.pickedWeekday = pickedWeekday
133 |
134 | return recurrence
135 | }
136 |
137 | class func isEqualRecurrence(recurrence1: TBRecurrence?, recurrence2: TBRecurrence?) -> Bool {
138 | if recurrence1 == nil && recurrence2 == nil {
139 | return true
140 | } else if recurrence1?.frequency == recurrence2?.frequency && recurrence1?.interval == recurrence2?.interval {
141 | if recurrence1?.frequency == .Daily {
142 | return true
143 | } else if recurrence1?.frequency == .Weekly {
144 | let selectedWeekdays1 = recurrence1?.selectedWeekdays.sort { $0 < $1 }
145 | let selectedWeekdays2 = recurrence2?.selectedWeekdays.sort { $0 < $1 }
146 |
147 | return selectedWeekdays1! == selectedWeekdays2!
148 | } else if recurrence1?.frequency == .Monthly {
149 | if recurrence1?.byWeekNumber == recurrence2?.byWeekNumber {
150 | if recurrence1?.byWeekNumber == true {
151 | return recurrence1?.pickedWeekNumber == recurrence2?.pickedWeekNumber && recurrence1?.pickedWeekday == recurrence2?.pickedWeekday
152 | } else {
153 | let selectedMonthdays1 = recurrence1?.selectedMonthdays.sort { $0 < $1 }
154 | let selectedMonthdays2 = recurrence2?.selectedMonthdays.sort { $0 < $1 }
155 |
156 | return selectedMonthdays1! == selectedMonthdays2!
157 | }
158 | } else {
159 | return false
160 | }
161 | } else if recurrence1?.frequency == .Yearly {
162 | if recurrence1?.byWeekNumber == recurrence2?.byWeekNumber {
163 | let selectedMonths1 = recurrence1?.selectedMonths.sort { $0 < $1 }
164 | let selectedMonths2 = recurrence2?.selectedMonths.sort { $0 < $1 }
165 |
166 | if recurrence1?.byWeekNumber == true {
167 | return selectedMonths1! == selectedMonths2! && recurrence1?.pickedWeekNumber == recurrence2?.pickedWeekNumber && recurrence1?.pickedWeekday == recurrence2?.pickedWeekday
168 | } else {
169 | return selectedMonths1! == selectedMonths2!
170 | }
171 | } else {
172 | return false
173 | }
174 | } else {
175 | return false
176 | }
177 | } else {
178 | return false
179 | }
180 | }
181 |
182 | // preset recurrence initialization
183 | class func dailyRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
184 | return initDaily(1, occurrenceDate: occurrenceDate)
185 | }
186 |
187 | class func weeklyRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
188 | return initWeekly(1, selectedWeekdays: [], occurrenceDate: occurrenceDate)
189 | }
190 |
191 | class func biWeeklyRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
192 | return initWeekly(2, selectedWeekdays: [], occurrenceDate: occurrenceDate)
193 | }
194 |
195 | class func monthlyRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
196 | return initMonthly(1, selectedMonthdays: [], occurrenceDate: occurrenceDate)
197 | }
198 |
199 | class func yearlyRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
200 | return initYearly(1, selectedMonths: [], occurrenceDate: occurrenceDate)
201 | }
202 |
203 | class func weekdayRecurrence(occurrenceDate: NSDate) -> TBRecurrence {
204 | return initWeekly(1, selectedWeekdays: [1, 2, 3, 4, 5], occurrenceDate: occurrenceDate)
205 | }
206 |
207 | // custom recurrence initialization
208 | class func initDaily(interval: Int, occurrenceDate: NSDate) -> TBRecurrence {
209 | let dailyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
210 | dailyRecurrence.frequency = .Daily
211 |
212 | if interval < 1 {
213 | dailyRecurrence.interval = 1
214 | } else {
215 | dailyRecurrence.interval = interval
216 | }
217 |
218 | return dailyRecurrence
219 | }
220 |
221 | class func initWeekly(interval: Int, var selectedWeekdays: [Int], occurrenceDate: NSDate) -> TBRecurrence {
222 | let weeklyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
223 | weeklyRecurrence.frequency = .Weekly
224 | for day in selectedWeekdays {
225 | if day < 0 || day > 6 {
226 | selectedWeekdays.removeObject(day)
227 | }
228 | }
229 | selectedWeekdays = selectedWeekdays.unique
230 |
231 | if interval < 1 {
232 | weeklyRecurrence.interval = 1
233 | } else {
234 | weeklyRecurrence.interval = interval
235 | }
236 |
237 | if selectedWeekdays.count > 0 {
238 | weeklyRecurrence.selectedWeekdays = selectedWeekdays
239 | }
240 |
241 | return weeklyRecurrence
242 | }
243 |
244 | class func initMonthly(interval: Int, var selectedMonthdays: [Int], occurrenceDate: NSDate) -> TBRecurrence {
245 | let monthlyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
246 | monthlyRecurrence.frequency = .Monthly
247 | monthlyRecurrence.byWeekNumber = false
248 | for day in selectedMonthdays {
249 | if day < 1 || day > 31 {
250 | selectedMonthdays.removeObject(day)
251 | }
252 | }
253 | selectedMonthdays = selectedMonthdays.unique
254 |
255 | if interval < 1 {
256 | monthlyRecurrence.interval = 1
257 | } else {
258 | monthlyRecurrence.interval = interval
259 | }
260 |
261 | if selectedMonthdays.count > 0 {
262 | monthlyRecurrence.selectedMonthdays = selectedMonthdays
263 | }
264 |
265 | return monthlyRecurrence
266 | }
267 |
268 | class func initMonthlyByWeekNumber(interval: Int, pickedWeekNumber: TBRPWeekPickerNumber, pickedWeekday: TBRPWeekPickerDay, occurrenceDate: NSDate) -> TBRecurrence {
269 | let monthlyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
270 | monthlyRecurrence.frequency = .Monthly
271 | monthlyRecurrence.byWeekNumber = true
272 |
273 | if interval < 1 {
274 | monthlyRecurrence.interval = 1
275 | } else {
276 | monthlyRecurrence.interval = interval
277 | }
278 |
279 | monthlyRecurrence.pickedWeekNumber = pickedWeekNumber
280 | monthlyRecurrence.pickedWeekday = pickedWeekday
281 |
282 | return monthlyRecurrence
283 | }
284 |
285 | class func initYearly(interval: Int, var selectedMonths: [Int], occurrenceDate: NSDate) -> TBRecurrence {
286 | let yearlyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
287 | yearlyRecurrence.frequency = .Yearly
288 | yearlyRecurrence.byWeekNumber = false
289 | for day in selectedMonths {
290 | if day < 1 || day > 12 {
291 | selectedMonths.removeObject(day)
292 | }
293 | }
294 | selectedMonths = selectedMonths.unique
295 |
296 | if interval < 1 {
297 | yearlyRecurrence.interval = 1
298 | } else {
299 | yearlyRecurrence.interval = interval
300 | }
301 |
302 | if selectedMonths.count > 0 {
303 | yearlyRecurrence.selectedMonths = selectedMonths
304 | }
305 |
306 | return yearlyRecurrence
307 | }
308 |
309 | class func initYearlyByWeekNumber(interval: Int, pickedWeekNumber: TBRPWeekPickerNumber, pickedWeekday: TBRPWeekPickerDay, occurrenceDate: NSDate) -> TBRecurrence {
310 | let yearlyRecurrence = TBRecurrence(occurrenceDate: occurrenceDate)
311 | yearlyRecurrence.frequency = .Yearly
312 | yearlyRecurrence.byWeekNumber = true
313 |
314 | if interval < 1 {
315 | yearlyRecurrence.interval = 1
316 | } else {
317 | yearlyRecurrence.interval = interval
318 | }
319 |
320 | yearlyRecurrence.pickedWeekNumber = pickedWeekNumber
321 | yearlyRecurrence.pickedWeekday = pickedWeekday
322 |
323 | return yearlyRecurrence
324 | }
325 |
326 | // MARK: - Helper
327 | func isDailyRecurrence() -> Bool {
328 | return frequency == .Daily && interval == 1
329 | }
330 |
331 | func isWeeklyRecurrence(occurrenceDate: NSDate) -> Bool {
332 | let occurrenceDateDayIndexInWeek = NSCalendar.dayIndexInWeek(occurrenceDate)
333 |
334 | return frequency == .Weekly && selectedWeekdays == [occurrenceDateDayIndexInWeek - 1] && interval == 1
335 | }
336 |
337 | func isBiWeeklyRecurrence(occurrenceDate: NSDate) -> Bool {
338 | let occurrenceDateDayIndexInWeek = NSCalendar.dayIndexInWeek(occurrenceDate)
339 |
340 | return frequency == .Weekly && selectedWeekdays == [occurrenceDateDayIndexInWeek - 1] && interval == 2
341 | }
342 |
343 | func isMonthlyRecurrence(occurrenceDate: NSDate) -> Bool {
344 | let occurrenceDateDayIndexInMonth = NSCalendar.dayIndexInMonth(occurrenceDate)
345 |
346 | return frequency == .Monthly && interval == 1 && byWeekNumber == false && selectedMonthdays == [occurrenceDateDayIndexInMonth]
347 | }
348 |
349 | func isYearlyRecurrence(occurrenceDate: NSDate) -> Bool {
350 | let occurrenceDateMonthIndexInYear = NSCalendar.monthIndexInYear(occurrenceDate)
351 |
352 | return frequency == .Yearly && interval == 1 && byWeekNumber == false && selectedMonths == [occurrenceDateMonthIndexInYear]
353 | }
354 |
355 | func isWeekdayRecurrence() -> Bool {
356 | return frequency == .Weekly && interval == 1 && selectedWeekdays == [1, 2, 3, 4, 5]
357 | }
358 |
359 | func isCustomRecurrence(occurrenceDate: NSDate) -> Bool {
360 | return !isDailyRecurrence() && !isWeeklyRecurrence(occurrenceDate) && !isBiWeeklyRecurrence(occurrenceDate) && !isMonthlyRecurrence(occurrenceDate) && !isYearlyRecurrence(occurrenceDate)
361 | }
362 | }
363 |
--------------------------------------------------------------------------------
/TBRepeatPicker/TBRPHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TBRPHelper.swift
3 | // TBRepeatPicker
4 | //
5 | // Created by hongxin on 15/9/28.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let TBRPScreenWidth: CGFloat = UIScreen.mainScreen().bounds.size.width
12 | let TBRPScreenHeight: CGFloat = UIScreen.mainScreen().bounds.size.height
13 | let iPhone6PlusScreenWidth: CGFloat = 414.0
14 |
15 | let TBRPTopSeparatorIdentifier = "TBRPTopSeparator"
16 | let TBRPBottomSeparatorIdentifier = "TBRPBottomSeparator"
17 | let TBRPSeparatorLineWidth: CGFloat = 0.5
18 |
19 | class TBRPHelper {
20 | class func leadingMargin() -> CGFloat {
21 | if TBRPScreenWidth == iPhone6PlusScreenWidth {
22 | return 20.0
23 | }
24 | return 15.0
25 | }
26 |
27 | class func separatorColor() -> CGColorRef {
28 | let defaultSeparatorColor = UITableView().separatorColor
29 | let red = defaultSeparatorColor?.rgbComponents.red
30 | let green = defaultSeparatorColor?.rgbComponents.green
31 | let blue = defaultSeparatorColor?.rgbComponents.blue
32 | let bit: CGFloat = 255.0
33 |
34 | return UIColor.init(red: red! / bit, green: green! / bit, blue: blue! / bit, alpha: 0.7).CGColor
35 | }
36 |
37 | class func detailTextColor() -> UIColor {
38 | return UIColor.grayColor()
39 | }
40 |
41 | class func weekdays(language: TBRPLanguage) -> [String] {
42 | let languageLocale = NSLocale(localeIdentifier: TBRPInternationalControl.languageKey(language))
43 |
44 | let dateFormatter = NSDateFormatter()
45 | dateFormatter.locale = languageLocale
46 | return dateFormatter.weekdaySymbols
47 | }
48 |
49 | class func yearMonths(language: TBRPLanguage) -> [String] {
50 | let languageLocale = NSLocale(localeIdentifier: TBRPInternationalControl.languageKey(language))
51 |
52 | let dateFormatter = NSDateFormatter()
53 | dateFormatter.locale = languageLocale
54 | return dateFormatter.shortMonthSymbols
55 | }
56 |
57 | class func completeYearMonths(language: TBRPLanguage) -> [String] {
58 | let languageLocale = NSLocale(localeIdentifier: TBRPInternationalControl.languageKey(language))
59 |
60 | let dateFormatter = NSDateFormatter()
61 | dateFormatter.locale = languageLocale
62 | return dateFormatter.monthSymbols
63 | }
64 |
65 | class func englishDayString(day: Int) -> String {
66 | var suffix = "th"
67 | let ones = day % 10
68 | let tens = (day / 10) % 10
69 |
70 | if (tens == 1) {
71 | suffix = "th"
72 | } else if (ones == 1) {
73 | suffix = "st"
74 | } else if (ones == 2) {
75 | suffix = "nd"
76 | } else if (ones == 3) {
77 | suffix = "rd"
78 | } else {
79 | suffix = "th"
80 | }
81 |
82 | return "\(day)\(suffix)"
83 | }
84 |
85 | class func frequencies(language: TBRPLanguage) -> [String] {
86 | let internationalControl = TBRPInternationalControl(language: language)
87 |
88 | return [internationalControl.localized("TBRPHelper.frequencies.daily", comment: "Daily"),internationalControl.localized("TBRPHelper.frequencies.weekly", comment: "Weekly"), internationalControl.localized("TBRPHelper.frequencies.monthly", comment: "Monthly"), internationalControl.localized("TBRPHelper.frequencies.yearly", comment: "Yearly")]
89 | }
90 |
91 | class func units(language: TBRPLanguage) -> [String] {
92 | let internationalControl = TBRPInternationalControl(language: language)
93 |
94 | return [internationalControl.localized("TBRPHelper.units.day", comment: "Day"), internationalControl.localized("TBRPHelper.units.week", comment: "Week"), internationalControl.localized("TBRPHelper.units.month", comment: "Month"), internationalControl.localized("TBRPHelper.units.year", comment: "Year")]
95 | }
96 |
97 | class func pluralUnits(language: TBRPLanguage) -> [String] {
98 | let internationalControl = TBRPInternationalControl(language: language)
99 |
100 | return [internationalControl.localized("TBRPHelper.pluralUnits.days", comment: "days"), internationalControl.localized("TBRPHelper.pluralUnits.weeks", comment: "weeks"), internationalControl.localized("TBRPHelper.pluralUnits.months", comment: "months"), internationalControl.localized("TBRPHelper.pluralUnits.years", comment: "years")]
101 | }
102 |
103 | class func presetRepeats(language: TBRPLanguage) -> [String] {
104 | let internationalControl = TBRPInternationalControl(language: language)
105 |
106 | return [internationalControl.localized("TBRPHelper.presetRepeat.never", comment: "Never"), internationalControl.localized("TBRPHelper.presetRepeat.everyDay", comment: "Every Day"), internationalControl.localized("TBRPHelper.presetRepeat.everyWeek", comment: "Every Week"), internationalControl.localized("TBRPHelper.presetRepeat.everyTwoWeeks", comment: "Every 2 Weeks"), internationalControl.localized("TBRPHelper.presetRepeat.everyMonth", comment: "Every Month"), internationalControl.localized("TBRPHelper.presetRepeat.everyYear", comment: "Every Year")]
107 | }
108 |
109 | class func daysInWeekPicker(language: TBRPLanguage) -> [String] {
110 | let internationalControl = TBRPInternationalControl(language: language)
111 | let commonWeekdays = weekdays(language)
112 | let additionDays = [internationalControl.localized("TBRPHelper.daysInWeekPicker.day", comment: "day"), internationalControl.localized("TBRPHelper.daysInWeekPicker.weekday", comment: "weekday"), internationalControl.localized("TBRPHelper.daysInWeekPicker.weekendDay", comment: "weekend day")]
113 |
114 | return commonWeekdays + additionDays
115 | }
116 |
117 | class func numbersInWeekPicker(language: TBRPLanguage) -> [String] {
118 | let internationalControl = TBRPInternationalControl(language: language)
119 |
120 | return [internationalControl.localized("TBRPHelper.numbersInWeekPicker.first", comment: "first"), internationalControl.localized("TBRPHelper.numbersInWeekPicker.second", comment: "second"), internationalControl.localized("TBRPHelper.numbersInWeekPicker.third", comment: "third"), internationalControl.localized("TBRPHelper.numbersInWeekPicker.fourth", comment: "fourth"), internationalControl.localized("TBRPHelper.numbersInWeekPicker.fifth", comment: "fifth"), internationalControl.localized("TBRPHelper.numbersInWeekPicker.last", comment: "last")]
121 | }
122 |
123 | class func recurrenceString(recurrence: TBRecurrence, occurrenceDate: NSDate, language: TBRPLanguage) -> String? {
124 | let internationalControl = TBRPInternationalControl(language: language)
125 |
126 | var unitString: String?
127 | if language == .Korean || language == .Japanese {
128 | unitString = "\(recurrence.interval)" + pluralUnits(language)[recurrence.frequency.rawValue]
129 | } else {
130 | if recurrence.interval == 1 {
131 | unitString = units(language)[recurrence.frequency.rawValue]
132 | } else if recurrence.interval > 1 {
133 | if language == .English {
134 | unitString = "\(recurrence.interval)" + " " + pluralUnits(language)[recurrence.frequency.rawValue]
135 | } else {
136 | unitString = "\(recurrence.interval)" + pluralUnits(language)[recurrence.frequency.rawValue]
137 | }
138 | }
139 | }
140 |
141 | unitString = unitString?.lowercaseString
142 |
143 | if unitString == nil {
144 | return nil
145 | }
146 |
147 | if recurrence.frequency == .Daily {
148 | // Daily
149 | return String(format: internationalControl.localized("RecurrenceString.presetRepeat", comment: "Event will occur every %@."), unitString!)
150 | } else if recurrence.frequency == .Weekly {
151 | // Weekly
152 | let occurrenceDateDayIndexInWeek = NSCalendar.dayIndexInWeek(occurrenceDate)
153 |
154 | if recurrence.selectedWeekdays == [occurrenceDateDayIndexInWeek - 1] {
155 | return String(format: internationalControl.localized("RecurrenceString.presetRepeat", comment: "Event will occur every %@."), unitString!)
156 | } else if recurrence.isWeekdayRecurrence() {
157 | return internationalControl.localized("RecurrenceString.weekdayRecurrence", comment: "Event will occur every weekday.")
158 | } else if recurrence.selectedWeekdays == [0, 1, 2, 3, 4, 5, 6] && recurrence.interval == 1 {
159 | return recurrenceString(TBRecurrence.dailyRecurrence(occurrenceDate), occurrenceDate: occurrenceDate, language: language)
160 | } else {
161 | var weekdaysString: String
162 | if language == .Korean {
163 | weekdaysString = weekdays(language)[recurrence.selectedWeekdays.first!]
164 | } else {
165 | weekdaysString = internationalControl.localized("RecurrenceString.element.on.weekly", comment: "on") + " " + weekdays(language)[recurrence.selectedWeekdays.first!]
166 | }
167 |
168 | for i in 1.. Bool {
150 | return repeatPickerIndexPath != nil
151 | }
152 |
153 | private func hasWeekPicker() -> Bool {
154 | return weekPickerIndexPath != nil
155 | }
156 |
157 | private func closeRepeatPicker() {
158 | if !hasRepeatPicker() {
159 | return;
160 | }
161 |
162 | tableView.deleteRowsAtIndexPaths([repeatPickerIndexPath!], withRowAnimation: .Fade)
163 | repeatPickerIndexPath = nil
164 | updateDetailTextColor()
165 | }
166 |
167 | private func closeWeekPicker() {
168 | if !hasWeekPicker() {
169 | return;
170 | }
171 |
172 | tableView.deleteRowsAtIndexPaths([weekPickerIndexPath!], withRowAnimation: .Fade)
173 | weekPickerIndexPath = nil
174 | }
175 |
176 | private func isRepeatPickerCell(indexPath: NSIndexPath) -> Bool {
177 | return hasRepeatPicker() && repeatPickerIndexPath == indexPath
178 | }
179 |
180 | private func isWeekPickerCell(indexPath: NSIndexPath) -> Bool {
181 | return hasWeekPicker() && weekPickerIndexPath == indexPath && (frequency == .Monthly || frequency == .Yearly)
182 | }
183 |
184 | private func isMonthsCollectionCell(indexPath: NSIndexPath) -> Bool {
185 | return indexPath == NSIndexPath(forRow: 0, inSection: 1) && frequency == .Yearly
186 | }
187 |
188 | private func isDaysCollectionCell(indexPath: NSIndexPath) -> Bool {
189 | return indexPath == NSIndexPath(forRow: 2, inSection: 1) && frequency == .Monthly
190 | }
191 |
192 | private func setupData() {
193 | // refresh weekPickerIndexPath
194 | if byWeekNumber == true {
195 | if frequency == .Yearly {
196 | weekPickerIndexPath = NSIndexPath(forRow: 1, inSection: 2)
197 | } else if frequency == .Monthly {
198 | weekPickerIndexPath = NSIndexPath(forRow: 2, inSection: 1)
199 | }
200 | }
201 | }
202 |
203 | private func updateFrequencyTitleCell() {
204 | frequencyTitleCell?.detailTextLabel?.text = frequencies[(frequency?.rawValue)!]
205 | }
206 |
207 | private func updateIntervalTitleCell() {
208 | intervalTitleCell?.detailTextLabel?.text = unitString()
209 |
210 | if hasRepeatPicker() && repeatPickerIndexPath == NSIndexPath(forRow: 2, inSection: 0) {
211 | let cell = tableView.cellForRowAtIndexPath(repeatPickerIndexPath!) as! TBRPPickerViewCell
212 | cell.unit = unit()
213 | }
214 | }
215 |
216 | private func updateDetailTextColor() {
217 | if repeatPickerIndexPath == NSIndexPath(forRow: 1, inSection: 0) {
218 | frequencyTitleCell?.detailTextLabel?.textColor = tintColor
219 | } else if repeatPickerIndexPath == NSIndexPath(forRow: 2, inSection: 0) {
220 | intervalTitleCell?.detailTextLabel?.textColor = tintColor
221 | } else {
222 | let detailTextColor = TBRPHelper.detailTextColor()
223 | frequencyTitleCell?.detailTextLabel?.textColor = detailTextColor
224 | intervalTitleCell?.detailTextLabel?.textColor = detailTextColor
225 | }
226 | }
227 |
228 | private func updateMoreOptions() {
229 | if frequency == .Daily {
230 | let deleteRange = NSMakeRange(1, tableView.numberOfSections - 1)
231 |
232 | tableView.beginUpdates()
233 | tableView.deleteSections(NSIndexSet(indexesInRange: deleteRange), withRowAnimation: .Fade)
234 | tableView.endUpdates()
235 | } else if frequency == .Weekly || frequency == .Monthly {
236 | if tableView.numberOfSections == 1 {
237 | tableView.beginUpdates()
238 | tableView.insertSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
239 | tableView.endUpdates()
240 | } else if tableView.numberOfSections == 2 {
241 | tableView.beginUpdates()
242 | tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
243 | tableView.endUpdates()
244 | } else if tableView.numberOfSections == 3 {
245 | tableView.beginUpdates()
246 | tableView.deleteSections(NSIndexSet(index: 2), withRowAnimation: .Fade)
247 | tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
248 | tableView.endUpdates()
249 | }
250 | } else if frequency == .Yearly {
251 | if tableView.numberOfSections == 1 {
252 | let insertYearOptionsRange = NSMakeRange(1, 2)
253 | tableView.insertSections(NSIndexSet(indexesInRange: insertYearOptionsRange), withRowAnimation: .Fade)
254 | } else if tableView.numberOfSections == 2 {
255 | tableView.beginUpdates()
256 | tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
257 | tableView.insertSections(NSIndexSet(index: 2), withRowAnimation: .Fade)
258 | tableView.endUpdates()
259 | }
260 | }
261 | }
262 |
263 | private func updateWeekPickerOptions () {
264 | if frequency == .Monthly {
265 | tableView.beginUpdates()
266 | if hasRepeatPicker() {
267 | closeRepeatPicker()
268 | }
269 |
270 |
271 | weekPickerIndexPath = NSIndexPath(forRow: 2, inSection: 1)
272 | tableView.reloadRowsAtIndexPaths([weekPickerIndexPath!], withRowAnimation: .Fade)
273 |
274 | if byWeekNumber == false {
275 | weekPickerIndexPath = nil
276 | }
277 |
278 | tableView.endUpdates()
279 | } else if frequency == .Yearly {
280 | tableView.beginUpdates()
281 | if hasRepeatPicker() {
282 | closeRepeatPicker()
283 | }
284 |
285 | if byWeekNumber == true {
286 | weekPickerIndexPath = NSIndexPath(forRow: 1, inSection: 2)
287 | tableView.insertRowsAtIndexPaths([weekPickerIndexPath!], withRowAnimation: .Fade)
288 | } else if byWeekNumber == false {
289 | closeWeekPicker()
290 | }
291 |
292 | tableView.endUpdates()
293 | }
294 |
295 | updateIntervalCellBottomSeparator()
296 | }
297 |
298 | private func updateFooterTitle() {
299 | let footerView = tableView.footerViewForSection(0)
300 |
301 | tableView.beginUpdates()
302 | footerView?.textLabel?.text = footerTitle()
303 | tableView.endUpdates()
304 | footerView?.setNeedsLayout()
305 | }
306 |
307 | private func footerTitle() -> String? {
308 | return TBRPHelper.recurrenceString(recurrence, occurrenceDate: occurrenceDate, language: language)
309 | }
310 |
311 | private func unit() -> String? {
312 | if interval == 1 {
313 | return units[(frequency?.rawValue)!]
314 | } else if interval > 1 {
315 | return pluralUnits[(frequency?.rawValue)!]
316 | } else {
317 | return nil
318 | }
319 | }
320 |
321 | private func unitString() -> String? {
322 | if interval == 1 {
323 | return unit()
324 | } else if interval > 1 {
325 | return "\(interval!)" + " " + unit()!
326 | } else {
327 | return nil
328 | }
329 | }
330 |
331 | private func updateIntervalCellBottomSeparator() {
332 | if hasRepeatPicker() && intervalTitleIndexpath!.row == 1 {
333 | intervalTitleCell?.updateBottomSeparatorWithLeftX(TBRPHelper.leadingMargin())
334 | } else {
335 | intervalTitleCell?.updateBottomSeparatorWithLeftX(0)
336 | }
337 | }
338 |
339 | private func updateYearlyWeekCellBottomSeparator() {
340 | let yearlyWeekCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 2)) as! TBRPSwitchCell
341 | if byWeekNumber == true {
342 | yearlyWeekCell.updateBottomSeparatorWithLeftX(TBRPHelper.leadingMargin())
343 | } else {
344 | yearlyWeekCell.updateBottomSeparatorWithLeftX(0)
345 | }
346 | }
347 |
348 | // MARK: - Table view data source
349 | override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
350 | if frequency == .Daily {
351 | return 1
352 | } else if frequency == .Yearly {
353 | return 3
354 | } else {
355 | return 2
356 | }
357 | }
358 |
359 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
360 | if section == 0 {
361 | if hasRepeatPicker() {
362 | return 3
363 | } else {
364 | return 2
365 | }
366 | } else if section == 1 {
367 | if frequency == .Weekly {
368 | return 7
369 | } else if frequency == .Monthly {
370 | return 3
371 | } else if frequency == .Yearly {
372 | return 1
373 | } else {
374 | return 0
375 | }
376 | } else {
377 | if byWeekNumber == true {
378 | return 2
379 | }
380 | return 1
381 | }
382 | }
383 |
384 | override func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? {
385 | if section == 0 {
386 | return footerTitle()
387 | }
388 | return nil
389 | }
390 |
391 | override func tableView(tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
392 | if view.isKindOfClass(UITableViewHeaderFooterView) {
393 | let tableViewHeaderFooterView = view as! UITableViewHeaderFooterView
394 | tableViewHeaderFooterView.textLabel?.font = UIFont.systemFontOfSize(CGFloat(13.0))
395 | }
396 | }
397 |
398 | override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
399 | if isRepeatPickerCell(indexPath) || isWeekPickerCell(indexPath) {
400 | return TBRPPickerHeight
401 | } else if isMonthsCollectionCell(indexPath) {
402 | return TBRPMonthsCollectionHeight
403 | } else if isDaysCollectionCell(indexPath) {
404 | return TBRPDaysCollectionHeight
405 | }
406 |
407 | return 44.0
408 | }
409 |
410 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
411 | if indexPath.section == 0 {
412 | if isRepeatPickerCell(indexPath) {
413 | if indexPath == NSIndexPath(forRow: 1, inSection: 0) {
414 | let cell = TBRPPickerViewCell(style: .Default, reuseIdentifier: TBRPPickerViewCellID, pickerStyle: .Frequency, language: language)
415 | cell.frequency = frequency
416 | cell.delegate = self
417 | cell.selectionStyle = .None
418 | cell.accessoryType = .None
419 | return cell
420 | } else {
421 | let cell = TBRPPickerViewCell(style: .Default, reuseIdentifier: TBRPPickerViewCellID, pickerStyle: .Interval, language: language)
422 | cell.unit = unit()
423 | cell.interval = interval
424 | cell.delegate = self
425 | cell.selectionStyle = .None
426 | cell.accessoryType = .None
427 | return cell
428 | }
429 | } else {
430 | var cell = tableView.dequeueReusableCellWithIdentifier(TBRPCustomRepeatCellID) as? TBRPCustomRepeatCell
431 | if cell == nil {
432 | cell = TBRPCustomRepeatCell(style: .Value1, reuseIdentifier: TBRPCustomRepeatCellID)
433 | }
434 | cell?.selectionStyle = .Default
435 | cell!.accessoryType = .None
436 |
437 | if indexPath == frequencyTitleIndexpath {
438 | cell?.textLabel?.text = internationalControl?.localized("TBRPCustomRepeatController.textLabel.frequency", comment: "Frequency")
439 | cell?.detailTextLabel?.text = frequencies[(frequency?.rawValue)!]
440 | if hasRepeatPicker() && repeatPickerIndexPath == NSIndexPath(forRow: 1, inSection: 0) {
441 | cell?.detailTextLabel?.textColor = tintColor
442 | } else {
443 | cell?.detailTextLabel?.textColor = TBRPHelper.detailTextColor()
444 | }
445 |
446 | cell?.addSectionTopSeparator()
447 | } else if indexPath == intervalTitleIndexpath {
448 | cell?.textLabel?.text = internationalControl?.localized("TBRPCustomRepeatController.textLabel.interval", comment: "Every")
449 | cell?.detailTextLabel?.text = unitString()
450 |
451 | if hasRepeatPicker() && repeatPickerIndexPath == NSIndexPath(forRow: 2, inSection: 0) {
452 | cell?.updateBottomSeparatorWithLeftX(TBRPHelper.leadingMargin())
453 | cell?.detailTextLabel?.textColor = tintColor
454 | } else {
455 | cell?.updateBottomSeparatorWithLeftX(0)
456 | cell?.detailTextLabel?.textColor = TBRPHelper.detailTextColor()
457 | }
458 | }
459 |
460 | return cell!
461 | }
462 | } else if indexPath.section == 1 {
463 | if frequency == .Weekly {
464 | var cell = tableView.dequeueReusableCellWithIdentifier(TBRPCustomRepeatCellID) as? TBRPCustomRepeatCell
465 | if cell == nil {
466 | cell = TBRPCustomRepeatCell(style: .Value1, reuseIdentifier: TBRPCustomRepeatCellID)
467 | }
468 | cell?.selectionStyle = .Default
469 |
470 | cell?.textLabel?.text = TBRPHelper.weekdays(language)[indexPath.row]
471 | cell?.detailTextLabel?.text = nil
472 | if selectedWeekdays.contains(indexPath.row) == true {
473 | cell?.accessoryType = .Checkmark
474 | } else {
475 | cell?.accessoryType = .None
476 | }
477 |
478 | if indexPath.row == 0 {
479 | cell?.addSectionTopSeparator()
480 | } else if indexPath.row == TBRPHelper.weekdays(language).count - 1 {
481 | cell?.updateBottomSeparatorWithLeftX(0)
482 | }
483 |
484 | return cell!
485 | } else if frequency == .Monthly {
486 | if indexPath.row == 2 {
487 | if byWeekNumber == true {
488 | let cell = TBRPPickerViewCell(style: .Default, reuseIdentifier: TBRPPickerViewCellID, pickerStyle: .Week, language: language)
489 | cell.delegate = self
490 | cell.pickedWeekNumber = pickedWeekNumber
491 | cell.pickedWeekday = pickedWeekday
492 | cell.selectionStyle = .None
493 | cell.accessoryType = .None
494 | return cell
495 | } else {
496 | let cell = TBRPCollectionViewCell(style: .Default, reuseIdentifier: TBRPCollectionViewCellID, mode: .Days, language: language)
497 | cell.selectionStyle = .None
498 | cell.selectedMonthdays = selectedMonthdays
499 | cell.delegate = self
500 |
501 | return cell
502 | }
503 | } else {
504 | var cell = tableView.dequeueReusableCellWithIdentifier(TBRPCustomRepeatCellID) as? TBRPCustomRepeatCell
505 | if cell == nil {
506 | cell = TBRPCustomRepeatCell(style: .Value1, reuseIdentifier: TBRPCustomRepeatCellID)
507 | }
508 | cell?.selectionStyle = .Default
509 |
510 | switch indexPath.row {
511 | case 0:
512 | cell?.textLabel?.text = internationalControl?.localized("TBRPCustomRepeatController.textLabel.date", comment: "Each")
513 | cell?.selectionStyle = .Default
514 | if byWeekNumber == true {
515 | cell?.accessoryType = .None
516 | } else {
517 | cell?.accessoryType = .Checkmark
518 | }
519 | cell?.addSectionTopSeparator()
520 |
521 | case 1:
522 | cell?.textLabel?.text = internationalControl?.localized("TBRPCustomRepeatController.weekCell.onThe", comment: "On the...")
523 | cell?.selectionStyle = .Default
524 | if byWeekNumber == true {
525 | cell?.accessoryType = .Checkmark
526 | } else {
527 | cell?.accessoryType = .None
528 | }
529 |
530 | cell?.addSectionBottomSeparator()
531 |
532 | default:
533 | cell?.textLabel?.text = nil
534 | }
535 | cell?.detailTextLabel?.text = nil
536 |
537 | return cell!
538 | }
539 | } else {
540 | let cell = TBRPCollectionViewCell(style: .Default, reuseIdentifier: TBRPCollectionViewCellID, mode: .Months, language: language)
541 | cell.selectionStyle = .None
542 | cell.selectedMonths = selectedMonths
543 | cell.delegate = self
544 |
545 | return cell
546 | }
547 | } else {
548 | if indexPath.row == 0 {
549 | let cell = TBRPSwitchCell(style: .Default, reuseIdentifier: TBRPSwitchCellID)
550 |
551 | if let _ = byWeekNumber {
552 | cell.weekSwitch?.setOn(byWeekNumber!, animated: true)
553 | } else {
554 | cell.weekSwitch?.setOn(false, animated: false)
555 | }
556 | cell.textLabel?.text = internationalControl?.localized("TBRPCustomRepeatController.weekCell.daysOfWeek", comment: "Days of Week")
557 | cell.selectionStyle = .None
558 | cell.accessoryType = .None
559 | cell.delegate = self
560 |
561 | cell.addSectionTopSeparator()
562 | if byWeekNumber == true {
563 | cell.updateBottomSeparatorWithLeftX(TBRPHelper.leadingMargin())
564 | } else {
565 | cell.updateBottomSeparatorWithLeftX(0)
566 | }
567 | return cell
568 | } else {
569 | let cell = TBRPPickerViewCell(style: .Default, reuseIdentifier: TBRPPickerViewCellID, pickerStyle: .Week, language: language)
570 | cell.delegate = self
571 | cell.pickedWeekNumber = pickedWeekNumber
572 | cell.pickedWeekday = pickedWeekday
573 | cell.selectionStyle = .None
574 | cell.accessoryType = .None
575 | return cell
576 | }
577 | }
578 | }
579 |
580 | // MARK: - Table view delegate
581 | override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
582 | tableView.deselectRowAtIndexPath(indexPath, animated: true)
583 | if indexPath == repeatPickerIndexPath {
584 | return
585 | }
586 |
587 | let cell = tableView.cellForRowAtIndexPath(indexPath)
588 | if cell?.reuseIdentifier == TBRPCustomRepeatCellID {
589 | if indexPath.section == 0 {
590 | tableView.beginUpdates()
591 |
592 | if hasRepeatPicker() {
593 | let repeatPickerIndexPathTemp = repeatPickerIndexPath
594 | closeRepeatPicker()
595 |
596 | if indexPath.row == (repeatPickerIndexPathTemp!.row) - 1 {
597 |
598 | } else {
599 | if indexPath == frequencyTitleIndexpath {
600 | repeatPickerIndexPath = NSIndexPath(forRow: indexPath.row + 1, inSection: indexPath.section)
601 | } else {
602 | repeatPickerIndexPath = indexPath
603 | }
604 |
605 | tableView.insertRowsAtIndexPaths([repeatPickerIndexPath!], withRowAnimation: .Fade)
606 | }
607 | } else {
608 | repeatPickerIndexPath = NSIndexPath(forRow: indexPath.row + 1, inSection: indexPath.section)
609 | tableView.insertRowsAtIndexPaths([repeatPickerIndexPath!], withRowAnimation: .Fade)
610 | }
611 |
612 | tableView.endUpdates()
613 |
614 | updateIntervalCellBottomSeparator()
615 | updateDetailTextColor()
616 | } else if indexPath.section == 1 {
617 | if frequency == .Weekly {
618 | if hasRepeatPicker() {
619 | tableView.beginUpdates()
620 | closeRepeatPicker()
621 | tableView.endUpdates()
622 |
623 | updateIntervalCellBottomSeparator()
624 | }
625 |
626 | let cell = tableView.cellForRowAtIndexPath(indexPath)
627 | let day = indexPath.row
628 |
629 | if selectedWeekdays.count == 1 && selectedWeekdays.contains(day) == true {
630 | return
631 | }
632 |
633 | if selectedWeekdays.contains(day) == true {
634 | cell?.accessoryType = .None
635 | selectedWeekdays.removeObject(day)
636 | } else {
637 | cell?.accessoryType = .Checkmark
638 | selectedWeekdays.append(day)
639 | }
640 |
641 | updateFooterTitle()
642 | } else if frequency == .Monthly {
643 | let dateCellIndexPath = NSIndexPath(forRow: 0, inSection: 1)
644 | let weekCellIndexPath = NSIndexPath(forRow: 1, inSection: 1)
645 | let dateCell = tableView.cellForRowAtIndexPath(dateCellIndexPath)
646 | let weekCell = tableView.cellForRowAtIndexPath(weekCellIndexPath)
647 |
648 | if indexPath == weekCellIndexPath && byWeekNumber == false {
649 | byWeekNumber = true
650 | weekCell?.accessoryType = .Checkmark
651 | dateCell?.accessoryType = .None
652 | } else if indexPath == dateCellIndexPath && byWeekNumber == true {
653 | byWeekNumber = false
654 | dateCell?.accessoryType = .Checkmark
655 | weekCell?.accessoryType = .None
656 | }
657 |
658 | updateFooterTitle()
659 | }
660 | }
661 | }
662 | }
663 |
664 | // MARK: - TBRPPickerCell delegate
665 | func pickerDidPick(pickerView: UIPickerView, pickStyle: TBRPPickerStyle, didSelectRow row: Int, inComponent component: Int) {
666 | if pickStyle == .Frequency {
667 | frequency = TBRPFrequency(rawValue: row)
668 | } else if pickStyle == .Interval {
669 | if component == 0 {
670 | interval = row + 1
671 | }
672 | } else if pickStyle == .Week {
673 | if hasRepeatPicker() {
674 | tableView.beginUpdates()
675 | closeRepeatPicker()
676 | tableView.endUpdates()
677 |
678 | updateIntervalCellBottomSeparator()
679 | }
680 |
681 | if component == 0 {
682 | pickedWeekNumber = TBRPWeekPickerNumber(rawValue: row)!
683 | } else if component == 1 {
684 | pickedWeekday = TBRPWeekPickerDay(rawValue: row)!
685 | }
686 | }
687 |
688 | updateFooterTitle()
689 | }
690 |
691 | // MARK: - TBRPSwitchCell delegate
692 | func didSwitch(sender: AnyObject) {
693 | if let weekSwitch = sender as? UISwitch {
694 | byWeekNumber = weekSwitch.on
695 |
696 | updateYearlyWeekCellBottomSeparator()
697 | updateFooterTitle()
698 | }
699 | }
700 |
701 |
702 | // MARK: - TBRPCollectionViewCell delegate
703 | func selectedMonthdaysDidChanged(days: [Int]) {
704 | if hasRepeatPicker() {
705 | tableView.beginUpdates()
706 | closeRepeatPicker()
707 | tableView.endUpdates()
708 |
709 | updateIntervalCellBottomSeparator()
710 | }
711 |
712 | selectedMonthdays = days
713 |
714 | updateFooterTitle()
715 | }
716 |
717 | func selectedMonthsDidChanged(months: [Int]) {
718 | if hasRepeatPicker() {
719 | tableView.beginUpdates()
720 | closeRepeatPicker()
721 | tableView.endUpdates()
722 |
723 | updateIntervalCellBottomSeparator()
724 | }
725 |
726 | selectedMonths = months
727 |
728 | updateFooterTitle()
729 | }
730 | }
731 |
--------------------------------------------------------------------------------