├── README.md
├── VIPER-SWIFT
├── Images.xcassets
│ ├── line.imageset
│ │ ├── line.png
│ │ ├── line@2x.png
│ │ └── Contents.json
│ ├── alarm.imageset
│ │ ├── alarm.png
│ │ ├── alarm@2x.png
│ │ └── Contents.json
│ ├── check.imageset
│ │ ├── check.png
│ │ ├── check@2x.png
│ │ └── Contents.json
│ ├── empty.imageset
│ │ ├── empty.png
│ │ ├── empty@2x.png
│ │ └── Contents.json
│ ├── month.imageset
│ │ ├── month.png
│ │ ├── month@2x.png
│ │ └── Contents.json
│ ├── notes.imageset
│ │ ├── notes.png
│ │ ├── notes@2x.png
│ │ └── Contents.json
│ ├── paper.imageset
│ │ ├── paper.png
│ │ ├── paper@2x.png
│ │ └── Contents.json
│ ├── circle.imageset
│ │ ├── circle.png
│ │ ├── circle@2x.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Icon@2x.png
│ │ └── Contents.json
│ ├── calendar.imageset
│ │ ├── calendar.png
│ │ ├── calendar@2x.png
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ ├── Splash-4.png
│ │ ├── Splash-4@2x.png
│ │ ├── LaunchImage@2x.png
│ │ └── Contents.json
├── Classes
│ ├── Common
│ │ ├── Clock
│ │ │ ├── Clock.swift
│ │ │ └── DeviceClock.swift
│ │ ├── Store
│ │ │ ├── Entities
│ │ │ │ └── ManagedTodoItem.swift
│ │ │ ├── TODO.xcdatamodeld
│ │ │ │ └── TODO.xcdatamodel
│ │ │ │ │ └── contents
│ │ │ └── CoreDataStore.swift
│ │ ├── Model
│ │ │ ├── NearTermDateRelation.swift
│ │ │ └── TodoItem.swift
│ │ ├── View
│ │ │ └── RootWireframe.swift
│ │ └── Categories
│ │ │ └── NSCalendar+CalendarAdditions.swift
│ ├── Modules
│ │ ├── List
│ │ │ ├── Module Interface
│ │ │ │ └── ListModuleInterface.swift
│ │ │ ├── User Interface
│ │ │ │ ├── View
│ │ │ │ │ ├── ListViewInterface.swift
│ │ │ │ │ └── ListViewController.swift
│ │ │ │ ├── Presenter
│ │ │ │ │ ├── UpcomingDisplayData.swift
│ │ │ │ │ ├── UpcomingDisplaySection.swift
│ │ │ │ │ ├── UpcomingDisplayItem.swift
│ │ │ │ │ ├── ListPresenter.swift
│ │ │ │ │ └── UpcomingDisplayDataCollection.swift
│ │ │ │ └── Wireframe
│ │ │ │ │ └── ListWireframe.swift
│ │ │ └── Application Logic
│ │ │ │ ├── Interactor
│ │ │ │ ├── ListInteractorIO.swift
│ │ │ │ ├── UpcomingItem.swift
│ │ │ │ └── ListInteractor.swift
│ │ │ │ └── Manager
│ │ │ │ └── ListDataManager.swift
│ │ └── Add
│ │ │ ├── Module Interface
│ │ │ ├── AddModuleDelegateInterface.swift
│ │ │ └── AddModuleInterface.swift
│ │ │ ├── User Interface
│ │ │ ├── View
│ │ │ │ ├── AddViewInterface.swift
│ │ │ │ └── AddViewController.swift
│ │ │ ├── Presenter
│ │ │ │ └── AddPresenter.swift
│ │ │ ├── Transition
│ │ │ │ ├── AddDismissalTransition.swift
│ │ │ │ └── AddPresentationTransition.swift
│ │ │ └── Wireframe
│ │ │ │ └── AddWireframe.swift
│ │ │ └── Application Logic
│ │ │ ├── Interactor
│ │ │ └── AddInteractor.swift
│ │ │ └── Manager
│ │ │ └── AddDataManager.swift
│ ├── AppDelegate.swift
│ └── AppDependencies.swift
├── Info.plist
└── Base.lproj
│ └── Main.storyboard
├── VIPER-SWIFT.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
├── VIPER-SWIFTTests
├── DataTests.swift
├── Info.plist
├── CalendarTests.swift
└── RelativeDateTests.swift
└── LICENSE
/README.md:
--------------------------------------------------------------------------------
1 | VIPER-SWIFT
2 | ===========
3 |
4 | An example Todo list app written in Swift using the VIPER architecture.
5 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/line.imageset/line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/line.imageset/line.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/check.imageset/check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/check.imageset/check.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/empty.imageset/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/empty.imageset/empty.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/month.imageset/month.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/month.imageset/month.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/notes.imageset/notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/notes.imageset/notes.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/paper.imageset/paper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/paper.imageset/paper.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/check.imageset/check@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/check.imageset/check@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/circle.imageset/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/circle.imageset/circle.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/empty.imageset/empty@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/empty.imageset/empty@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/line.imageset/line@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/line.imageset/line@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/month.imageset/month@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/month.imageset/month@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/notes.imageset/notes@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/notes.imageset/notes@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/paper.imageset/paper@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/paper.imageset/paper@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/circle.imageset/circle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/circle.imageset/circle@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/Splash-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/Splash-4.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/Splash-4@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/Splash-4@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objcio/issue-13-viper-swift/HEAD/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/LaunchImage@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | profile
14 | *.moved-aside
15 | DerivedData
16 | .idea/
17 |
18 | /Build
19 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Clock/Clock.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Clock.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol Clock {
12 | func today() -> NSDate
13 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Clock/DeviceClock.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeviceClock.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class DeviceClock : NSObject, Clock {
12 | func today() -> NSDate {
13 | return NSDate()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/Module Interface/ListModuleInterface.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListModuleInterface.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ListModuleInterface {
12 | func addNewEntry()
13 | func updateView()
14 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/line.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "line.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "line@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/alarm.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "alarm.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "alarm@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "check.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "check@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/empty.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "empty.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "empty@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/month.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "month.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "month@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/notes.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "notes.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "notes@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/paper.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "paper.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "paper@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/circle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "circle.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "circle@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/calendar.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "calendar.png"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x",
11 | "filename" : "calendar@2x.png"
12 | }
13 | ],
14 | "info" : {
15 | "version" : 1,
16 | "author" : "xcode"
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Store/Entities/ManagedTodoItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ManagedTodoItem.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Conrad Stoll. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class ManagedTodoItem : NSManagedObject {
13 | @NSManaged var name : NSString
14 | @NSManaged var date : NSDate
15 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/Module Interface/AddModuleDelegateInterface.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddModuleDelegateInterface.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AddModuleDelegate {
12 | func addModuleDidCancelAddAction()
13 | func addModuleDidSaveAddAction()
14 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/Module Interface/AddModuleInterface.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddModuleInterface.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AddModuleInterface {
12 | func cancelAddAction()
13 | func saveAddActionWithName(name: NSString, dueDate: NSDate)
14 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Model/NearTermDateRelation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NearTermDateRelation.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum NearTermDateRelation {
12 | case OutOfRange,
13 | Today,
14 | Tomorrow,
15 | LaterThisWeek,
16 | NextWeek
17 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/View/AddViewInterface.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddViewInterface.swift
3 | // VIPER TODO
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AddViewInterface {
12 | func setEntryName(name: NSString)
13 | func setEntryDueDate(date: NSDate)
14 | func setMinimumDueDate(date: NSDate)
15 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Model/TodoItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TodoItem.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct TodoItem {
12 | let dueDate : NSDate
13 | let name : String
14 |
15 | init(dueDate: NSDate, name: String) {
16 | self.dueDate = dueDate
17 | self.name = name
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/View/ListViewInterface.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListViewInterface.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ListViewInterface {
12 | func showNoContentMessage()
13 | func showUpcomingDisplayData(data: UpcomingDisplayData)
14 | func reloadEntries ()
15 | }
16 |
17 |
18 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/Application Logic/Interactor/ListInteractorIO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListInteractorIO.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 |
12 | protocol ListInteractorInput {
13 | func findUpcomingItems()
14 | }
15 |
16 | protocol ListInteractorOutput {
17 | func foundUpcomingItems(upcomingItems: UpcomingItem[])
18 | }
19 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.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" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "size" : "60x60",
15 | "idiom" : "iphone",
16 | "filename" : "Icon@2x.png",
17 | "scale" : "2x"
18 | }
19 | ],
20 | "info" : {
21 | "version" : 1,
22 | "author" : "xcode"
23 | }
24 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/Application Logic/Interactor/AddInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddInteractor.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class AddInteractor : NSObject {
12 | var addDataManager : AddDataManager?
13 |
14 | func saveNewEntryWithName(name: NSString, dueDate: NSDate) {
15 | let newEntry = TodoItem(dueDate: dueDate, name: name)
16 | addDataManager?.addNewEntry(newEntry)
17 | }
18 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/Application Logic/Manager/AddDataManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddDataManager.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class AddDataManager : NSObject {
12 | var dataStore : CoreDataStore?
13 |
14 | func addNewEntry(entry: TodoItem) {
15 | let newEntry = dataStore?.newTodoItem() as ManagedTodoItem
16 | newEntry.name = entry.name
17 | newEntry.date = entry.dueDate;
18 |
19 | dataStore?.save()
20 | }
21 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Conrad Stoll. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 |
15 | let appDependencies = AppDependencies()
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
18 | appDependencies.installRootViewControllerIntoWindow(window!)
19 |
20 | return true
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Presenter/UpcomingDisplayData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpcomingDisplayData.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UpcomingDisplayData : Equatable {
12 | let sections : UpcomingDisplaySection[] = []
13 |
14 | init(sections: UpcomingDisplaySection[]) {
15 | self.sections = sections
16 | self.sections.unshare()
17 | }
18 | }
19 |
20 | func == (leftSide: UpcomingDisplayData, rightSide: UpcomingDisplayData) -> Bool {
21 | var hasEqualSections = false
22 | hasEqualSections = rightSide.sections == leftSide.sections
23 | return hasEqualSections
24 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/View/RootWireframe.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootWireframe.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class RootWireframe : NSObject {
13 | func showRootViewController(viewController: UIViewController, inWindow: UIWindow) {
14 | let navigationController = navigationControllerFromWindow(inWindow)
15 | navigationController.viewControllers = [viewController]
16 | }
17 |
18 | func navigationControllerFromWindow(window: UIWindow) -> UINavigationController {
19 | let navigationController = window.rootViewController as UINavigationController
20 | return navigationController
21 | }
22 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Store/TODO.xcdatamodeld/TODO.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/VIPER-SWIFTTests/DataTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataStoreTests.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/6/14.
6 | // Copyright (c) 2014 Conrad Stoll. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class DataTests: XCTestCase {
12 | var dataStore = CoreDataStore()
13 | var dataManager = ListDataManager()
14 |
15 | override func setUp() {
16 | super.setUp()
17 |
18 | dataManager.coreDataStore = dataStore
19 | }
20 |
21 | func testPerformance() {
22 | self.measureBlock() {
23 | let startDate = NSDate()
24 | let endDate = NSDate(timeIntervalSinceReferenceDate: 0)
25 | self.dataManager.todoItemsBetweenStartDate(startDate, endDate: endDate, completion: { entries in
26 |
27 | })
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/VIPER-SWIFTTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Presenter/UpcomingDisplaySection.swift:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // UpcomingDisplaySection.swift
4 | // VIPER-SWIFT
5 | //
6 | // Created by Conrad Stoll on 6/5/14.
7 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
8 | //
9 |
10 | import Foundation
11 |
12 | struct UpcomingDisplaySection : Equatable {
13 | let name : String = ""
14 | let imageName : String = ""
15 | var items : UpcomingDisplayItem[] = []
16 |
17 | init(name: String, imageName: String, items: UpcomingDisplayItem[]?) {
18 | self.name = name
19 | self.imageName = imageName
20 |
21 | if items {
22 | self.items = items!
23 | self.items.unshare()
24 | }
25 | }
26 | }
27 |
28 | func == (leftSide: UpcomingDisplaySection, rightSide: UpcomingDisplaySection) -> Bool {
29 | var hasEqualSections = false
30 | hasEqualSections = rightSide.items == leftSide.items
31 | return hasEqualSections
32 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Presenter/UpcomingDisplayItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpcomingDisplayItem.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UpcomingDisplayItem : Equatable, Printable {
12 | let title : String = ""
13 | let dueDate : String = ""
14 |
15 | var description : String { get {
16 | return "\(title) -- \(dueDate)"
17 | }}
18 |
19 | init(title: String, dueDate: String) {
20 | self.title = title
21 | self.dueDate = dueDate
22 | }
23 | }
24 |
25 | func == (leftSide: UpcomingDisplayItem, rightSide: UpcomingDisplayItem) -> Bool {
26 | var hasEqualSections = false
27 | hasEqualSections = rightSide.title == leftSide.title
28 |
29 | if hasEqualSections == false {
30 | return false
31 | }
32 |
33 | hasEqualSections = rightSide.dueDate == rightSide.dueDate
34 |
35 | return hasEqualSections
36 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "filename" : "Splash-4@2x.png",
9 | "scale" : "2x"
10 | },
11 | {
12 | "extent" : "full-screen",
13 | "idiom" : "iphone",
14 | "subtype" : "retina4",
15 | "filename" : "LaunchImage@2x.png",
16 | "minimum-system-version" : "7.0",
17 | "orientation" : "portrait",
18 | "scale" : "2x"
19 | },
20 | {
21 | "orientation" : "portrait",
22 | "idiom" : "iphone",
23 | "extent" : "full-screen",
24 | "filename" : "Splash-4.png",
25 | "scale" : "1x"
26 | },
27 | {
28 | "orientation" : "portrait",
29 | "idiom" : "iphone",
30 | "extent" : "full-screen",
31 | "subtype" : "retina4",
32 | "scale" : "2x"
33 | }
34 | ],
35 | "info" : {
36 | "version" : 1,
37 | "author" : "xcode"
38 | }
39 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/Presenter/AddPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddPresenter.swift
3 | // VIPER TODO
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class AddPresenter : NSObject, AddModuleInterface {
12 | var addInteractor : AddInteractor?
13 | var addWireframe : AddWireframe?
14 | var addModuleDelegate : AddModuleDelegate?
15 |
16 | func cancelAddAction() {
17 | addWireframe?.dismissAddInterface()
18 | addModuleDelegate?.addModuleDidCancelAddAction()
19 | }
20 |
21 | func saveAddActionWithName(name: NSString, dueDate: NSDate) {
22 | addInteractor?.saveNewEntryWithName(name, dueDate: dueDate);
23 | addWireframe?.dismissAddInterface()
24 | addModuleDelegate?.addModuleDidSaveAddAction()
25 | }
26 |
27 | func configureUserInterfaceForPresentation(addViewUserInterface: AddViewInterface) {
28 | addViewUserInterface.setMinimumDueDate(NSDate())
29 | }
30 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Mutual Mobile
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.
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/Application Logic/Interactor/UpcomingItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpcomingItem.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct UpcomingItem : Equatable {
12 | let title : String = ""
13 | let dueDate : NSDate = NSDate()
14 | let dateRelation : NearTermDateRelation = NearTermDateRelation.OutOfRange
15 |
16 | init(title: String, dueDate: NSDate, dateRelation: NearTermDateRelation) {
17 | self.title = title
18 | self.dueDate = dueDate
19 | self.dateRelation = dateRelation
20 | }
21 | }
22 |
23 | func == (leftSide: UpcomingItem, rightSide: UpcomingItem) -> Bool {
24 | var hasEqualSections = false
25 | hasEqualSections = rightSide.title == leftSide.title
26 |
27 | if hasEqualSections == false {
28 | return false
29 | }
30 |
31 | hasEqualSections = rightSide.dueDate == rightSide.dueDate
32 |
33 | if hasEqualSections == false {
34 | return false
35 | }
36 |
37 | hasEqualSections = rightSide.dateRelation == rightSide.dateRelation
38 |
39 | return hasEqualSections
40 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarStyle
34 | UIStatusBarStyleLightContent
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 |
39 | UIViewControllerBasedStatusBarAppearance
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/Application Logic/Manager/ListDataManager.swift:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // ListDataManager.swift
4 | // VIPER-SWIFT
5 | //
6 | // Created by Conrad Stoll on 6/5/14.
7 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
8 | //
9 |
10 | import Foundation
11 |
12 | class ListDataManager : NSObject {
13 | var coreDataStore : CoreDataStore?
14 |
15 | func todoItemsBetweenStartDate(startDate: NSDate, endDate: NSDate, completion: ((TodoItem[]) -> Void)!) {
16 | let calendar = NSCalendar.autoupdatingCurrentCalendar()
17 | let beginning = calendar.dateForBeginningOfDay(startDate)
18 | let end = calendar.dateForEndOfDay(endDate)
19 |
20 | let predicate = NSPredicate(format: "(date >= %@) AND (date <= %@)", beginning, end)
21 | let sortDescriptors = []
22 |
23 | coreDataStore?.fetchEntriesWithPredicate(predicate,
24 | sortDescriptors: sortDescriptors,
25 | completionBlock: { entries in
26 | let todoItems = self.todoItemsFromDataStoreEntries(entries)
27 | completion(todoItems)
28 | })
29 | }
30 |
31 | func todoItemsFromDataStoreEntries(entries: ManagedTodoItem[]) -> TodoItem[] {
32 | var todoItems : TodoItem[] = []
33 |
34 | for managedTodoItem in entries {
35 | let todoItem = TodoItem(dueDate: managedTodoItem.date, name: managedTodoItem.name)
36 | todoItems.append(todoItem)
37 | }
38 |
39 | return todoItems
40 | }
41 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/Transition/AddDismissalTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddDismissalTransition.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AddDismissalTransition : NSObject, UIViewControllerAnimatedTransitioning {
13 | func transitionDuration(transitionContext: UIViewControllerContextTransitioning!) -> NSTimeInterval {
14 | return 0.72
15 | }
16 |
17 | func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
18 | let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as AddViewController
19 |
20 | let finalCenter = CGPointMake(160.0, (fromVC.view.bounds.size.height / 2) - 1000.0)
21 |
22 | let options = UIViewAnimationOptions.CurveEaseIn
23 |
24 | UIView.animateWithDuration(self.transitionDuration(transitionContext),
25 | delay: 0.0,
26 | usingSpringWithDamping: 0.64,
27 | initialSpringVelocity: 0.22,
28 | options: options,
29 | animations: {
30 | fromVC.view.center = finalCenter
31 | fromVC.transitioningBackgroundView.alpha = 0.0
32 | },
33 | completion: { finished in
34 | fromVC.view.removeFromSuperview()
35 | transitionContext.completeTransition(true)
36 | }
37 | )
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Wireframe/ListWireframe.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListWireframe.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | let ListViewControllerIdentifier = "ListViewController"
13 |
14 | class ListWireframe : NSObject {
15 | var addWireframe : AddWireframe?
16 | var listPresenter : ListPresenter?
17 | var rootWireframe : RootWireframe?
18 | var listViewController : ListViewController?
19 |
20 | func presentListInterfaceFromWindow(window: UIWindow) {
21 | let viewController = listViewControllerFromStoryboard()
22 | viewController.eventHandler = listPresenter
23 | listViewController = viewController
24 | listPresenter!.userInterface = viewController
25 | rootWireframe?.showRootViewController(viewController, inWindow: window)
26 | }
27 |
28 | func presentAddInterface() {
29 | addWireframe?.presentAddInterfaceFromViewController(listViewController!)
30 | }
31 |
32 | func listViewControllerFromStoryboard() -> ListViewController {
33 | let storyboard = mainStoryboard()
34 | let viewController = storyboard.instantiateViewControllerWithIdentifier(ListViewControllerIdentifier) as ListViewController
35 | return viewController
36 | }
37 |
38 | func mainStoryboard() -> UIStoryboard {
39 | let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
40 | return storyboard
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Presenter/ListPresenter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListPresenter.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class ListPresenter : NSObject, ListInteractorOutput, ListModuleInterface, AddModuleDelegate {
13 | var listInteractor : ListInteractorInput?
14 | var listWireframe : ListWireframe?
15 | var userInterface : ListViewInterface?
16 |
17 | func updateView() {
18 | listInteractor?.findUpcomingItems()
19 | }
20 |
21 | func foundUpcomingItems(upcomingItems: UpcomingItem[]) {
22 | if upcomingItems.count == 0 {
23 | userInterface?.showNoContentMessage()
24 | } else {
25 | updateUserInterfaceWithUpcomingItems(upcomingItems)
26 | }
27 | }
28 |
29 | func updateUserInterfaceWithUpcomingItems(upcomingItems: UpcomingItem[]) {
30 | let upcomingDisplayData = upcomingDisplayDataWithItems(upcomingItems)
31 | userInterface?.showUpcomingDisplayData(upcomingDisplayData)
32 | }
33 |
34 | func upcomingDisplayDataWithItems(upcomingItems: UpcomingItem[]) -> UpcomingDisplayData {
35 | let collection = UpcomingDisplayDataCollection()
36 | collection.addUpcomingItems(upcomingItems)
37 | return collection.collectedDisplayData()
38 | }
39 |
40 | func addNewEntry() {
41 | listWireframe?.presentAddInterface()
42 | }
43 |
44 | func addModuleDidCancelAddAction() {
45 | // No action necessary
46 | }
47 |
48 | func addModuleDidSaveAddAction() {
49 | updateView()
50 | }
51 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/Application Logic/Interactor/ListInteractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListInteractor.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class ListInteractor : NSObject, ListInteractorInput {
12 | var output : ListInteractorOutput?
13 |
14 | let clock : Clock
15 | let dataManager : ListDataManager
16 |
17 | init(dataManager: ListDataManager, clock: Clock) {
18 | self.dataManager = dataManager
19 | self.clock = clock
20 | }
21 |
22 | func findUpcomingItems() {
23 | let today = clock.today()
24 | let endOfNextWeek = NSCalendar.currentCalendar().dateForEndOfFollowingWeekWithDate(today)
25 |
26 | dataManager.todoItemsBetweenStartDate(today,
27 | endDate: endOfNextWeek,
28 | completion: { todoItems in
29 | let upcomingItems = self.upcomingItemsFromToDoItems(todoItems)
30 | self.output?.foundUpcomingItems(upcomingItems)
31 | })
32 | }
33 |
34 | func upcomingItemsFromToDoItems(todoItems: TodoItem[]) -> UpcomingItem[] {
35 | let calendar = NSCalendar.autoupdatingCurrentCalendar()
36 |
37 | var upcomingItems : UpcomingItem[] = []
38 |
39 | for todoItem in todoItems {
40 | var dateRelation = calendar.nearTermRelationForDate(todoItem.dueDate, relativeToToday: clock.today())
41 | let upcomingItem = UpcomingItem(title: todoItem.name, dueDate: todoItem.dueDate, dateRelation: dateRelation)
42 | upcomingItems.insert(upcomingItem, atIndex: upcomingItems.endIndex)
43 | }
44 |
45 | return upcomingItems
46 | }
47 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/AppDependencies.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDependencies.swift
3 | // VIPER TODO
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AppDependencies {
13 | var listWireframe = ListWireframe()
14 |
15 | init() {
16 | configureDependencies()
17 | }
18 |
19 | func installRootViewControllerIntoWindow(window: UIWindow) {
20 | listWireframe.presentListInterfaceFromWindow(window)
21 | }
22 |
23 | func configureDependencies() {
24 | let coreDataStore = CoreDataStore()
25 | let clock = DeviceClock()
26 | let rootWireframe = RootWireframe()
27 |
28 | let listPresenter = ListPresenter()
29 | let listDataManager = ListDataManager()
30 | let listInteractor = ListInteractor(dataManager: listDataManager, clock: clock)
31 |
32 | let addWireframe = AddWireframe()
33 | let addInteractor = AddInteractor()
34 | let addPresenter = AddPresenter()
35 | let addDataManager = AddDataManager()
36 |
37 | listInteractor.output = listPresenter
38 |
39 | listPresenter.listInteractor = listInteractor
40 | listPresenter.listWireframe = listWireframe
41 |
42 | listWireframe.addWireframe = addWireframe
43 | listWireframe.listPresenter = listPresenter
44 | listWireframe.rootWireframe = rootWireframe
45 |
46 | listDataManager.coreDataStore = coreDataStore
47 |
48 | addInteractor.addDataManager = addDataManager
49 |
50 | addWireframe.addPresenter = addPresenter
51 |
52 | addPresenter.addWireframe = addWireframe
53 | addPresenter.addModuleDelegate = listPresenter
54 | addPresenter.addInteractor = addInteractor
55 |
56 | addDataManager.dataStore = coreDataStore
57 | }
58 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/Wireframe/AddWireframe.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddWireframe.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | let AddViewControllerIdentifier = "AddViewController"
13 |
14 | class AddWireframe : NSObject, UIViewControllerTransitioningDelegate {
15 |
16 | var addPresenter : AddPresenter?
17 | var presentedViewController : UIViewController?
18 |
19 | func presentAddInterfaceFromViewController(viewController: UIViewController) {
20 | let newViewController = addViewController()
21 | newViewController.eventHandler = addPresenter
22 | newViewController.modalPresentationStyle = .Custom
23 | newViewController.transitioningDelegate = self
24 |
25 | addPresenter?.configureUserInterfaceForPresentation(newViewController)
26 |
27 | viewController.presentViewController(newViewController, animated: true, completion: nil)
28 |
29 | presentedViewController = newViewController
30 | }
31 |
32 | func dismissAddInterface() {
33 | presentedViewController?.dismissViewControllerAnimated(true, completion: nil)
34 | }
35 |
36 | func addViewController() -> AddViewController {
37 | let storyboard = mainStoryboard()
38 | let addViewController: AddViewController = storyboard.instantiateViewControllerWithIdentifier(AddViewControllerIdentifier) as AddViewController
39 | return addViewController
40 | }
41 |
42 | func mainStoryboard() -> UIStoryboard {
43 | let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
44 | return storyboard
45 | }
46 |
47 | func animationControllerForDismissedController(dismissed: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
48 | return AddDismissalTransition()
49 | }
50 |
51 | func animationControllerForPresentedController(presented: UIViewController!, presentingController presenting: UIViewController!, sourceController source: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
52 | return AddPresentationTransition()
53 | }
54 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/Transition/AddPresentationTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddPresentationTransition.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AddPresentationTransition: NSObject, UIViewControllerAnimatedTransitioning {
13 | func transitionDuration(transitionContext: UIViewControllerContextTransitioning!) -> NSTimeInterval {
14 | return 0.72
15 | }
16 |
17 | func animateTransition(transitionContext: UIViewControllerContextTransitioning!) {
18 | let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
19 | let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as AddViewController
20 |
21 | toVC.transitioningBackgroundView.backgroundColor = UIColor.darkGrayColor()
22 | toVC.transitioningBackgroundView.alpha = 0.0
23 | toVC.transitioningBackgroundView.frame = UIScreen.mainScreen().bounds
24 |
25 | let containerView = transitionContext.containerView()
26 | containerView.addSubview(toVC.transitioningBackgroundView)
27 | containerView.addSubview(toVC.view)
28 |
29 | let toViewFrame = CGRectMake(0, 0, 260, 300)
30 | toVC.view.frame = toViewFrame
31 |
32 | let finalCenter = CGPointMake(fromVC.view.bounds.size.width / 2, 20 + toViewFrame.size.height / 2)
33 | toVC.view.center = CGPointMake(finalCenter.x, finalCenter.y - 1000)
34 |
35 | let options = UIViewAnimationOptions.CurveEaseIn
36 |
37 | UIView.animateWithDuration(self.transitionDuration(transitionContext),
38 | delay: 0.0,
39 | usingSpringWithDamping: 0.64,
40 | initialSpringVelocity: 0.22,
41 | options: options,
42 | animations: {
43 | toVC.view.center = finalCenter
44 | toVC.transitioningBackgroundView.alpha = 0.7
45 | },
46 | completion: { finished in
47 | toVC.view.center = finalCenter
48 | transitionContext.completeTransition(true)
49 | }
50 | )
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/Add/User Interface/View/AddViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddViewController.swift
3 | // VIPER TODO
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AddViewController: UIViewController, UITextFieldDelegate, AddViewInterface {
13 | var eventHandler : AddModuleInterface?
14 |
15 | @IBOutlet var nameTextField : UITextField
16 | @IBOutlet var datePicker : UIDatePicker?
17 |
18 | var minimumDate : NSDate = NSDate()
19 | var transitioningBackgroundView : UIView = UIView()
20 |
21 | @IBAction func save(sender: AnyObject) {
22 | eventHandler?.saveAddActionWithName(nameTextField.text, dueDate: datePicker!.date)
23 | }
24 |
25 | @IBAction func cancel(sender: AnyObject) {
26 | nameTextField.resignFirstResponder()
27 | eventHandler?.cancelAddAction()
28 | }
29 |
30 | override func viewDidAppear(animated: Bool) {
31 | super.viewDidAppear(animated)
32 |
33 | var gestureRecognizer = UITapGestureRecognizer()
34 | gestureRecognizer.addTarget(self, action: Selector("dismiss"))
35 |
36 | transitioningBackgroundView.userInteractionEnabled = true
37 |
38 | nameTextField.becomeFirstResponder()
39 |
40 | if let realDatePicker = datePicker {
41 | realDatePicker.minimumDate = minimumDate
42 | }
43 | }
44 |
45 | override func viewWillDisappear(animated: Bool) {
46 | super.viewWillDisappear(animated)
47 |
48 | nameTextField.resignFirstResponder()
49 | }
50 |
51 | func dismiss() {
52 | eventHandler?.cancelAddAction()
53 | }
54 |
55 | func setEntryName(name: NSString) {
56 | nameTextField.text = name
57 | }
58 |
59 | func setEntryDueDate(date: NSDate) {
60 | if let realDatePicker = datePicker {
61 | realDatePicker.minimumDate = date
62 | }
63 | }
64 |
65 | func setMinimumDueDate(date: NSDate) {
66 | minimumDate = date
67 |
68 | if let realDatePicker = datePicker {
69 | realDatePicker.minimumDate = date
70 | }
71 | }
72 |
73 | func textFieldShouldReturn(textField: UITextField!) -> Bool {
74 | textField.resignFirstResponder()
75 |
76 | return true
77 | }
78 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Store/CoreDataStore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreDataStore.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/4/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | extension Array {
13 | func lastObject() -> T {
14 | let endIndex = self.endIndex
15 | let lastItemIndex = endIndex - 1
16 |
17 | return self[lastItemIndex]
18 | }
19 | }
20 |
21 | class CoreDataStore : NSObject {
22 | var persistentStoreCoordinator : NSPersistentStoreCoordinator?
23 | var managedObjectModel : NSManagedObjectModel?
24 | var managedObjectContext : NSManagedObjectContext?
25 |
26 | init() {
27 | managedObjectModel = NSManagedObjectModel.mergedModelFromBundles(nil)
28 |
29 | persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
30 |
31 | let domains = NSSearchPathDomainMask.UserDomainMask
32 | let directory = NSSearchPathDirectory.DocumentDirectory
33 |
34 | let error = NSError()
35 | let applicationDocumentsDirectory : AnyObject = NSFileManager.defaultManager().URLsForDirectory(directory, inDomains: domains).lastObject()
36 | let options = [NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true]
37 |
38 | let storeURL = applicationDocumentsDirectory.URLByAppendingPathComponent("VIPER-SWIFT.sqlite")
39 |
40 | persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: "", URL: storeURL, options: options, error: nil)
41 |
42 | managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
43 | managedObjectContext!.persistentStoreCoordinator = persistentStoreCoordinator
44 | managedObjectContext!.undoManager = nil
45 |
46 | super.init()
47 | }
48 |
49 | func fetchEntriesWithPredicate(predicate: NSPredicate, sortDescriptors: AnyObject[], completionBlock: ((ManagedTodoItem[]) -> Void)!) {
50 | let fetchRequest = NSFetchRequest(entityName: "TodoItem")
51 | fetchRequest.predicate = predicate
52 | fetchRequest.sortDescriptors = []
53 |
54 | managedObjectContext?.performBlock {
55 | let queryResults = self.managedObjectContext?.executeFetchRequest(fetchRequest, error: nil)
56 | let managedResults = queryResults! as ManagedTodoItem[]
57 | completionBlock(managedResults)
58 | }
59 | }
60 |
61 | func newTodoItem() -> ManagedTodoItem {
62 | let entityDescription = NSEntityDescription.entityForName("TodoItem", inManagedObjectContext: managedObjectContext)
63 | let newEntry = NSManagedObject(entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext) as ManagedTodoItem
64 |
65 | return newEntry
66 | }
67 |
68 | func save() {
69 | managedObjectContext?.save(nil)
70 | }
71 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/View/ListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListViewController.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | var ListEntryCellIdentifier = "ListEntryCell"
13 |
14 | class ListViewController : UITableViewController, ListViewInterface {
15 | var eventHandler : ListModuleInterface?
16 | var dataProperty : UpcomingDisplayData?
17 | var strongTableView : UITableView?
18 |
19 | @IBOutlet var noContentView : UIView
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | strongTableView = tableView
25 | configureView()
26 | }
27 |
28 | override func viewWillAppear(animated: Bool) {
29 | super.viewWillAppear(animated)
30 |
31 | eventHandler?.updateView()
32 | }
33 |
34 | func configureView() {
35 | navigationItem.title = "VIPER TODO"
36 |
37 | let addItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: Selector("didTapAddButton"))
38 |
39 | navigationItem.rightBarButtonItem = addItem
40 | }
41 |
42 | func didTapAddButton () {
43 | eventHandler?.addNewEntry()
44 | }
45 |
46 | func showNoContentMessage() {
47 | view = noContentView
48 | }
49 |
50 | func showUpcomingDisplayData(data: UpcomingDisplayData) {
51 | view = strongTableView
52 |
53 | dataProperty = data
54 | reloadEntries()
55 | }
56 |
57 | func reloadEntries() {
58 | tableView.reloadData()
59 | }
60 |
61 | override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
62 | var numberOfSections = dataProperty?.sections.count
63 |
64 | if dataProperty?.sections.count == nil {
65 | numberOfSections = 0
66 | }
67 |
68 | return numberOfSections!
69 | }
70 |
71 | override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
72 | let upcomingSection = dataProperty?.sections[section]
73 | return upcomingSection!.items.count
74 | }
75 |
76 | override func tableView(tableView: UITableView!, titleForHeaderInSection section: Int) -> String! {
77 | let upcomingSection = dataProperty?.sections[section]
78 | return upcomingSection!.name
79 | }
80 |
81 | override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
82 | let upcomingSection = dataProperty?.sections[indexPath.section]
83 | let upcomingItem = upcomingSection!.items[indexPath.row]
84 |
85 | let cell = tableView.dequeueReusableCellWithIdentifier(ListEntryCellIdentifier, forIndexPath: indexPath) as UITableViewCell
86 |
87 | cell.textLabel.text = upcomingItem.title;
88 | cell.detailTextLabel.text = upcomingItem.dueDate;
89 | cell.imageView.image = UIImage(named: upcomingSection!.imageName)
90 | cell.selectionStyle = UITableViewCellSelectionStyle.None;
91 |
92 | return cell
93 | }
94 | }
--------------------------------------------------------------------------------
/VIPER-SWIFTTests/CalendarTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CalendarTests.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/6/14.
6 | // Copyright (c) 2014 Conrad Stoll. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class CalendarTests: XCTestCase {
12 | var calendar = NSCalendar()
13 |
14 | override func setUp() {
15 | super.setUp()
16 |
17 | calendar = NSCalendar.gregorianCalendar()
18 | }
19 |
20 | func testEarlyYearMonthDayIsBeforeLaterYearMonthDay() {
21 | let earlyDate = calendar.dateWithYear(2004, month: 2, day: 29)
22 | let laterDate = calendar.dateWithYear(2004, month: 3, day: 1)
23 | let comparison = calendar.isDate(earlyDate, beforeYearMonthDay: laterDate)
24 | XCTAssert(comparison, "\(earlyDate) should be before \(laterDate)")
25 | }
26 |
27 | func testYearMonthDayIsNotBeforeSameYearMonthDay() {
28 | let earlyDate = calendar.dateWithYear(2005, month: 6, day: 1)
29 | let laterDate = calendar.dateWithYear(2005, month: 6, day: 1)
30 | let comparison = calendar.isDate(earlyDate, beforeYearMonthDay: laterDate)
31 | XCTAssertFalse(comparison, "\(earlyDate) should not be before \(laterDate)")
32 | }
33 |
34 | func testLaterYearMonthDayIsNotBeforeEarlyYearMonthDay() {
35 | let earlyDate = calendar.dateWithYear(2006, month: 4, day: 15)
36 | let laterDate = calendar.dateWithYear(2006, month: 4, day: 16)
37 | let comparison = calendar.isDate(laterDate, beforeYearMonthDay: earlyDate)
38 | XCTAssertFalse(comparison, "\(earlyDate) should not be before \(laterDate)")
39 | }
40 |
41 | func testEqualYearMonthDaysCompareAsEqual() {
42 | let earlyDate = calendar.dateWithYear(2005, month: 6, day: 1)
43 | let laterDate = calendar.dateWithYear(2005, month: 6, day: 1)
44 | let comparison = calendar.isDate(earlyDate, equalToYearMonthDay: laterDate)
45 | XCTAssert(comparison, "\(earlyDate) should equal \(laterDate)")
46 | }
47 |
48 | func testDifferentYearMonthDaysCompareAsNotEqual() {
49 | let earlyDate = calendar.dateWithYear(2005, month: 6, day: 1)
50 | let laterDate = calendar.dateWithYear(2005, month: 6, day: 2)
51 | let comparison = calendar.isDate(earlyDate, equalToYearMonthDay: laterDate)
52 | XCTAssertFalse(comparison, "\(earlyDate) should not equal \(laterDate)")
53 | }
54 |
55 | func testEndOfNextWeekDuringSameYear() {
56 | let date = calendar.dateWithYear(2005, month: 8, day: 2)
57 | let expectedNextWeek = calendar.dateWithYear(2005, month: 8, day: 13)
58 | let nextWeek = calendar.dateForEndOfFollowingWeekWithDate(date)
59 | let comparison = calendar.isDate(nextWeek, equalToYearMonthDay: expectedNextWeek)
60 | XCTAssert(comparison, "Next week should end on \(expectedNextWeek) (not \(nextWeek))")
61 | }
62 |
63 | func testEndOfNextWeekDuringFollowingYear() {
64 | let date = calendar.dateWithYear(2005, month: 12, day: 27)
65 | let expectedNextWeek = calendar.dateWithYear(2006, month: 1, day: 7)
66 | let nextWeek = calendar.dateForEndOfFollowingWeekWithDate(date)
67 | let comparison = calendar.isDate(nextWeek, equalToYearMonthDay: expectedNextWeek)
68 | XCTAssert(comparison, "Next week should end on \(expectedNextWeek) (not \(nextWeek))")
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/VIPER-SWIFTTests/RelativeDateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RelativeDateTests.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/6/14.
6 | // Copyright (c) 2014 Conrad Stoll. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class RelativeDateTests: XCTestCase {
12 | var calendar = NSCalendar()
13 |
14 | override func setUp() {
15 | super.setUp()
16 |
17 | calendar = NSCalendar.gregorianCalendar()
18 | }
19 |
20 | func testDateBeforeTodayIsOutOfBounds() {
21 | let date = calendar.dateWithYear(2000, month: 1, day: 1)
22 | let today = calendar.dateWithYear(2000, month: 1, day: 2)
23 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
24 | XCTAssertEqual(relation, NearTermDateRelation.OutOfRange, "\(date) should be out of range.")
25 | }
26 |
27 | func testTodayRelatesAsToday() {
28 | let date = calendar.dateWithYear(2000, month: 1, day: 1)
29 | let today = calendar.dateWithYear(2000, month: 1, day: 1)
30 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
31 | XCTAssertEqual(relation, NearTermDateRelation.Today, "\(date) should be today.")
32 | }
33 |
34 | func testTomorrowDuringTheSameWeekAsTodayRelatesAsTomorrow() {
35 | let date = calendar.dateWithYear(2004, month: 1, day: 3)
36 | let today = calendar.dateWithYear(2004, month: 1, day: 2)
37 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
38 | XCTAssertEqual(relation, NearTermDateRelation.Tomorrow, "\(date) should be tomorrow.")
39 | }
40 |
41 | func testTomorrowDuringNextWeekRelatesAsNextWeek() {
42 | let date = calendar.dateWithYear(2004, month: 10, day: 10)
43 | let today = calendar.dateWithYear(2004, month: 10, day: 9)
44 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
45 | XCTAssertEqual(relation, NearTermDateRelation.NextWeek, "\(date) should be next week.")
46 | }
47 |
48 | func testDateAfterTomorrowButDuringTheSameWeekAsTodayRelatesAsLaterThisWeek() {
49 | let date = calendar.dateWithYear(2004, month: 3, day: 6)
50 | let today = calendar.dateWithYear(2004, month: 3, day: 2)
51 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
52 | XCTAssertEqual(relation, NearTermDateRelation.LaterThisWeek, "\(date) should be later this week.")
53 | }
54 |
55 | func testDateDuringWeekAfterTodayRelatesAsNextWeek() {
56 | let date = calendar.dateWithYear(2004, month: 7, day: 11)
57 | let today = calendar.dateWithYear(2004, month: 7, day: 6)
58 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
59 | XCTAssertEqual(relation, NearTermDateRelation.NextWeek, "\(date) should be next week.")
60 | }
61 |
62 | func testDateDuringWeekAfterTodayThatFallsInNextYearRelatesAsNextWeek() {
63 | let date = calendar.dateWithYear(2006, month: 1, day: 2)
64 | let today = calendar.dateWithYear(2005, month: 12, day: 29)
65 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
66 | XCTAssertEqual(relation, NearTermDateRelation.NextWeek, "\(date) should be next week.")
67 | }
68 |
69 | func testDateBeyondNextWeekRelatesAsOutOfRange() {
70 | let date = calendar.dateWithYear(2005, month: 9, day: 25)
71 | let today = calendar.dateWithYear(2005, month: 9, day: 14)
72 | let relation = calendar.nearTermRelationForDate(date, relativeToToday: today)
73 | XCTAssertEqual(relation, NearTermDateRelation.OutOfRange, "\(date) should be next week.")
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Modules/List/User Interface/Presenter/UpcomingDisplayDataCollection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpcomingDisplayDataCollection.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UpcomingDisplayDataCollection {
12 | let dayFormatter = NSDateFormatter()
13 | var sections : Dictionary = Dictionary()
14 |
15 | init() {
16 | dayFormatter.dateFormat = NSDateFormatter.dateFormatFromTemplate("EEEE", options: 0, locale: NSLocale.autoupdatingCurrentLocale())
17 | }
18 |
19 | func addUpcomingItems(upcomingItems: UpcomingItem[]) {
20 | for upcomingItem in upcomingItems {
21 | addUpcomingItem(upcomingItem)
22 | }
23 | }
24 |
25 | func addUpcomingItem(upcomingItem: UpcomingItem) {
26 | var displayItem = displayItemForUpcomingItem(upcomingItem)
27 | addDisplayItem(displayItem, dateRelation: upcomingItem.dateRelation)
28 | }
29 |
30 | func addDisplayItem(displayItem: UpcomingDisplayItem, dateRelation: NearTermDateRelation) {
31 | if var realSection : UpcomingDisplayItem[] = sections[dateRelation] {
32 | realSection.append(displayItem)
33 | sections[dateRelation] = realSection
34 | } else {
35 | var newSection : UpcomingDisplayItem[] = []
36 | newSection.append(displayItem)
37 | sections[dateRelation] = newSection
38 | }
39 | }
40 |
41 | func displayItemForUpcomingItem(upcomingItem: UpcomingItem) -> UpcomingDisplayItem {
42 | let day = formattedDay(upcomingItem.dueDate, dateRelation: upcomingItem.dateRelation)
43 | let displayItem = UpcomingDisplayItem(title: upcomingItem.title, dueDate: day)
44 | return displayItem
45 | }
46 |
47 | func formattedDay(date: NSDate, dateRelation: NearTermDateRelation) -> String {
48 | if dateRelation == NearTermDateRelation.Today {
49 | return ""
50 | }
51 |
52 | return dayFormatter.stringFromDate(date)
53 | }
54 |
55 | func collectedDisplayData() -> UpcomingDisplayData {
56 | let collectedSections : UpcomingDisplaySection[] = sortedUpcomingDisplaySections()
57 | return UpcomingDisplayData(sections: collectedSections)
58 | }
59 |
60 | func displaySectionForDateRelation(dateRelation: NearTermDateRelation) -> UpcomingDisplaySection {
61 | let sectionTitle = sectionTitleForDateRelation(dateRelation)
62 | let imageName = sectionImageNameForDateRelation(dateRelation)
63 | let items = sections[dateRelation]
64 |
65 | return UpcomingDisplaySection(name: sectionTitle, imageName: imageName, items: items)
66 | }
67 |
68 | func sortedUpcomingDisplaySections() -> UpcomingDisplaySection[] {
69 | let keys = sortedNearTermDateRelations()
70 | var displaySections : UpcomingDisplaySection[] = []
71 |
72 | for dateRelation in keys {
73 | var itemArray = sections[dateRelation]
74 |
75 | if itemArray {
76 | var displaySection = displaySectionForDateRelation(dateRelation)
77 | displaySections.insert(displaySection, atIndex: displaySections.endIndex)
78 | }
79 | }
80 |
81 | return displaySections
82 | }
83 |
84 | func sortedNearTermDateRelations() -> NearTermDateRelation[] {
85 | var array : NearTermDateRelation[] = []
86 | array.insert(NearTermDateRelation.Today, atIndex: 0)
87 | array.insert(NearTermDateRelation.Tomorrow, atIndex: 1)
88 | array.insert(NearTermDateRelation.LaterThisWeek, atIndex: 2)
89 | array.insert(NearTermDateRelation.NextWeek, atIndex: 3)
90 | return array
91 | }
92 |
93 | func sectionTitleForDateRelation(dateRelation: NearTermDateRelation) -> String {
94 | switch dateRelation {
95 | case .Today:
96 | return "Today"
97 | case .Tomorrow:
98 | return "Tomorrow"
99 | case .LaterThisWeek:
100 | return "Later This Week"
101 | case .NextWeek:
102 | return "Next Week"
103 | case .OutOfRange:
104 | return "Unknown"
105 | }
106 | }
107 |
108 | func sectionImageNameForDateRelation(dateRelation: NearTermDateRelation) -> String {
109 | switch dateRelation {
110 | case .Today:
111 | return "check"
112 | case .Tomorrow:
113 | return "alarm"
114 | case .LaterThisWeek:
115 | return "circle"
116 | case .NextWeek:
117 | return "calendar"
118 | case .OutOfRange:
119 | return "paper"
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Categories/NSCalendar+CalendarAdditions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSCalendar+CalendarAdditions.swift
3 | // VIPER-SWIFT
4 | //
5 | // Created by Conrad Stoll on 6/5/14.
6 | // Copyright (c) 2014 Mutual Mobile. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSCalendar {
12 | class func gregorianCalendar() -> NSCalendar {
13 | return NSCalendar(calendarIdentifier: NSGregorianCalendar)
14 | }
15 |
16 | func dateWithYear(year: Int, month: Int, day: Int) -> NSDate {
17 | let components = NSDateComponents()
18 | components.year = year
19 | components.month = month
20 | components.day = day
21 | components.hour = 12
22 | return dateFromComponents(components)
23 | }
24 |
25 | func dateForTomorrowRelativeToToday(today: NSDate) -> NSDate {
26 | let tomorrowComponents = NSDateComponents()
27 | tomorrowComponents.day = 1
28 | return dateByAddingComponents(tomorrowComponents, toDate: today, options: nil)
29 | }
30 |
31 | func dateForEndOfWeekWithDate(date: NSDate) -> NSDate {
32 | let daysRemainingThisWeek = daysRemainingInWeekWithDate(date)
33 | let remainingDaysComponent = NSDateComponents()
34 | remainingDaysComponent.day = daysRemainingThisWeek
35 | return dateByAddingComponents(remainingDaysComponent, toDate: date, options: nil)
36 | }
37 |
38 | func dateForBeginningOfDay(date: NSDate) -> NSDate {
39 | let newComponent = components((NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay), fromDate: date)
40 | let newDate = dateFromComponents(newComponent)
41 | return newDate
42 | }
43 |
44 | func dateForEndOfDay(date: NSDate) -> NSDate {
45 | let components = NSDateComponents()
46 | components.day = 1
47 | let toDate = dateForBeginningOfDay(date)
48 | let nextDay = dateByAddingComponents(components, toDate: toDate, options: nil)
49 | let endDay = nextDay.dateByAddingTimeInterval(-1)
50 | return nextDay
51 | }
52 |
53 | func daysRemainingInWeekWithDate(date: NSDate) -> Int {
54 | let weekdayComponent = components(NSCalendarUnit.WeekdayCalendarUnit, fromDate: date)
55 | let daysRange = rangeOfUnit(NSCalendarUnit.WeekdayCalendarUnit, inUnit: NSCalendarUnit.WeekCalendarUnit, forDate: date)
56 | let daysPerWeek = daysRange.length
57 | let daysRemaining = daysPerWeek - weekdayComponent.weekday
58 | return daysRemaining
59 | }
60 |
61 | func dateForEndOfFollowingWeekWithDate(date: NSDate) -> NSDate {
62 | let endOfWeek = dateForEndOfWeekWithDate(date)
63 | let nextWeekComponent = NSDateComponents()
64 | nextWeekComponent.setWeek(1)
65 | let followingWeekDate = dateByAddingComponents(nextWeekComponent, toDate: endOfWeek, options: nil)
66 | return followingWeekDate
67 | }
68 |
69 | func isDate(date: NSDate, beforeYearMonthDay: NSDate) -> Bool {
70 | let comparison = compareYearMonthDay(date, toYearMonthDay: beforeYearMonthDay)
71 | let result = comparison == NSComparisonResult.OrderedAscending
72 | return result
73 | }
74 |
75 | func isDate(date: NSDate, equalToYearMonthDay: NSDate) -> Bool {
76 | let comparison = compareYearMonthDay(date, toYearMonthDay: equalToYearMonthDay)
77 | let result = comparison == NSComparisonResult.OrderedSame
78 | return result
79 | }
80 |
81 | func isDate(date: NSDate, duringSameWeekAsDate: NSDate) -> Bool {
82 | let dateComponents = components(NSCalendarUnit.WeekCalendarUnit, fromDate: date)
83 | let duringSameWeekComponents = components(NSCalendarUnit.WeekCalendarUnit, fromDate: duringSameWeekAsDate)
84 | let result = dateComponents.week() == duringSameWeekComponents.week()
85 | return result
86 | }
87 |
88 | func isDate(date: NSDate, duringWeekAfterDate: NSDate) -> Bool {
89 | let nextWeek = dateForEndOfFollowingWeekWithDate(duringWeekAfterDate)
90 | let dateComponents = components(NSCalendarUnit.WeekCalendarUnit, fromDate: date)
91 | let nextWeekComponents = components(NSCalendarUnit.WeekCalendarUnit, fromDate: nextWeek)
92 | let result = dateComponents.week() == nextWeekComponents.week()
93 | return result
94 | }
95 |
96 | func compareYearMonthDay(date: NSDate, toYearMonthDay: NSDate) -> NSComparisonResult {
97 | let dateComponents = yearMonthDayComponentsFromDate(date)
98 | let yearMonthDayComponents = yearMonthDayComponentsFromDate(toYearMonthDay)
99 |
100 | var result = compareInteger(dateComponents.year, right: yearMonthDayComponents.year)
101 |
102 | if result == NSComparisonResult.OrderedSame {
103 | result = compareInteger(dateComponents.month, right: yearMonthDayComponents.month)
104 |
105 | if result == NSComparisonResult.OrderedSame {
106 | result = compareInteger(dateComponents.day, right: yearMonthDayComponents.day)
107 | }
108 | }
109 |
110 | return result
111 | }
112 |
113 | func yearMonthDayComponentsFromDate(date: NSDate) -> NSDateComponents {
114 | let newComponents = components((NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay), fromDate: date)
115 | return newComponents
116 | }
117 |
118 | func compareInteger(left: Int, right: Int) -> NSComparisonResult {
119 | var result = NSComparisonResult.OrderedDescending
120 |
121 | if left == right {
122 | result = NSComparisonResult.OrderedSame
123 | } else if left < right {
124 | result = NSComparisonResult.OrderedAscending
125 | } else {
126 | result = NSComparisonResult.OrderedDescending
127 | }
128 |
129 | return result
130 | }
131 |
132 | func nearTermRelationForDate(date: NSDate, relativeToToday: NSDate) -> NearTermDateRelation {
133 | var relation = NearTermDateRelation.OutOfRange
134 |
135 | let dateForTomorrow = dateForTomorrowRelativeToToday(relativeToToday)
136 |
137 | let isDateBeforeYearMonthDay = isDate(date, beforeYearMonthDay: relativeToToday)
138 | let isDateEqualToYearMonthDay = isDate(date, equalToYearMonthDay: relativeToToday)
139 | let isDateEqualToYearMonthDayRelativeToTomorrow = isDate(date, equalToYearMonthDay: dateForTomorrow)
140 | let isDateDuringSameWeekAsDate = isDate(date, duringSameWeekAsDate: relativeToToday)
141 | let isDateDuringSameWeekAfterDate = isDate(date, duringWeekAfterDate: relativeToToday)
142 |
143 | if isDateBeforeYearMonthDay {
144 | relation = NearTermDateRelation.OutOfRange
145 | } else if isDateEqualToYearMonthDay {
146 | relation = NearTermDateRelation.Today
147 | } else if isDateEqualToYearMonthDayRelativeToTomorrow {
148 | let isRelativeDateDuringSameWeek = isDate(relativeToToday, duringSameWeekAsDate: date)
149 |
150 | if isRelativeDateDuringSameWeek {
151 | relation = NearTermDateRelation.Tomorrow
152 | } else {
153 | relation = NearTermDateRelation.NextWeek
154 | }
155 | } else if isDateDuringSameWeekAsDate {
156 | relation = NearTermDateRelation.LaterThisWeek
157 | } else if isDateDuringSameWeekAfterDate {
158 | relation = NearTermDateRelation.NextWeek
159 | }
160 |
161 | return relation
162 | }
163 | }
--------------------------------------------------------------------------------
/VIPER-SWIFT/Base.lproj/Main.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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/VIPER-SWIFT.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 261FA1B919414A720029F589 /* AppDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA17219414A720029F589 /* AppDependencies.swift */; };
11 | 261FA1BC19414A720029F589 /* NSCalendar+CalendarAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA17919414A720029F589 /* NSCalendar+CalendarAdditions.swift */; };
12 | 261FA1BE19414A720029F589 /* Clock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA17D19414A720029F589 /* Clock.swift */; };
13 | 261FA1BF19414A720029F589 /* DeviceClock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA17E19414A720029F589 /* DeviceClock.swift */; };
14 | 261FA1C019414A720029F589 /* NearTermDateRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18019414A720029F589 /* NearTermDateRelation.swift */; };
15 | 261FA1C119414A720029F589 /* TodoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18119414A720029F589 /* TodoItem.swift */; };
16 | 261FA1C219414A720029F589 /* CoreDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18319414A720029F589 /* CoreDataStore.swift */; };
17 | 261FA1C419414A720029F589 /* TODO.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18719414A720029F589 /* TODO.xcdatamodeld */; };
18 | 261FA1C519414A720029F589 /* RootWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18A19414A720029F589 /* RootWireframe.swift */; };
19 | 261FA1C619414A720029F589 /* AddInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18F19414A720029F589 /* AddInteractor.swift */; };
20 | 261FA1C719414A720029F589 /* AddDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19119414A720029F589 /* AddDataManager.swift */; };
21 | 261FA1C819414A720029F589 /* AddModuleDelegateInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19419414A720029F589 /* AddModuleDelegateInterface.swift */; };
22 | 261FA1C919414A720029F589 /* AddModuleInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19519414A720029F589 /* AddModuleInterface.swift */; };
23 | 261FA1CA19414A720029F589 /* AddPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19819414A720029F589 /* AddPresenter.swift */; };
24 | 261FA1CB19414A720029F589 /* AddDismissalTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19A19414A720029F589 /* AddDismissalTransition.swift */; };
25 | 261FA1CC19414A720029F589 /* AddPresentationTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19B19414A720029F589 /* AddPresentationTransition.swift */; };
26 | 261FA1CD19414A720029F589 /* AddViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19D19414A720029F589 /* AddViewController.swift */; };
27 | 261FA1CE19414A720029F589 /* AddViewInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA19E19414A720029F589 /* AddViewInterface.swift */; };
28 | 261FA1CF19414A720029F589 /* AddWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A019414A720029F589 /* AddWireframe.swift */; };
29 | 261FA1D019414A720029F589 /* ListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A419414A720029F589 /* ListInteractor.swift */; };
30 | 261FA1D119414A720029F589 /* ListInteractorIO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A519414A720029F589 /* ListInteractorIO.swift */; };
31 | 261FA1D219414A720029F589 /* UpcomingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A619414A720029F589 /* UpcomingItem.swift */; };
32 | 261FA1D319414A720029F589 /* ListDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A819414A720029F589 /* ListDataManager.swift */; };
33 | 261FA1D419414A720029F589 /* ListModuleInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1AB19414A720029F589 /* ListModuleInterface.swift */; };
34 | 261FA1D519414A720029F589 /* ListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1AE19414A720029F589 /* ListPresenter.swift */; };
35 | 261FA1D619414A720029F589 /* UpcomingDisplayData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1AF19414A720029F589 /* UpcomingDisplayData.swift */; };
36 | 261FA1D719414A720029F589 /* UpcomingDisplayDataCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B019414A720029F589 /* UpcomingDisplayDataCollection.swift */; };
37 | 261FA1D819414A720029F589 /* UpcomingDisplayItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B119414A720029F589 /* UpcomingDisplayItem.swift */; };
38 | 261FA1D919414A720029F589 /* UpcomingDisplaySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B219414A720029F589 /* UpcomingDisplaySection.swift */; };
39 | 261FA1DA19414A720029F589 /* ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B419414A720029F589 /* ListViewController.swift */; };
40 | 261FA1DB19414A720029F589 /* ListViewInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B519414A720029F589 /* ListViewInterface.swift */; };
41 | 261FA1DC19414A720029F589 /* ListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B719414A720029F589 /* ListWireframe.swift */; };
42 | 261FA1E719414CBE0029F589 /* ManagedTodoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1E619414CBE0029F589 /* ManagedTodoItem.swift */; };
43 | 261FA1EC1942320E0029F589 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 261FA1EA1942320E0029F589 /* Main.storyboard */; };
44 | 261FA1EE194232180029F589 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 261FA1ED194232180029F589 /* Images.xcassets */; };
45 | 26A605EB1942A1EE0036C71F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A605EA1942A1EE0036C71F /* AppDelegate.swift */; };
46 | 26D96F9C19428C3600F117F5 /* CalendarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D96F9B19428C3600F117F5 /* CalendarTests.swift */; };
47 | 26D96F9D19428C7E00F117F5 /* NSCalendar+CalendarAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA17919414A720029F589 /* NSCalendar+CalendarAdditions.swift */; };
48 | 26D96F9E19428D8100F117F5 /* NearTermDateRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18019414A720029F589 /* NearTermDateRelation.swift */; };
49 | 26D96FA11942912A00F117F5 /* UpcomingDisplayData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1AF19414A720029F589 /* UpcomingDisplayData.swift */; };
50 | 26D96FA21942912A00F117F5 /* UpcomingDisplayDataCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B019414A720029F589 /* UpcomingDisplayDataCollection.swift */; };
51 | 26D96FA31942912A00F117F5 /* UpcomingDisplayItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B119414A720029F589 /* UpcomingDisplayItem.swift */; };
52 | 26D96FA41942912A00F117F5 /* UpcomingDisplaySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B219414A720029F589 /* UpcomingDisplaySection.swift */; };
53 | 26D96FA51942912A00F117F5 /* ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B419414A720029F589 /* ListViewController.swift */; };
54 | 26D96FA61942913600F117F5 /* ListViewInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1B519414A720029F589 /* ListViewInterface.swift */; };
55 | 26D96FA71942913B00F117F5 /* ListModuleInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1AB19414A720029F589 /* ListModuleInterface.swift */; };
56 | 26D96FA81942915D00F117F5 /* UpcomingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A619414A720029F589 /* UpcomingItem.swift */; };
57 | 26D96FA91942932A00F117F5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 261FA1EA1942320E0029F589 /* Main.storyboard */; };
58 | 26D96FAA1942932A00F117F5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 261FA1ED194232180029F589 /* Images.xcassets */; };
59 | 26D96FAC1942967900F117F5 /* RelativeDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D96FAB1942967900F117F5 /* RelativeDateTests.swift */; };
60 | 26D96FAE19429A9000F117F5 /* DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D96FAD19429A9000F117F5 /* DataTests.swift */; };
61 | 26D96FAF19429AD000F117F5 /* ManagedTodoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1E619414CBE0029F589 /* ManagedTodoItem.swift */; };
62 | 26D96FB019429AD000F117F5 /* CoreDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18319414A720029F589 /* CoreDataStore.swift */; };
63 | 26D96FB119429B1A00F117F5 /* TodoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA18119414A720029F589 /* TodoItem.swift */; };
64 | 26D96FB219429B1A00F117F5 /* ListDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261FA1A819414A720029F589 /* ListDataManager.swift */; };
65 | /* End PBXBuildFile section */
66 |
67 | /* Begin PBXContainerItemProxy section */
68 | 261FA1611941497E0029F589 /* PBXContainerItemProxy */ = {
69 | isa = PBXContainerItemProxy;
70 | containerPortal = 261FA1461941497E0029F589 /* Project object */;
71 | proxyType = 1;
72 | remoteGlobalIDString = 261FA14D1941497E0029F589;
73 | remoteInfo = "VIPER-SWIFT";
74 | };
75 | /* End PBXContainerItemProxy section */
76 |
77 | /* Begin PBXFileReference section */
78 | 261FA14E1941497E0029F589 /* VIPER-SWIFT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "VIPER-SWIFT.app"; sourceTree = BUILT_PRODUCTS_DIR; };
79 | 261FA1601941497E0029F589 /* VIPER-SWIFTTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "VIPER-SWIFTTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
80 | 261FA1651941497E0029F589 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
81 | 261FA17219414A720029F589 /* AppDependencies.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDependencies.swift; sourceTree = ""; };
82 | 261FA17919414A720029F589 /* NSCalendar+CalendarAdditions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSCalendar+CalendarAdditions.swift"; sourceTree = ""; };
83 | 261FA17D19414A720029F589 /* Clock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Clock.swift; sourceTree = ""; };
84 | 261FA17E19414A720029F589 /* DeviceClock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceClock.swift; sourceTree = ""; };
85 | 261FA18019414A720029F589 /* NearTermDateRelation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearTermDateRelation.swift; sourceTree = ""; };
86 | 261FA18119414A720029F589 /* TodoItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TodoItem.swift; sourceTree = ""; };
87 | 261FA18319414A720029F589 /* CoreDataStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataStore.swift; sourceTree = ""; };
88 | 261FA18819414A720029F589 /* TODO.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TODO.xcdatamodel; sourceTree = ""; };
89 | 261FA18A19414A720029F589 /* RootWireframe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootWireframe.swift; sourceTree = ""; };
90 | 261FA18F19414A720029F589 /* AddInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddInteractor.swift; sourceTree = ""; };
91 | 261FA19119414A720029F589 /* AddDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddDataManager.swift; sourceTree = ""; };
92 | 261FA19419414A720029F589 /* AddModuleDelegateInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddModuleDelegateInterface.swift; sourceTree = ""; };
93 | 261FA19519414A720029F589 /* AddModuleInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddModuleInterface.swift; sourceTree = ""; };
94 | 261FA19819414A720029F589 /* AddPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPresenter.swift; sourceTree = ""; };
95 | 261FA19A19414A720029F589 /* AddDismissalTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddDismissalTransition.swift; sourceTree = ""; };
96 | 261FA19B19414A720029F589 /* AddPresentationTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPresentationTransition.swift; sourceTree = ""; };
97 | 261FA19D19414A720029F589 /* AddViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddViewController.swift; sourceTree = ""; };
98 | 261FA19E19414A720029F589 /* AddViewInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddViewInterface.swift; sourceTree = ""; };
99 | 261FA1A019414A720029F589 /* AddWireframe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddWireframe.swift; sourceTree = ""; };
100 | 261FA1A419414A720029F589 /* ListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListInteractor.swift; sourceTree = ""; };
101 | 261FA1A519414A720029F589 /* ListInteractorIO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListInteractorIO.swift; sourceTree = ""; };
102 | 261FA1A619414A720029F589 /* UpcomingItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpcomingItem.swift; sourceTree = ""; };
103 | 261FA1A819414A720029F589 /* ListDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListDataManager.swift; sourceTree = ""; };
104 | 261FA1AB19414A720029F589 /* ListModuleInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListModuleInterface.swift; sourceTree = ""; };
105 | 261FA1AE19414A720029F589 /* ListPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListPresenter.swift; sourceTree = ""; };
106 | 261FA1AF19414A720029F589 /* UpcomingDisplayData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpcomingDisplayData.swift; sourceTree = ""; };
107 | 261FA1B019414A720029F589 /* UpcomingDisplayDataCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpcomingDisplayDataCollection.swift; sourceTree = ""; };
108 | 261FA1B119414A720029F589 /* UpcomingDisplayItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpcomingDisplayItem.swift; sourceTree = ""; };
109 | 261FA1B219414A720029F589 /* UpcomingDisplaySection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpcomingDisplaySection.swift; sourceTree = ""; };
110 | 261FA1B419414A720029F589 /* ListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListViewController.swift; sourceTree = ""; };
111 | 261FA1B519414A720029F589 /* ListViewInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListViewInterface.swift; sourceTree = ""; };
112 | 261FA1B719414A720029F589 /* ListWireframe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListWireframe.swift; sourceTree = ""; };
113 | 261FA1E619414CBE0029F589 /* ManagedTodoItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedTodoItem.swift; sourceTree = ""; };
114 | 261FA1E819414E600029F589 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
115 | 261FA1EB1942320E0029F589 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "VIPER-SWIFT/Base.lproj/Main.storyboard"; sourceTree = SOURCE_ROOT; };
116 | 261FA1ED194232180029F589 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "VIPER-SWIFT/Images.xcassets"; sourceTree = SOURCE_ROOT; };
117 | 26A605EA1942A1EE0036C71F /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
118 | 26D96F9B19428C3600F117F5 /* CalendarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarTests.swift; sourceTree = ""; };
119 | 26D96FAB1942967900F117F5 /* RelativeDateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativeDateTests.swift; sourceTree = ""; };
120 | 26D96FAD19429A9000F117F5 /* DataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataTests.swift; sourceTree = ""; };
121 | /* End PBXFileReference section */
122 |
123 | /* Begin PBXFrameworksBuildPhase section */
124 | 261FA14B1941497E0029F589 /* Frameworks */ = {
125 | isa = PBXFrameworksBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | 261FA15D1941497E0029F589 /* Frameworks */ = {
132 | isa = PBXFrameworksBuildPhase;
133 | buildActionMask = 2147483647;
134 | files = (
135 | );
136 | runOnlyForDeploymentPostprocessing = 0;
137 | };
138 | /* End PBXFrameworksBuildPhase section */
139 |
140 | /* Begin PBXGroup section */
141 | 261FA1451941497E0029F589 = {
142 | isa = PBXGroup;
143 | children = (
144 | 261FA1501941497E0029F589 /* VIPER-SWIFT */,
145 | 261FA1631941497E0029F589 /* VIPER-SWIFTTests */,
146 | 261FA14F1941497E0029F589 /* Products */,
147 | );
148 | sourceTree = "";
149 | };
150 | 261FA14F1941497E0029F589 /* Products */ = {
151 | isa = PBXGroup;
152 | children = (
153 | 261FA14E1941497E0029F589 /* VIPER-SWIFT.app */,
154 | 261FA1601941497E0029F589 /* VIPER-SWIFTTests.xctest */,
155 | );
156 | name = Products;
157 | sourceTree = "";
158 | };
159 | 261FA1501941497E0029F589 /* VIPER-SWIFT */ = {
160 | isa = PBXGroup;
161 | children = (
162 | 261FA17019414A720029F589 /* Classes */,
163 | 261FA1DD19414AC20029F589 /* Resources */,
164 | 261FA1DE19414AC60029F589 /* Supporting Files */,
165 | );
166 | path = "VIPER-SWIFT";
167 | sourceTree = "";
168 | };
169 | 261FA1631941497E0029F589 /* VIPER-SWIFTTests */ = {
170 | isa = PBXGroup;
171 | children = (
172 | 26D96F9B19428C3600F117F5 /* CalendarTests.swift */,
173 | 26D96FAD19429A9000F117F5 /* DataTests.swift */,
174 | 26D96FAB1942967900F117F5 /* RelativeDateTests.swift */,
175 | 261FA1641941497E0029F589 /* Supporting Files */,
176 | );
177 | path = "VIPER-SWIFTTests";
178 | sourceTree = "";
179 | };
180 | 261FA1641941497E0029F589 /* Supporting Files */ = {
181 | isa = PBXGroup;
182 | children = (
183 | 261FA1651941497E0029F589 /* Info.plist */,
184 | );
185 | name = "Supporting Files";
186 | sourceTree = "";
187 | };
188 | 261FA17019414A720029F589 /* Classes */ = {
189 | isa = PBXGroup;
190 | children = (
191 | 261FA17319414A720029F589 /* Common */,
192 | 261FA18B19414A720029F589 /* Modules */,
193 | 26A605EA1942A1EE0036C71F /* AppDelegate.swift */,
194 | 261FA17219414A720029F589 /* AppDependencies.swift */,
195 | );
196 | path = Classes;
197 | sourceTree = "";
198 | };
199 | 261FA17319414A720029F589 /* Common */ = {
200 | isa = PBXGroup;
201 | children = (
202 | 261FA17419414A720029F589 /* Categories */,
203 | 261FA17C19414A720029F589 /* Clock */,
204 | 261FA17F19414A720029F589 /* Model */,
205 | 261FA18219414A720029F589 /* Store */,
206 | 261FA18919414A720029F589 /* View */,
207 | );
208 | path = Common;
209 | sourceTree = "";
210 | };
211 | 261FA17419414A720029F589 /* Categories */ = {
212 | isa = PBXGroup;
213 | children = (
214 | 261FA17919414A720029F589 /* NSCalendar+CalendarAdditions.swift */,
215 | );
216 | path = Categories;
217 | sourceTree = "";
218 | };
219 | 261FA17C19414A720029F589 /* Clock */ = {
220 | isa = PBXGroup;
221 | children = (
222 | 261FA17D19414A720029F589 /* Clock.swift */,
223 | 261FA17E19414A720029F589 /* DeviceClock.swift */,
224 | );
225 | path = Clock;
226 | sourceTree = "";
227 | };
228 | 261FA17F19414A720029F589 /* Model */ = {
229 | isa = PBXGroup;
230 | children = (
231 | 261FA18019414A720029F589 /* NearTermDateRelation.swift */,
232 | 261FA18119414A720029F589 /* TodoItem.swift */,
233 | );
234 | path = Model;
235 | sourceTree = "";
236 | };
237 | 261FA18219414A720029F589 /* Store */ = {
238 | isa = PBXGroup;
239 | children = (
240 | 261FA18419414A720029F589 /* Entities */,
241 | 261FA18319414A720029F589 /* CoreDataStore.swift */,
242 | 261FA18719414A720029F589 /* TODO.xcdatamodeld */,
243 | );
244 | path = Store;
245 | sourceTree = "";
246 | };
247 | 261FA18419414A720029F589 /* Entities */ = {
248 | isa = PBXGroup;
249 | children = (
250 | 261FA1E619414CBE0029F589 /* ManagedTodoItem.swift */,
251 | );
252 | path = Entities;
253 | sourceTree = "";
254 | };
255 | 261FA18919414A720029F589 /* View */ = {
256 | isa = PBXGroup;
257 | children = (
258 | 261FA18A19414A720029F589 /* RootWireframe.swift */,
259 | );
260 | path = View;
261 | sourceTree = "";
262 | };
263 | 261FA18B19414A720029F589 /* Modules */ = {
264 | isa = PBXGroup;
265 | children = (
266 | 261FA18C19414A720029F589 /* Add */,
267 | 261FA1A119414A720029F589 /* List */,
268 | );
269 | path = Modules;
270 | sourceTree = "";
271 | };
272 | 261FA18C19414A720029F589 /* Add */ = {
273 | isa = PBXGroup;
274 | children = (
275 | 261FA18D19414A720029F589 /* Application Logic */,
276 | 261FA19319414A720029F589 /* Module Interface */,
277 | 261FA19619414A720029F589 /* User Interface */,
278 | );
279 | path = Add;
280 | sourceTree = "";
281 | };
282 | 261FA18D19414A720029F589 /* Application Logic */ = {
283 | isa = PBXGroup;
284 | children = (
285 | 261FA18E19414A720029F589 /* Interactor */,
286 | 261FA19019414A720029F589 /* Manager */,
287 | 261FA19219414A720029F589 /* Model */,
288 | );
289 | path = "Application Logic";
290 | sourceTree = "";
291 | };
292 | 261FA18E19414A720029F589 /* Interactor */ = {
293 | isa = PBXGroup;
294 | children = (
295 | 261FA18F19414A720029F589 /* AddInteractor.swift */,
296 | );
297 | path = Interactor;
298 | sourceTree = "";
299 | };
300 | 261FA19019414A720029F589 /* Manager */ = {
301 | isa = PBXGroup;
302 | children = (
303 | 261FA19119414A720029F589 /* AddDataManager.swift */,
304 | );
305 | path = Manager;
306 | sourceTree = "";
307 | };
308 | 261FA19219414A720029F589 /* Model */ = {
309 | isa = PBXGroup;
310 | children = (
311 | );
312 | path = Model;
313 | sourceTree = "";
314 | };
315 | 261FA19319414A720029F589 /* Module Interface */ = {
316 | isa = PBXGroup;
317 | children = (
318 | 261FA19419414A720029F589 /* AddModuleDelegateInterface.swift */,
319 | 261FA19519414A720029F589 /* AddModuleInterface.swift */,
320 | );
321 | path = "Module Interface";
322 | sourceTree = "";
323 | };
324 | 261FA19619414A720029F589 /* User Interface */ = {
325 | isa = PBXGroup;
326 | children = (
327 | 261FA19719414A720029F589 /* Presenter */,
328 | 261FA19919414A720029F589 /* Transition */,
329 | 261FA19C19414A720029F589 /* View */,
330 | 261FA19F19414A720029F589 /* Wireframe */,
331 | );
332 | path = "User Interface";
333 | sourceTree = "";
334 | };
335 | 261FA19719414A720029F589 /* Presenter */ = {
336 | isa = PBXGroup;
337 | children = (
338 | 261FA19819414A720029F589 /* AddPresenter.swift */,
339 | );
340 | path = Presenter;
341 | sourceTree = "";
342 | };
343 | 261FA19919414A720029F589 /* Transition */ = {
344 | isa = PBXGroup;
345 | children = (
346 | 261FA19A19414A720029F589 /* AddDismissalTransition.swift */,
347 | 261FA19B19414A720029F589 /* AddPresentationTransition.swift */,
348 | );
349 | path = Transition;
350 | sourceTree = "";
351 | };
352 | 261FA19C19414A720029F589 /* View */ = {
353 | isa = PBXGroup;
354 | children = (
355 | 261FA19D19414A720029F589 /* AddViewController.swift */,
356 | 261FA19E19414A720029F589 /* AddViewInterface.swift */,
357 | );
358 | path = View;
359 | sourceTree = "";
360 | };
361 | 261FA19F19414A720029F589 /* Wireframe */ = {
362 | isa = PBXGroup;
363 | children = (
364 | 261FA1A019414A720029F589 /* AddWireframe.swift */,
365 | );
366 | path = Wireframe;
367 | sourceTree = "";
368 | };
369 | 261FA1A119414A720029F589 /* List */ = {
370 | isa = PBXGroup;
371 | children = (
372 | 261FA1A219414A720029F589 /* Application Logic */,
373 | 261FA1AA19414A720029F589 /* Module Interface */,
374 | 261FA1AC19414A720029F589 /* User Interface */,
375 | );
376 | path = List;
377 | sourceTree = "";
378 | };
379 | 261FA1A219414A720029F589 /* Application Logic */ = {
380 | isa = PBXGroup;
381 | children = (
382 | 261FA1A319414A720029F589 /* Interactor */,
383 | 261FA1A719414A720029F589 /* Manager */,
384 | 261FA1A919414A720029F589 /* Model */,
385 | );
386 | path = "Application Logic";
387 | sourceTree = "";
388 | };
389 | 261FA1A319414A720029F589 /* Interactor */ = {
390 | isa = PBXGroup;
391 | children = (
392 | 261FA1A419414A720029F589 /* ListInteractor.swift */,
393 | 261FA1A519414A720029F589 /* ListInteractorIO.swift */,
394 | 261FA1A619414A720029F589 /* UpcomingItem.swift */,
395 | );
396 | path = Interactor;
397 | sourceTree = "";
398 | };
399 | 261FA1A719414A720029F589 /* Manager */ = {
400 | isa = PBXGroup;
401 | children = (
402 | 261FA1A819414A720029F589 /* ListDataManager.swift */,
403 | );
404 | path = Manager;
405 | sourceTree = "";
406 | };
407 | 261FA1A919414A720029F589 /* Model */ = {
408 | isa = PBXGroup;
409 | children = (
410 | );
411 | path = Model;
412 | sourceTree = "";
413 | };
414 | 261FA1AA19414A720029F589 /* Module Interface */ = {
415 | isa = PBXGroup;
416 | children = (
417 | 261FA1AB19414A720029F589 /* ListModuleInterface.swift */,
418 | );
419 | path = "Module Interface";
420 | sourceTree = "";
421 | };
422 | 261FA1AC19414A720029F589 /* User Interface */ = {
423 | isa = PBXGroup;
424 | children = (
425 | 261FA1AD19414A720029F589 /* Presenter */,
426 | 261FA1B319414A720029F589 /* View */,
427 | 261FA1B619414A720029F589 /* Wireframe */,
428 | );
429 | path = "User Interface";
430 | sourceTree = "";
431 | };
432 | 261FA1AD19414A720029F589 /* Presenter */ = {
433 | isa = PBXGroup;
434 | children = (
435 | 261FA1AE19414A720029F589 /* ListPresenter.swift */,
436 | 261FA1AF19414A720029F589 /* UpcomingDisplayData.swift */,
437 | 261FA1B019414A720029F589 /* UpcomingDisplayDataCollection.swift */,
438 | 261FA1B119414A720029F589 /* UpcomingDisplayItem.swift */,
439 | 261FA1B219414A720029F589 /* UpcomingDisplaySection.swift */,
440 | );
441 | path = Presenter;
442 | sourceTree = "";
443 | };
444 | 261FA1B319414A720029F589 /* View */ = {
445 | isa = PBXGroup;
446 | children = (
447 | 261FA1B419414A720029F589 /* ListViewController.swift */,
448 | 261FA1B519414A720029F589 /* ListViewInterface.swift */,
449 | );
450 | path = View;
451 | sourceTree = "";
452 | };
453 | 261FA1B619414A720029F589 /* Wireframe */ = {
454 | isa = PBXGroup;
455 | children = (
456 | 261FA1B719414A720029F589 /* ListWireframe.swift */,
457 | );
458 | path = Wireframe;
459 | sourceTree = "";
460 | };
461 | 261FA1DD19414AC20029F589 /* Resources */ = {
462 | isa = PBXGroup;
463 | children = (
464 | 261FA1EA1942320E0029F589 /* Main.storyboard */,
465 | 261FA1ED194232180029F589 /* Images.xcassets */,
466 | );
467 | name = Resources;
468 | path = "../../../../Documents/Repos/VIPER-TODO-SWIFT/viper-todo-swift/VIPER TODO/Resources";
469 | sourceTree = "";
470 | };
471 | 261FA1DE19414AC60029F589 /* Supporting Files */ = {
472 | isa = PBXGroup;
473 | children = (
474 | 261FA1E819414E600029F589 /* Info.plist */,
475 | );
476 | name = "Supporting Files";
477 | sourceTree = "";
478 | };
479 | /* End PBXGroup section */
480 |
481 | /* Begin PBXNativeTarget section */
482 | 261FA14D1941497E0029F589 /* VIPER-SWIFT */ = {
483 | isa = PBXNativeTarget;
484 | buildConfigurationList = 261FA16A1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFT" */;
485 | buildPhases = (
486 | 261FA14A1941497E0029F589 /* Sources */,
487 | 261FA14B1941497E0029F589 /* Frameworks */,
488 | 261FA14C1941497E0029F589 /* Resources */,
489 | );
490 | buildRules = (
491 | );
492 | dependencies = (
493 | );
494 | name = "VIPER-SWIFT";
495 | productName = "VIPER-SWIFT";
496 | productReference = 261FA14E1941497E0029F589 /* VIPER-SWIFT.app */;
497 | productType = "com.apple.product-type.application";
498 | };
499 | 261FA15F1941497E0029F589 /* VIPER-SWIFTTests */ = {
500 | isa = PBXNativeTarget;
501 | buildConfigurationList = 261FA16D1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFTTests" */;
502 | buildPhases = (
503 | 261FA15C1941497E0029F589 /* Sources */,
504 | 261FA15D1941497E0029F589 /* Frameworks */,
505 | 261FA15E1941497E0029F589 /* Resources */,
506 | );
507 | buildRules = (
508 | );
509 | dependencies = (
510 | 261FA1621941497E0029F589 /* PBXTargetDependency */,
511 | );
512 | name = "VIPER-SWIFTTests";
513 | productName = "VIPER-SWIFTTests";
514 | productReference = 261FA1601941497E0029F589 /* VIPER-SWIFTTests.xctest */;
515 | productType = "com.apple.product-type.bundle.unit-test";
516 | };
517 | /* End PBXNativeTarget section */
518 |
519 | /* Begin PBXProject section */
520 | 261FA1461941497E0029F589 /* Project object */ = {
521 | isa = PBXProject;
522 | attributes = {
523 | LastUpgradeCheck = 0600;
524 | ORGANIZATIONNAME = "Conrad Stoll";
525 | TargetAttributes = {
526 | 261FA14D1941497E0029F589 = {
527 | CreatedOnToolsVersion = 6.0;
528 | };
529 | 261FA15F1941497E0029F589 = {
530 | CreatedOnToolsVersion = 6.0;
531 | TestTargetID = 261FA14D1941497E0029F589;
532 | };
533 | };
534 | };
535 | buildConfigurationList = 261FA1491941497E0029F589 /* Build configuration list for PBXProject "VIPER-SWIFT" */;
536 | compatibilityVersion = "Xcode 3.2";
537 | developmentRegion = English;
538 | hasScannedForEncodings = 0;
539 | knownRegions = (
540 | en,
541 | Base,
542 | );
543 | mainGroup = 261FA1451941497E0029F589;
544 | productRefGroup = 261FA14F1941497E0029F589 /* Products */;
545 | projectDirPath = "";
546 | projectRoot = "";
547 | targets = (
548 | 261FA14D1941497E0029F589 /* VIPER-SWIFT */,
549 | 261FA15F1941497E0029F589 /* VIPER-SWIFTTests */,
550 | );
551 | };
552 | /* End PBXProject section */
553 |
554 | /* Begin PBXResourcesBuildPhase section */
555 | 261FA14C1941497E0029F589 /* Resources */ = {
556 | isa = PBXResourcesBuildPhase;
557 | buildActionMask = 2147483647;
558 | files = (
559 | 261FA1EE194232180029F589 /* Images.xcassets in Resources */,
560 | 261FA1EC1942320E0029F589 /* Main.storyboard in Resources */,
561 | );
562 | runOnlyForDeploymentPostprocessing = 0;
563 | };
564 | 261FA15E1941497E0029F589 /* Resources */ = {
565 | isa = PBXResourcesBuildPhase;
566 | buildActionMask = 2147483647;
567 | files = (
568 | 26D96FA91942932A00F117F5 /* Main.storyboard in Resources */,
569 | 26D96FAA1942932A00F117F5 /* Images.xcassets in Resources */,
570 | );
571 | runOnlyForDeploymentPostprocessing = 0;
572 | };
573 | /* End PBXResourcesBuildPhase section */
574 |
575 | /* Begin PBXSourcesBuildPhase section */
576 | 261FA14A1941497E0029F589 /* Sources */ = {
577 | isa = PBXSourcesBuildPhase;
578 | buildActionMask = 2147483647;
579 | files = (
580 | 261FA1C719414A720029F589 /* AddDataManager.swift in Sources */,
581 | 261FA1D119414A720029F589 /* ListInteractorIO.swift in Sources */,
582 | 261FA1D719414A720029F589 /* UpcomingDisplayDataCollection.swift in Sources */,
583 | 261FA1D219414A720029F589 /* UpcomingItem.swift in Sources */,
584 | 261FA1D519414A720029F589 /* ListPresenter.swift in Sources */,
585 | 261FA1D419414A720029F589 /* ListModuleInterface.swift in Sources */,
586 | 261FA1B919414A720029F589 /* AppDependencies.swift in Sources */,
587 | 261FA1D619414A720029F589 /* UpcomingDisplayData.swift in Sources */,
588 | 261FA1C619414A720029F589 /* AddInteractor.swift in Sources */,
589 | 261FA1D919414A720029F589 /* UpcomingDisplaySection.swift in Sources */,
590 | 261FA1C819414A720029F589 /* AddModuleDelegateInterface.swift in Sources */,
591 | 261FA1BF19414A720029F589 /* DeviceClock.swift in Sources */,
592 | 261FA1DA19414A720029F589 /* ListViewController.swift in Sources */,
593 | 261FA1BE19414A720029F589 /* Clock.swift in Sources */,
594 | 261FA1C519414A720029F589 /* RootWireframe.swift in Sources */,
595 | 261FA1C419414A720029F589 /* TODO.xcdatamodeld in Sources */,
596 | 261FA1CD19414A720029F589 /* AddViewController.swift in Sources */,
597 | 261FA1C119414A720029F589 /* TodoItem.swift in Sources */,
598 | 26A605EB1942A1EE0036C71F /* AppDelegate.swift in Sources */,
599 | 261FA1CB19414A720029F589 /* AddDismissalTransition.swift in Sources */,
600 | 261FA1C219414A720029F589 /* CoreDataStore.swift in Sources */,
601 | 261FA1CC19414A720029F589 /* AddPresentationTransition.swift in Sources */,
602 | 261FA1C919414A720029F589 /* AddModuleInterface.swift in Sources */,
603 | 261FA1D319414A720029F589 /* ListDataManager.swift in Sources */,
604 | 261FA1CA19414A720029F589 /* AddPresenter.swift in Sources */,
605 | 261FA1D019414A720029F589 /* ListInteractor.swift in Sources */,
606 | 261FA1C019414A720029F589 /* NearTermDateRelation.swift in Sources */,
607 | 261FA1E719414CBE0029F589 /* ManagedTodoItem.swift in Sources */,
608 | 261FA1D819414A720029F589 /* UpcomingDisplayItem.swift in Sources */,
609 | 261FA1BC19414A720029F589 /* NSCalendar+CalendarAdditions.swift in Sources */,
610 | 261FA1DB19414A720029F589 /* ListViewInterface.swift in Sources */,
611 | 261FA1DC19414A720029F589 /* ListWireframe.swift in Sources */,
612 | 261FA1CE19414A720029F589 /* AddViewInterface.swift in Sources */,
613 | 261FA1CF19414A720029F589 /* AddWireframe.swift in Sources */,
614 | );
615 | runOnlyForDeploymentPostprocessing = 0;
616 | };
617 | 261FA15C1941497E0029F589 /* Sources */ = {
618 | isa = PBXSourcesBuildPhase;
619 | buildActionMask = 2147483647;
620 | files = (
621 | 26D96FB219429B1A00F117F5 /* ListDataManager.swift in Sources */,
622 | 26D96FAF19429AD000F117F5 /* ManagedTodoItem.swift in Sources */,
623 | 26D96F9D19428C7E00F117F5 /* NSCalendar+CalendarAdditions.swift in Sources */,
624 | 26D96FAC1942967900F117F5 /* RelativeDateTests.swift in Sources */,
625 | 26D96FAE19429A9000F117F5 /* DataTests.swift in Sources */,
626 | 26D96FA71942913B00F117F5 /* ListModuleInterface.swift in Sources */,
627 | 26D96FA41942912A00F117F5 /* UpcomingDisplaySection.swift in Sources */,
628 | 26D96FA31942912A00F117F5 /* UpcomingDisplayItem.swift in Sources */,
629 | 26D96F9C19428C3600F117F5 /* CalendarTests.swift in Sources */,
630 | 26D96FA61942913600F117F5 /* ListViewInterface.swift in Sources */,
631 | 26D96FB019429AD000F117F5 /* CoreDataStore.swift in Sources */,
632 | 26D96FA11942912A00F117F5 /* UpcomingDisplayData.swift in Sources */,
633 | 26D96FA81942915D00F117F5 /* UpcomingItem.swift in Sources */,
634 | 26D96F9E19428D8100F117F5 /* NearTermDateRelation.swift in Sources */,
635 | 26D96FA51942912A00F117F5 /* ListViewController.swift in Sources */,
636 | 26D96FB119429B1A00F117F5 /* TodoItem.swift in Sources */,
637 | 26D96FA21942912A00F117F5 /* UpcomingDisplayDataCollection.swift in Sources */,
638 | );
639 | runOnlyForDeploymentPostprocessing = 0;
640 | };
641 | /* End PBXSourcesBuildPhase section */
642 |
643 | /* Begin PBXTargetDependency section */
644 | 261FA1621941497E0029F589 /* PBXTargetDependency */ = {
645 | isa = PBXTargetDependency;
646 | target = 261FA14D1941497E0029F589 /* VIPER-SWIFT */;
647 | targetProxy = 261FA1611941497E0029F589 /* PBXContainerItemProxy */;
648 | };
649 | /* End PBXTargetDependency section */
650 |
651 | /* Begin PBXVariantGroup section */
652 | 261FA1EA1942320E0029F589 /* Main.storyboard */ = {
653 | isa = PBXVariantGroup;
654 | children = (
655 | 261FA1EB1942320E0029F589 /* Base */,
656 | );
657 | name = Main.storyboard;
658 | sourceTree = "";
659 | };
660 | /* End PBXVariantGroup section */
661 |
662 | /* Begin XCBuildConfiguration section */
663 | 261FA1681941497E0029F589 /* Debug */ = {
664 | isa = XCBuildConfiguration;
665 | buildSettings = {
666 | ALWAYS_SEARCH_USER_PATHS = NO;
667 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
668 | CLANG_CXX_LIBRARY = "libc++";
669 | CLANG_ENABLE_MODULES = YES;
670 | CLANG_ENABLE_OBJC_ARC = YES;
671 | CLANG_WARN_BOOL_CONVERSION = YES;
672 | CLANG_WARN_CONSTANT_CONVERSION = YES;
673 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
674 | CLANG_WARN_EMPTY_BODY = YES;
675 | CLANG_WARN_ENUM_CONVERSION = YES;
676 | CLANG_WARN_INT_CONVERSION = YES;
677 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
678 | CLANG_WARN_UNREACHABLE_CODE = YES;
679 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
680 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
681 | COPY_PHASE_STRIP = NO;
682 | ENABLE_STRICT_OBJC_MSGSEND = YES;
683 | GCC_C_LANGUAGE_STANDARD = gnu99;
684 | GCC_DYNAMIC_NO_PIC = NO;
685 | GCC_OPTIMIZATION_LEVEL = 0;
686 | GCC_PREPROCESSOR_DEFINITIONS = (
687 | "DEBUG=1",
688 | "$(inherited)",
689 | );
690 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
691 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
692 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
693 | GCC_WARN_UNDECLARED_SELECTOR = YES;
694 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
695 | GCC_WARN_UNUSED_FUNCTION = YES;
696 | GCC_WARN_UNUSED_VARIABLE = YES;
697 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
698 | METAL_ENABLE_DEBUG_INFO = YES;
699 | ONLY_ACTIVE_ARCH = YES;
700 | SDKROOT = iphoneos;
701 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
702 | };
703 | name = Debug;
704 | };
705 | 261FA1691941497E0029F589 /* Release */ = {
706 | isa = XCBuildConfiguration;
707 | buildSettings = {
708 | ALWAYS_SEARCH_USER_PATHS = NO;
709 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
710 | CLANG_CXX_LIBRARY = "libc++";
711 | CLANG_ENABLE_MODULES = YES;
712 | CLANG_ENABLE_OBJC_ARC = YES;
713 | CLANG_WARN_BOOL_CONVERSION = YES;
714 | CLANG_WARN_CONSTANT_CONVERSION = YES;
715 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
716 | CLANG_WARN_EMPTY_BODY = YES;
717 | CLANG_WARN_ENUM_CONVERSION = YES;
718 | CLANG_WARN_INT_CONVERSION = YES;
719 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
720 | CLANG_WARN_UNREACHABLE_CODE = YES;
721 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
722 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
723 | COPY_PHASE_STRIP = YES;
724 | ENABLE_NS_ASSERTIONS = NO;
725 | ENABLE_STRICT_OBJC_MSGSEND = YES;
726 | GCC_C_LANGUAGE_STANDARD = gnu99;
727 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
728 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
729 | GCC_WARN_UNDECLARED_SELECTOR = YES;
730 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
731 | GCC_WARN_UNUSED_FUNCTION = YES;
732 | GCC_WARN_UNUSED_VARIABLE = YES;
733 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
734 | METAL_ENABLE_DEBUG_INFO = NO;
735 | SDKROOT = iphoneos;
736 | VALIDATE_PRODUCT = YES;
737 | };
738 | name = Release;
739 | };
740 | 261FA16B1941497E0029F589 /* Debug */ = {
741 | isa = XCBuildConfiguration;
742 | buildSettings = {
743 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
744 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
745 | INFOPLIST_FILE = "VIPER-SWIFT/Info.plist";
746 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
747 | PRODUCT_NAME = "$(TARGET_NAME)";
748 | };
749 | name = Debug;
750 | };
751 | 261FA16C1941497E0029F589 /* Release */ = {
752 | isa = XCBuildConfiguration;
753 | buildSettings = {
754 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
755 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
756 | INFOPLIST_FILE = "VIPER-SWIFT/Info.plist";
757 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
758 | PRODUCT_NAME = "$(TARGET_NAME)";
759 | };
760 | name = Release;
761 | };
762 | 261FA16E1941497E0029F589 /* Debug */ = {
763 | isa = XCBuildConfiguration;
764 | buildSettings = {
765 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/VIPER-SWIFT.app/VIPER-SWIFT";
766 | FRAMEWORK_SEARCH_PATHS = (
767 | "$(SDKROOT)/Developer/Library/Frameworks",
768 | "$(inherited)",
769 | );
770 | GCC_PREPROCESSOR_DEFINITIONS = (
771 | "DEBUG=1",
772 | "$(inherited)",
773 | );
774 | INFOPLIST_FILE = "VIPER-SWIFTTests/Info.plist";
775 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
776 | METAL_ENABLE_DEBUG_INFO = YES;
777 | PRODUCT_NAME = "$(TARGET_NAME)";
778 | TEST_HOST = "$(BUNDLE_LOADER)";
779 | };
780 | name = Debug;
781 | };
782 | 261FA16F1941497E0029F589 /* Release */ = {
783 | isa = XCBuildConfiguration;
784 | buildSettings = {
785 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/VIPER-SWIFT.app/VIPER-SWIFT";
786 | FRAMEWORK_SEARCH_PATHS = (
787 | "$(SDKROOT)/Developer/Library/Frameworks",
788 | "$(inherited)",
789 | );
790 | INFOPLIST_FILE = "VIPER-SWIFTTests/Info.plist";
791 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
792 | METAL_ENABLE_DEBUG_INFO = NO;
793 | PRODUCT_NAME = "$(TARGET_NAME)";
794 | TEST_HOST = "$(BUNDLE_LOADER)";
795 | };
796 | name = Release;
797 | };
798 | /* End XCBuildConfiguration section */
799 |
800 | /* Begin XCConfigurationList section */
801 | 261FA1491941497E0029F589 /* Build configuration list for PBXProject "VIPER-SWIFT" */ = {
802 | isa = XCConfigurationList;
803 | buildConfigurations = (
804 | 261FA1681941497E0029F589 /* Debug */,
805 | 261FA1691941497E0029F589 /* Release */,
806 | );
807 | defaultConfigurationIsVisible = 0;
808 | defaultConfigurationName = Release;
809 | };
810 | 261FA16A1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFT" */ = {
811 | isa = XCConfigurationList;
812 | buildConfigurations = (
813 | 261FA16B1941497E0029F589 /* Debug */,
814 | 261FA16C1941497E0029F589 /* Release */,
815 | );
816 | defaultConfigurationIsVisible = 0;
817 | defaultConfigurationName = Release;
818 | };
819 | 261FA16D1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFTTests" */ = {
820 | isa = XCConfigurationList;
821 | buildConfigurations = (
822 | 261FA16E1941497E0029F589 /* Debug */,
823 | 261FA16F1941497E0029F589 /* Release */,
824 | );
825 | defaultConfigurationIsVisible = 0;
826 | defaultConfigurationName = Release;
827 | };
828 | /* End XCConfigurationList section */
829 |
830 | /* Begin XCVersionGroup section */
831 | 261FA18719414A720029F589 /* TODO.xcdatamodeld */ = {
832 | isa = XCVersionGroup;
833 | children = (
834 | 261FA18819414A720029F589 /* TODO.xcdatamodel */,
835 | );
836 | currentVersion = 261FA18819414A720029F589 /* TODO.xcdatamodel */;
837 | path = TODO.xcdatamodeld;
838 | sourceTree = "";
839 | versionGroupType = wrapper.xcdatamodel;
840 | };
841 | /* End XCVersionGroup section */
842 | };
843 | rootObject = 261FA1461941497E0029F589 /* Project object */;
844 | }
845 |
--------------------------------------------------------------------------------