├── 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
│ ├── circle.imageset
│ │ ├── circle.png
│ │ ├── circle@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
│ ├── 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
│ │ ├── Model
│ │ │ ├── TodoItem.swift
│ │ │ └── NearTermDateRelation.swift
│ │ ├── Store
│ │ │ ├── Entities
│ │ │ │ └── ManagedTodoItem.swift
│ │ │ ├── TODO.xcdatamodeld
│ │ │ │ └── TODO.xcdatamodel
│ │ │ │ │ └── contents
│ │ │ └── CoreDataStore.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
├── Info.plist
├── DataTests.swift
├── 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/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/line.imageset/line.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/check.imageset/check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/check.imageset/check.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/circle.imageset/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/circle.imageset/circle.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/empty.imageset/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/empty.imageset/empty.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/line.imageset/line@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/line.imageset/line@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/month.imageset/month.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/month.imageset/month.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/notes.imageset/notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/notes.imageset/notes.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/paper.imageset/paper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/paper.imageset/paper.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/alarm.imageset/alarm@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/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/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/check.imageset/check@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/empty.imageset/empty@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/empty.imageset/empty@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/month.imageset/month@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/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/mutualmobile/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/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/paper.imageset/paper@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/circle.imageset/circle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/VIPER-SWIFT/HEAD/VIPER-SWIFT/Images.xcassets/circle.imageset/circle@2x.png
--------------------------------------------------------------------------------
/VIPER-SWIFT/Images.xcassets/calendar.imageset/calendar@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mutualmobile/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/mutualmobile/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/mutualmobile/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/mutualmobile/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() -> Date
13 | }
14 |
--------------------------------------------------------------------------------
/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 : Date
13 | let name : String
14 | }
15 |
--------------------------------------------------------------------------------
/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() -> Date {
13 | return Date()
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 : String
14 | @NSManaged var date : Date
15 | }
16 |
--------------------------------------------------------------------------------
/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: String, dueDate: Date)
14 | }
15 |
--------------------------------------------------------------------------------
/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 | }
18 |
--------------------------------------------------------------------------------
/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: String)
13 | func setEntryDueDate(_ date: Date)
14 | func setMinimumDueDate(_ date: Date)
15 | }
16 |
--------------------------------------------------------------------------------
/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: String, dueDate: Date) {
15 | let newEntry = TodoItem(dueDate: dueDate, name: name)
16 | addDataManager?.addNewEntry(newEntry)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/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 {
12 | let sections : [UpcomingDisplaySection]
13 | }
14 |
15 | extension UpcomingDisplayData : Equatable {
16 | static func == (leftSide: UpcomingDisplayData, rightSide: UpcomingDisplayData) -> Bool {
17 | return rightSide.sections == leftSide.sections
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/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()
16 | newEntry.name = entry.name
17 | newEntry.date = entry.dueDate;
18 |
19 | dataStore.save()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/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 {
13 | let name : String
14 | let imageName : String
15 | var items : [UpcomingDisplayItem] = []
16 | }
17 |
18 | extension UpcomingDisplaySection : Equatable {
19 | static func == (leftSide: UpcomingDisplaySection, rightSide: UpcomingDisplaySection) -> Bool {
20 | return rightSide.items == leftSide.items
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/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: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | appDependencies.installRootViewControllerIntoWindow(window!)
19 |
20 | return true
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/VIPER-SWIFT/Classes/Common/Store/TODO.xcdatamodeld/TODO.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/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 | }
23 |
--------------------------------------------------------------------------------
/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 {
12 | let title : String
13 | let dueDate : String
14 | }
15 |
16 | extension UpcomingDisplayItem : Equatable {
17 | static func == (leftSide: UpcomingDisplayItem, rightSide: UpcomingDisplayItem) -> Bool {
18 | return rightSide.title == leftSide.title && rightSide.dueDate == rightSide.dueDate
19 | }
20 | }
21 |
22 | extension UpcomingDisplayItem: CustomStringConvertible {
23 | var description : String {
24 | return "\(title) -- \(dueDate)"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/VIPER-SWIFTTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/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.measure() {
23 | let startDate = Date()
24 | let endDate = Date(timeIntervalSinceReferenceDate: 0)
25 | self.dataManager.todoItemsBetweenStartDate(startDate, endDate: endDate, completion: { entries in
26 |
27 | })
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/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 configureUserInterfaceForPresentation(_ addViewUserInterface: AddViewInterface) {
17 | addViewUserInterface.setMinimumDueDate(Date())
18 | }
19 |
20 | // MARK: AddModuleInterface
21 |
22 | func cancelAddAction() {
23 | addWireframe?.dismissAddInterface()
24 | addModuleDelegate?.addModuleDidCancelAddAction()
25 | }
26 |
27 | func saveAddActionWithName(_ name: String, dueDate: Date) {
28 | addInteractor?.saveNewEntryWithName(name, dueDate: dueDate);
29 | addWireframe?.dismissAddInterface()
30 | addModuleDelegate?.addModuleDidSaveAddAction()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/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 : Date
14 | let dateRelation : NearTermDateRelation
15 |
16 | init(title: String, dueDate: Date = Date(), dateRelation: NearTermDateRelation = NearTermDateRelation.outOfRange) {
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 | }
41 |
--------------------------------------------------------------------------------
/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 | $(PRODUCT_BUNDLE_IDENTIFIER)
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: Date, endDate: Date, completion: (([TodoItem]) -> Void)!) {
16 | let calendar = Calendar.autoupdatingCurrent
17 | let beginning = calendar.dateForBeginningOfDay(startDate)
18 | let end = calendar.dateForEndOfDay(endDate)
19 |
20 | let predicate = NSPredicate(format: "(date >= %@) AND (date <= %@)", beginning as CVarArg, end as CVarArg)
21 | let sortDescriptors: [NSSortDescriptor] = []
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 | let todoItems : [TodoItem] = entries.map { entry in
33 | TodoItem(dueDate: entry.date, name: entry.name as String)
34 | }
35 |
36 | return todoItems
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/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(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
14 | return 0.72
15 | }
16 |
17 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
18 | let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! AddViewController
19 |
20 | let finalCenter = CGPoint(x: 160.0, y: (fromVC.view.bounds.size.height / 2) - 1000.0)
21 |
22 | let options = UIViewAnimationOptions.curveEaseIn
23 |
24 | UIView.animate(withDuration: self.transitionDuration(using: 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 | }
41 |
--------------------------------------------------------------------------------
/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.instantiateViewController(withIdentifier: ListViewControllerIdentifier) as! ListViewController
35 | return viewController
36 | }
37 |
38 | func mainStoryboard() -> UIStoryboard {
39 | let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
40 | return storyboard
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/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 | // MARK: ListInteractorInput
23 |
24 | func findUpcomingItems() {
25 | let today = clock.today()
26 | let endOfNextWeek = Calendar.current.dateForEndOfFollowingWeekWithDate(today)
27 |
28 | dataManager.todoItemsBetweenStartDate(today,
29 | endDate: endOfNextWeek,
30 | completion: { todoItems in
31 | let upcomingItems = self.upcomingItemsFromToDoItems(todoItems)
32 | self.output?.foundUpcomingItems(upcomingItems)
33 | })
34 | }
35 |
36 | func upcomingItemsFromToDoItems(_ todoItems: [TodoItem]) -> [UpcomingItem] {
37 | let calendar = Calendar.autoupdatingCurrent
38 |
39 | let upcomingItems: [UpcomingItem] = todoItems.map() { todoItem in
40 | let dateRelation = calendar.nearTermRelationForDate(todoItem.dueDate, relativeToToday: clock.today())
41 | return UpcomingItem(title: todoItem.name, dueDate: todoItem.dueDate, dateRelation: dateRelation)
42 | }
43 | return upcomingItems
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/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 | // MARK: ListInteractorOutput
18 |
19 | func foundUpcomingItems(_ upcomingItems: [UpcomingItem]) {
20 | if upcomingItems.count == 0 {
21 | userInterface?.showNoContentMessage()
22 | } else {
23 | updateUserInterfaceWithUpcomingItems(upcomingItems)
24 | }
25 | }
26 |
27 | func updateUserInterfaceWithUpcomingItems(_ upcomingItems: [UpcomingItem]) {
28 | let upcomingDisplayData = upcomingDisplayDataWithItems(upcomingItems)
29 | userInterface?.showUpcomingDisplayData(upcomingDisplayData)
30 | }
31 |
32 | func upcomingDisplayDataWithItems(_ upcomingItems: [UpcomingItem]) -> UpcomingDisplayData {
33 | let collection = UpcomingDisplayDataCollection()
34 | collection.addUpcomingItems(upcomingItems)
35 | return collection.collectedDisplayData()
36 | }
37 |
38 | // MARK: ListModuleInterface
39 |
40 | func addNewEntry() {
41 | listWireframe?.presentAddInterface()
42 | }
43 |
44 | func updateView() {
45 | listInteractor?.findUpcomingItems()
46 | }
47 |
48 | // MARK: AddModuleDelegate
49 |
50 | func addModuleDidCancelAddAction() {
51 | // No action necessary
52 | }
53 |
54 | func addModuleDidSaveAddAction() {
55 | updateView()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/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 | }
59 |
--------------------------------------------------------------------------------
/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.present(newViewController, animated: true, completion: nil)
28 |
29 | presentedViewController = newViewController
30 | }
31 |
32 | func dismissAddInterface() {
33 | presentedViewController?.dismiss(animated: true, completion: nil)
34 | }
35 |
36 | func addViewController() -> AddViewController {
37 | let storyboard = mainStoryboard()
38 | let addViewController: AddViewController = storyboard.instantiateViewController(withIdentifier: AddViewControllerIdentifier) as! AddViewController
39 | return addViewController
40 | }
41 |
42 | func mainStoryboard() -> UIStoryboard {
43 | let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
44 | return storyboard
45 | }
46 |
47 | // MARK: UIViewControllerTransitioningDelegate
48 |
49 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
50 | return AddDismissalTransition()
51 | }
52 |
53 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
54 | return AddPresentationTransition()
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/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(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
14 | return 0.72
15 | }
16 |
17 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
18 | let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
19 | let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! AddViewController
20 |
21 | toVC.transitioningBackgroundView.backgroundColor = UIColor.darkGray
22 | toVC.transitioningBackgroundView.alpha = 0.0
23 | toVC.transitioningBackgroundView.frame = UIScreen.main.bounds
24 |
25 | let containerView = transitionContext.containerView
26 |
27 | containerView.addSubview(toVC.transitioningBackgroundView)
28 | containerView.addSubview(toVC.view)
29 |
30 | let toViewFrame = CGRect(x: 0, y: 0, width: 260, height: 300)
31 | toVC.view.frame = toViewFrame
32 |
33 | let finalCenter = CGPoint(x: fromVC.view.bounds.size.width / 2, y: 20 + toViewFrame.size.height / 2)
34 | toVC.view.center = CGPoint(x: finalCenter.x, y: finalCenter.y - 1000)
35 |
36 | let options = UIViewAnimationOptions.curveEaseIn
37 |
38 | UIView.animate(withDuration: self.transitionDuration(using: transitionContext),
39 | delay: 0.0,
40 | usingSpringWithDamping: 0.64,
41 | initialSpringVelocity: 0.22,
42 | options: options,
43 | animations: {
44 | toVC.view.center = finalCenter
45 | toVC.transitioningBackgroundView.alpha = 0.7
46 | },
47 | completion: { finished in
48 | toVC.view.center = finalCenter
49 | transitionContext.completeTransition(true)
50 | }
51 | )
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/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 : Date = Date()
19 | var transitioningBackgroundView : UIView = UIView()
20 |
21 | @IBAction func save(_ sender: AnyObject) {
22 | if let text = nameTextField.text {
23 | eventHandler?.saveAddActionWithName(text, dueDate: datePicker.date)
24 | }
25 | }
26 |
27 | @IBAction func cancel(_ sender: AnyObject) {
28 | nameTextField.resignFirstResponder()
29 | eventHandler?.cancelAddAction()
30 | }
31 |
32 | override func viewDidAppear(_ animated: Bool) {
33 | super.viewDidAppear(animated)
34 |
35 | let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(AddViewController.dismissFunc))
36 | transitioningBackgroundView.isUserInteractionEnabled = true
37 | transitioningBackgroundView.addGestureRecognizer(gestureRecognizer)
38 |
39 | nameTextField.becomeFirstResponder()
40 |
41 | if let realDatePicker = datePicker {
42 | realDatePicker.minimumDate = minimumDate
43 | }
44 | }
45 |
46 | override func viewWillDisappear(_ animated: Bool) {
47 | super.viewWillDisappear(animated)
48 |
49 | nameTextField.resignFirstResponder()
50 | }
51 |
52 | @objc func dismissFunc() {
53 | eventHandler?.cancelAddAction()
54 | }
55 |
56 | // MARK: AddViewInterface
57 |
58 | func setEntryName(_ name: String) {
59 | nameTextField.text = name
60 | }
61 |
62 | func setEntryDueDate(_ date: Date) {
63 | if let realDatePicker = datePicker {
64 | realDatePicker.minimumDate = date
65 | }
66 | }
67 |
68 | func setMinimumDueDate(_ date: Date) {
69 | minimumDate = date
70 |
71 | if let realDatePicker = datePicker {
72 | realDatePicker.minimumDate = date
73 | }
74 | }
75 |
76 | // MARK: UITextFieldDelegate
77 |
78 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
79 | textField.resignFirstResponder()
80 |
81 | return true
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/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 | class CoreDataStore : NSObject {
13 | var persistentStoreCoordinator : NSPersistentStoreCoordinator!
14 | var managedObjectModel : NSManagedObjectModel!
15 | var managedObjectContext : NSManagedObjectContext!
16 |
17 | override init() {
18 | managedObjectModel = NSManagedObjectModel.mergedModel(from: nil)
19 |
20 | persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
21 |
22 | let domains = FileManager.SearchPathDomainMask.userDomainMask
23 | let directory = FileManager.SearchPathDirectory.documentDirectory
24 |
25 | let applicationDocumentsDirectory = FileManager.default.urls(for: directory, in: domains).first!
26 | let options = [NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true]
27 |
28 | let storeURL = applicationDocumentsDirectory.appendingPathComponent("VIPER-SWIFT.sqlite")
29 |
30 | try! persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: "", at: storeURL, options: options)
31 |
32 | managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
33 | managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
34 | managedObjectContext.undoManager = nil
35 |
36 | super.init()
37 | }
38 |
39 | func fetchEntriesWithPredicate(_ predicate: NSPredicate, sortDescriptors: [NSSortDescriptor], completionBlock: (([ManagedTodoItem]) -> Void)!) {
40 | let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "TodoItem")
41 | fetchRequest.predicate = predicate
42 | fetchRequest.sortDescriptors = sortDescriptors
43 |
44 | managedObjectContext.perform {
45 | let queryResults = try? self.managedObjectContext.fetch(fetchRequest)
46 | let managedResults = queryResults! as! [ManagedTodoItem]
47 | completionBlock(managedResults)
48 | }
49 | }
50 |
51 | func newTodoItem() -> ManagedTodoItem {
52 | let newEntry = NSEntityDescription.insertNewObject(forEntityName: "TodoItem", into: managedObjectContext) as! ManagedTodoItem
53 |
54 | return newEntry
55 | }
56 |
57 | func save() {
58 | do {
59 | try managedObjectContext.save()
60 | } catch _ {
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/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(ListViewController.didTapAddButton))
38 |
39 | navigationItem.rightBarButtonItem = addItem
40 | }
41 |
42 | @objc func didTapAddButton () {
43 | eventHandler?.addNewEntry()
44 | }
45 |
46 | // MARK: ListViewInterface
47 |
48 | func showNoContentMessage() {
49 | view = noContentView
50 | }
51 |
52 | func showUpcomingDisplayData(_ data: UpcomingDisplayData) {
53 | view = strongTableView
54 |
55 | dataProperty = data
56 | reloadEntries()
57 | }
58 |
59 | func reloadEntries() {
60 | tableView.reloadData()
61 | }
62 |
63 | // MARK: UITableViewDataSource
64 |
65 | override func numberOfSections(in tableView: UITableView) -> Int {
66 | return dataProperty?.sections.count ?? 0
67 | }
68 |
69 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
70 | let upcomingSection = dataProperty?.sections[section]
71 | return upcomingSection!.items.count
72 | }
73 |
74 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
75 | let upcomingSection = dataProperty?.sections[section]
76 | return upcomingSection!.name
77 | }
78 |
79 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
80 | let upcomingSection = dataProperty?.sections[(indexPath as NSIndexPath).section]
81 | let upcomingItem = upcomingSection!.items[(indexPath as NSIndexPath).row]
82 |
83 | let cell = tableView.dequeueReusableCell(withIdentifier: ListEntryCellIdentifier, for: indexPath) as UITableViewCell
84 |
85 | cell.textLabel?.text = upcomingItem.title;
86 | cell.detailTextLabel?.text = upcomingItem.dueDate;
87 | cell.imageView?.image = UIImage(named: upcomingSection!.imageName)
88 | cell.selectionStyle = UITableViewCellSelectionStyle.none;
89 |
90 | return cell
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/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: Calendar!
13 |
14 | override func setUp() {
15 | super.setUp()
16 |
17 | calendar = Calendar.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: Calendar!
13 |
14 | override func setUp() {
15 | super.setUp()
16 |
17 | calendar = Calendar.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 = DateFormatter()
13 | var sections : [NearTermDateRelation: [UpcomingDisplayItem]] = [:]
14 |
15 | init() {
16 | dayFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "EEEE", options: 0, locale: Locale.autoupdatingCurrent)
17 | }
18 |
19 | func addUpcomingItems(_ upcomingItems: [UpcomingItem]) {
20 | for upcomingItem in upcomingItems {
21 | addUpcomingItem(upcomingItem)
22 | }
23 | }
24 |
25 | func addUpcomingItem(_ upcomingItem: UpcomingItem) {
26 | let 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 as Date, dateRelation: upcomingItem.dateRelation)
43 | let displayItem = UpcomingDisplayItem(title: upcomingItem.title, dueDate: day)
44 | return displayItem
45 | }
46 |
47 | func formattedDay(_ date: Date, dateRelation: NearTermDateRelation) -> String {
48 | return dateRelation == NearTermDateRelation.today ? "" : dayFormatter.string(from: date)
49 | }
50 |
51 | func collectedDisplayData() -> UpcomingDisplayData {
52 | let collectedSections : [UpcomingDisplaySection] = sortedUpcomingDisplaySections()
53 | return UpcomingDisplayData(sections: collectedSections)
54 | }
55 |
56 | func displaySectionForDateRelation(_ dateRelation: NearTermDateRelation) -> UpcomingDisplaySection {
57 | let sectionTitle = sectionTitleForDateRelation(dateRelation)
58 | let imageName = sectionImageNameForDateRelation(dateRelation)
59 | let items: [UpcomingDisplayItem] = sections[dateRelation]!
60 |
61 | return UpcomingDisplaySection(name: sectionTitle, imageName: imageName, items: items)
62 | }
63 |
64 | func sortedUpcomingDisplaySections() -> [UpcomingDisplaySection] {
65 | let keys = sortedNearTermDateRelations()
66 | var displaySections : [UpcomingDisplaySection] = []
67 |
68 | for dateRelation in keys {
69 | let itemArray = sections[dateRelation]
70 |
71 | if (itemArray != nil) {
72 | let displaySection = displaySectionForDateRelation(dateRelation)
73 | displaySections.insert(displaySection, at: displaySections.endIndex)
74 | }
75 | }
76 |
77 | return displaySections
78 | }
79 |
80 | func sortedNearTermDateRelations() -> [NearTermDateRelation] {
81 | return [.today, .tomorrow, .laterThisWeek, .nextWeek]
82 | }
83 |
84 | func sectionTitleForDateRelation(_ dateRelation: NearTermDateRelation) -> String {
85 | switch dateRelation {
86 | case .today:
87 | return "Today"
88 | case .tomorrow:
89 | return "Tomorrow"
90 | case .laterThisWeek:
91 | return "Later This Week"
92 | case .nextWeek:
93 | return "Next Week"
94 | case .outOfRange:
95 | return "Unknown"
96 | }
97 | }
98 |
99 | func sectionImageNameForDateRelation(_ dateRelation: NearTermDateRelation) -> String {
100 | switch dateRelation {
101 | case .today:
102 | return "check"
103 | case .tomorrow:
104 | return "alarm"
105 | case .laterThisWeek:
106 | return "circle"
107 | case .nextWeek:
108 | return "calendar"
109 | case .outOfRange:
110 | return "paper"
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/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 Calendar {
12 | static func gregorianCalendar() -> Calendar {
13 | return Calendar(identifier: Calendar.Identifier.gregorian)
14 | }
15 |
16 | func dateWithYear(_ year: Int, month: Int, day: Int) -> Date {
17 | var components = DateComponents()
18 | components.year = year
19 | components.month = month
20 | components.day = day
21 | components.hour = 12
22 | return date(from: components)!
23 | }
24 |
25 | func dateForTomorrowRelativeToToday(_ today: Date) -> Date {
26 | var tomorrowComponents = DateComponents()
27 | tomorrowComponents.day = 1
28 | return date(byAdding: tomorrowComponents, to: today, wrappingComponents: false)!
29 |
30 | }
31 |
32 | func dateForEndOfWeekWithDate(_ date: Date) -> Date {
33 | let daysRemainingThisWeek = daysRemainingInWeekWithDate(date)
34 | var remainingDaysComponent = DateComponents()
35 | remainingDaysComponent.day = daysRemainingThisWeek
36 | return self.date(byAdding: remainingDaysComponent, to: date, wrappingComponents: false)!
37 | }
38 |
39 | func dateForBeginningOfDay(_ date: Date) -> Date {
40 | let newComponent = dateComponents(([.year, .month, .day]), from: date)
41 | let newDate = self.date(from: newComponent)
42 | return newDate!
43 | }
44 |
45 | func dateForEndOfDay(_ date: Date) -> Date {
46 | var components = DateComponents()
47 | components.day = 1
48 | let toDate = dateForBeginningOfDay(date)
49 | let nextDay = self.date(byAdding: components, to: toDate, wrappingComponents: false)!
50 | // let endDay = nextDay.dateByAddingTimeInterval(-1)
51 | return nextDay
52 | }
53 |
54 | func daysRemainingInWeekWithDate(_ date: Date) -> Int {
55 | let weekdayComponent = dateComponents([.weekday], from: date)
56 | let daysRange = CountableRange(range(of: .weekday, in: .weekOfYear, for: date)!)
57 | let daysPerWeek = daysRange.count
58 | let daysRemaining = daysPerWeek - weekdayComponent.weekday!
59 | return daysRemaining
60 | }
61 |
62 | func dateForEndOfFollowingWeekWithDate(_ date: Date) -> Date {
63 | let endOfWeek = dateForEndOfWeekWithDate(date)
64 | var nextWeekComponent = DateComponents()
65 | nextWeekComponent.weekOfYear = 1
66 | let followingWeekDate = self.date(byAdding: nextWeekComponent, to: endOfWeek, wrappingComponents: false)
67 | return followingWeekDate!
68 | }
69 |
70 | func isDate(_ date: Date, beforeYearMonthDay: Date) -> Bool {
71 | let comparison = compareYearMonthDay(date, toYearMonthDay: beforeYearMonthDay)
72 | let result = comparison == ComparisonResult.orderedAscending
73 | return result
74 | }
75 |
76 | func isDate(_ date: Date, equalToYearMonthDay: Date) -> Bool {
77 | let comparison = compareYearMonthDay(date, toYearMonthDay: equalToYearMonthDay)
78 | let result = comparison == ComparisonResult.orderedSame
79 | return result
80 | }
81 |
82 | func isDate(_ date: Date, duringSameWeekAsDate: Date) -> Bool {
83 | let dateC = dateComponents([.weekOfYear], from: date)
84 | let duringSameWeekComponents = dateComponents([.weekOfYear], from: duringSameWeekAsDate)
85 | let result = dateC.weekOfYear == duringSameWeekComponents.weekOfYear
86 | return result
87 | }
88 |
89 | func isDate(_ date: Date, duringWeekAfterDate: Date) -> Bool {
90 | let nextWeek = dateForEndOfFollowingWeekWithDate(duringWeekAfterDate)
91 | let dateC = dateComponents([.weekOfYear], from: date)
92 | let nextWeekComponents = dateComponents([.weekOfYear], from: nextWeek)
93 | let result = dateC.weekOfYear == nextWeekComponents.weekOfYear
94 | return result
95 | }
96 |
97 | func compareYearMonthDay(_ date: Date, toYearMonthDay: Date) -> ComparisonResult {
98 | let dateComponents = yearMonthDayComponentsFromDate(date)
99 | let yearMonthDayComponents = yearMonthDayComponentsFromDate(toYearMonthDay)
100 |
101 | var result = compareInteger(dateComponents.year!, right: yearMonthDayComponents.year!)
102 |
103 | if result == ComparisonResult.orderedSame {
104 | result = compareInteger(dateComponents.month!, right: yearMonthDayComponents.month!)
105 |
106 | if result == ComparisonResult.orderedSame {
107 | result = compareInteger(dateComponents.day!, right: yearMonthDayComponents.day!)
108 | }
109 | }
110 |
111 | return result
112 | }
113 |
114 | func yearMonthDayComponentsFromDate(_ date: Date) -> DateComponents {
115 | let newComponents = dateComponents(([.year, .month, .day]), from: date)
116 | return newComponents
117 | }
118 |
119 | func compareInteger(_ left: Int, right: Int) -> ComparisonResult {
120 | var result = ComparisonResult.orderedDescending
121 |
122 | if left == right {
123 | result = ComparisonResult.orderedSame
124 | } else if left < right {
125 | result = ComparisonResult.orderedAscending
126 | } else {
127 | result = ComparisonResult.orderedDescending
128 | }
129 |
130 | return result
131 | }
132 |
133 | func nearTermRelationForDate(_ date: Date, relativeToToday: Date) -> NearTermDateRelation {
134 | var relation = NearTermDateRelation.outOfRange
135 |
136 | let dateForTomorrow = dateForTomorrowRelativeToToday(relativeToToday)
137 |
138 | let isDateBeforeYearMonthDay = isDate(date, beforeYearMonthDay: relativeToToday)
139 | let isDateEqualToYearMonthDay = isDate(date, equalToYearMonthDay: relativeToToday)
140 | let isDateEqualToYearMonthDayRelativeToTomorrow = isDate(date, equalToYearMonthDay: dateForTomorrow)
141 | let isDateDuringSameWeekAsDate = isDate(date, duringSameWeekAsDate: relativeToToday)
142 | let isDateDuringSameWeekAfterDate = isDate(date, duringWeekAfterDate: relativeToToday)
143 |
144 | if isDateBeforeYearMonthDay {
145 | relation = NearTermDateRelation.outOfRange
146 | } else if isDateEqualToYearMonthDay {
147 | relation = NearTermDateRelation.today
148 | } else if isDateEqualToYearMonthDayRelativeToTomorrow {
149 | let isRelativeDateDuringSameWeek = isDate(relativeToToday, duringSameWeekAsDate: date)
150 |
151 | if isRelativeDateDuringSameWeek {
152 | relation = NearTermDateRelation.tomorrow
153 | } else {
154 | relation = NearTermDateRelation.nextWeek
155 | }
156 | } else if isDateDuringSameWeekAsDate {
157 | relation = NearTermDateRelation.laterThisWeek
158 | } else if isDateDuringSameWeekAfterDate {
159 | relation = NearTermDateRelation.nextWeek
160 | }
161 |
162 | return relation
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/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 |
61 |
68 |
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 |
120 |
121 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
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 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/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 | );
288 | path = "Application Logic";
289 | sourceTree = "";
290 | };
291 | 261FA18E19414A720029F589 /* Interactor */ = {
292 | isa = PBXGroup;
293 | children = (
294 | 261FA18F19414A720029F589 /* AddInteractor.swift */,
295 | );
296 | path = Interactor;
297 | sourceTree = "";
298 | };
299 | 261FA19019414A720029F589 /* Manager */ = {
300 | isa = PBXGroup;
301 | children = (
302 | 261FA19119414A720029F589 /* AddDataManager.swift */,
303 | );
304 | path = Manager;
305 | sourceTree = "";
306 | };
307 | 261FA19319414A720029F589 /* Module Interface */ = {
308 | isa = PBXGroup;
309 | children = (
310 | 261FA19419414A720029F589 /* AddModuleDelegateInterface.swift */,
311 | 261FA19519414A720029F589 /* AddModuleInterface.swift */,
312 | );
313 | path = "Module Interface";
314 | sourceTree = "";
315 | };
316 | 261FA19619414A720029F589 /* User Interface */ = {
317 | isa = PBXGroup;
318 | children = (
319 | 261FA19719414A720029F589 /* Presenter */,
320 | 261FA19919414A720029F589 /* Transition */,
321 | 261FA19C19414A720029F589 /* View */,
322 | 261FA19F19414A720029F589 /* Wireframe */,
323 | );
324 | path = "User Interface";
325 | sourceTree = "";
326 | };
327 | 261FA19719414A720029F589 /* Presenter */ = {
328 | isa = PBXGroup;
329 | children = (
330 | 261FA19819414A720029F589 /* AddPresenter.swift */,
331 | );
332 | path = Presenter;
333 | sourceTree = "";
334 | };
335 | 261FA19919414A720029F589 /* Transition */ = {
336 | isa = PBXGroup;
337 | children = (
338 | 261FA19A19414A720029F589 /* AddDismissalTransition.swift */,
339 | 261FA19B19414A720029F589 /* AddPresentationTransition.swift */,
340 | );
341 | path = Transition;
342 | sourceTree = "";
343 | };
344 | 261FA19C19414A720029F589 /* View */ = {
345 | isa = PBXGroup;
346 | children = (
347 | 261FA19D19414A720029F589 /* AddViewController.swift */,
348 | 261FA19E19414A720029F589 /* AddViewInterface.swift */,
349 | );
350 | path = View;
351 | sourceTree = "";
352 | };
353 | 261FA19F19414A720029F589 /* Wireframe */ = {
354 | isa = PBXGroup;
355 | children = (
356 | 261FA1A019414A720029F589 /* AddWireframe.swift */,
357 | );
358 | path = Wireframe;
359 | sourceTree = "";
360 | };
361 | 261FA1A119414A720029F589 /* List */ = {
362 | isa = PBXGroup;
363 | children = (
364 | 261FA1A219414A720029F589 /* Application Logic */,
365 | 261FA1AA19414A720029F589 /* Module Interface */,
366 | 261FA1AC19414A720029F589 /* User Interface */,
367 | );
368 | path = List;
369 | sourceTree = "";
370 | };
371 | 261FA1A219414A720029F589 /* Application Logic */ = {
372 | isa = PBXGroup;
373 | children = (
374 | 261FA1A319414A720029F589 /* Interactor */,
375 | 261FA1A719414A720029F589 /* Manager */,
376 | );
377 | path = "Application Logic";
378 | sourceTree = "";
379 | };
380 | 261FA1A319414A720029F589 /* Interactor */ = {
381 | isa = PBXGroup;
382 | children = (
383 | 261FA1A419414A720029F589 /* ListInteractor.swift */,
384 | 261FA1A519414A720029F589 /* ListInteractorIO.swift */,
385 | 261FA1A619414A720029F589 /* UpcomingItem.swift */,
386 | );
387 | path = Interactor;
388 | sourceTree = "";
389 | };
390 | 261FA1A719414A720029F589 /* Manager */ = {
391 | isa = PBXGroup;
392 | children = (
393 | 261FA1A819414A720029F589 /* ListDataManager.swift */,
394 | );
395 | path = Manager;
396 | sourceTree = "";
397 | };
398 | 261FA1AA19414A720029F589 /* Module Interface */ = {
399 | isa = PBXGroup;
400 | children = (
401 | 261FA1AB19414A720029F589 /* ListModuleInterface.swift */,
402 | );
403 | path = "Module Interface";
404 | sourceTree = "";
405 | };
406 | 261FA1AC19414A720029F589 /* User Interface */ = {
407 | isa = PBXGroup;
408 | children = (
409 | 261FA1AD19414A720029F589 /* Presenter */,
410 | 261FA1B319414A720029F589 /* View */,
411 | 261FA1B619414A720029F589 /* Wireframe */,
412 | );
413 | path = "User Interface";
414 | sourceTree = "";
415 | };
416 | 261FA1AD19414A720029F589 /* Presenter */ = {
417 | isa = PBXGroup;
418 | children = (
419 | 261FA1AE19414A720029F589 /* ListPresenter.swift */,
420 | 261FA1AF19414A720029F589 /* UpcomingDisplayData.swift */,
421 | 261FA1B019414A720029F589 /* UpcomingDisplayDataCollection.swift */,
422 | 261FA1B119414A720029F589 /* UpcomingDisplayItem.swift */,
423 | 261FA1B219414A720029F589 /* UpcomingDisplaySection.swift */,
424 | );
425 | path = Presenter;
426 | sourceTree = "";
427 | };
428 | 261FA1B319414A720029F589 /* View */ = {
429 | isa = PBXGroup;
430 | children = (
431 | 261FA1B419414A720029F589 /* ListViewController.swift */,
432 | 261FA1B519414A720029F589 /* ListViewInterface.swift */,
433 | );
434 | path = View;
435 | sourceTree = "";
436 | };
437 | 261FA1B619414A720029F589 /* Wireframe */ = {
438 | isa = PBXGroup;
439 | children = (
440 | 261FA1B719414A720029F589 /* ListWireframe.swift */,
441 | );
442 | path = Wireframe;
443 | sourceTree = "";
444 | };
445 | 261FA1DD19414AC20029F589 /* Resources */ = {
446 | isa = PBXGroup;
447 | children = (
448 | 261FA1EA1942320E0029F589 /* Main.storyboard */,
449 | 261FA1ED194232180029F589 /* Images.xcassets */,
450 | );
451 | name = Resources;
452 | path = "../../../../Documents/Repos/VIPER-TODO-SWIFT/viper-todo-swift/VIPER TODO/Resources";
453 | sourceTree = "";
454 | };
455 | 261FA1DE19414AC60029F589 /* Supporting Files */ = {
456 | isa = PBXGroup;
457 | children = (
458 | 261FA1E819414E600029F589 /* Info.plist */,
459 | );
460 | name = "Supporting Files";
461 | sourceTree = "";
462 | };
463 | /* End PBXGroup section */
464 |
465 | /* Begin PBXNativeTarget section */
466 | 261FA14D1941497E0029F589 /* VIPER-SWIFT */ = {
467 | isa = PBXNativeTarget;
468 | buildConfigurationList = 261FA16A1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFT" */;
469 | buildPhases = (
470 | 261FA14A1941497E0029F589 /* Sources */,
471 | 261FA14B1941497E0029F589 /* Frameworks */,
472 | 261FA14C1941497E0029F589 /* Resources */,
473 | );
474 | buildRules = (
475 | );
476 | dependencies = (
477 | );
478 | name = "VIPER-SWIFT";
479 | productName = "VIPER-SWIFT";
480 | productReference = 261FA14E1941497E0029F589 /* VIPER-SWIFT.app */;
481 | productType = "com.apple.product-type.application";
482 | };
483 | 261FA15F1941497E0029F589 /* VIPER-SWIFTTests */ = {
484 | isa = PBXNativeTarget;
485 | buildConfigurationList = 261FA16D1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFTTests" */;
486 | buildPhases = (
487 | 261FA15C1941497E0029F589 /* Sources */,
488 | 261FA15D1941497E0029F589 /* Frameworks */,
489 | 261FA15E1941497E0029F589 /* Resources */,
490 | );
491 | buildRules = (
492 | );
493 | dependencies = (
494 | 261FA1621941497E0029F589 /* PBXTargetDependency */,
495 | );
496 | name = "VIPER-SWIFTTests";
497 | productName = "VIPER-SWIFTTests";
498 | productReference = 261FA1601941497E0029F589 /* VIPER-SWIFTTests.xctest */;
499 | productType = "com.apple.product-type.bundle.unit-test";
500 | };
501 | /* End PBXNativeTarget section */
502 |
503 | /* Begin PBXProject section */
504 | 261FA1461941497E0029F589 /* Project object */ = {
505 | isa = PBXProject;
506 | attributes = {
507 | LastSwiftMigration = 0730;
508 | LastSwiftUpdateCheck = 0730;
509 | LastUpgradeCheck = 0920;
510 | ORGANIZATIONNAME = "Conrad Stoll";
511 | TargetAttributes = {
512 | 261FA14D1941497E0029F589 = {
513 | CreatedOnToolsVersion = 6.0;
514 | LastSwiftMigration = 0920;
515 | };
516 | 261FA15F1941497E0029F589 = {
517 | CreatedOnToolsVersion = 6.0;
518 | LastSwiftMigration = 0920;
519 | TestTargetID = 261FA14D1941497E0029F589;
520 | };
521 | };
522 | };
523 | buildConfigurationList = 261FA1491941497E0029F589 /* Build configuration list for PBXProject "VIPER-SWIFT" */;
524 | compatibilityVersion = "Xcode 3.2";
525 | developmentRegion = English;
526 | hasScannedForEncodings = 0;
527 | knownRegions = (
528 | en,
529 | Base,
530 | );
531 | mainGroup = 261FA1451941497E0029F589;
532 | productRefGroup = 261FA14F1941497E0029F589 /* Products */;
533 | projectDirPath = "";
534 | projectRoot = "";
535 | targets = (
536 | 261FA14D1941497E0029F589 /* VIPER-SWIFT */,
537 | 261FA15F1941497E0029F589 /* VIPER-SWIFTTests */,
538 | );
539 | };
540 | /* End PBXProject section */
541 |
542 | /* Begin PBXResourcesBuildPhase section */
543 | 261FA14C1941497E0029F589 /* Resources */ = {
544 | isa = PBXResourcesBuildPhase;
545 | buildActionMask = 2147483647;
546 | files = (
547 | 261FA1EE194232180029F589 /* Images.xcassets in Resources */,
548 | 261FA1EC1942320E0029F589 /* Main.storyboard in Resources */,
549 | );
550 | runOnlyForDeploymentPostprocessing = 0;
551 | };
552 | 261FA15E1941497E0029F589 /* Resources */ = {
553 | isa = PBXResourcesBuildPhase;
554 | buildActionMask = 2147483647;
555 | files = (
556 | 26D96FA91942932A00F117F5 /* Main.storyboard in Resources */,
557 | 26D96FAA1942932A00F117F5 /* Images.xcassets in Resources */,
558 | );
559 | runOnlyForDeploymentPostprocessing = 0;
560 | };
561 | /* End PBXResourcesBuildPhase section */
562 |
563 | /* Begin PBXSourcesBuildPhase section */
564 | 261FA14A1941497E0029F589 /* Sources */ = {
565 | isa = PBXSourcesBuildPhase;
566 | buildActionMask = 2147483647;
567 | files = (
568 | 261FA1C719414A720029F589 /* AddDataManager.swift in Sources */,
569 | 261FA1D119414A720029F589 /* ListInteractorIO.swift in Sources */,
570 | 261FA1D719414A720029F589 /* UpcomingDisplayDataCollection.swift in Sources */,
571 | 261FA1D219414A720029F589 /* UpcomingItem.swift in Sources */,
572 | 261FA1D519414A720029F589 /* ListPresenter.swift in Sources */,
573 | 261FA1D419414A720029F589 /* ListModuleInterface.swift in Sources */,
574 | 261FA1B919414A720029F589 /* AppDependencies.swift in Sources */,
575 | 261FA1D619414A720029F589 /* UpcomingDisplayData.swift in Sources */,
576 | 261FA1C619414A720029F589 /* AddInteractor.swift in Sources */,
577 | 261FA1D919414A720029F589 /* UpcomingDisplaySection.swift in Sources */,
578 | 261FA1C819414A720029F589 /* AddModuleDelegateInterface.swift in Sources */,
579 | 261FA1BF19414A720029F589 /* DeviceClock.swift in Sources */,
580 | 261FA1DA19414A720029F589 /* ListViewController.swift in Sources */,
581 | 261FA1BE19414A720029F589 /* Clock.swift in Sources */,
582 | 261FA1C519414A720029F589 /* RootWireframe.swift in Sources */,
583 | 261FA1C419414A720029F589 /* TODO.xcdatamodeld in Sources */,
584 | 261FA1CD19414A720029F589 /* AddViewController.swift in Sources */,
585 | 261FA1C119414A720029F589 /* TodoItem.swift in Sources */,
586 | 26A605EB1942A1EE0036C71F /* AppDelegate.swift in Sources */,
587 | 261FA1CB19414A720029F589 /* AddDismissalTransition.swift in Sources */,
588 | 261FA1C219414A720029F589 /* CoreDataStore.swift in Sources */,
589 | 261FA1CC19414A720029F589 /* AddPresentationTransition.swift in Sources */,
590 | 261FA1C919414A720029F589 /* AddModuleInterface.swift in Sources */,
591 | 261FA1D319414A720029F589 /* ListDataManager.swift in Sources */,
592 | 261FA1CA19414A720029F589 /* AddPresenter.swift in Sources */,
593 | 261FA1D019414A720029F589 /* ListInteractor.swift in Sources */,
594 | 261FA1C019414A720029F589 /* NearTermDateRelation.swift in Sources */,
595 | 261FA1E719414CBE0029F589 /* ManagedTodoItem.swift in Sources */,
596 | 261FA1D819414A720029F589 /* UpcomingDisplayItem.swift in Sources */,
597 | 261FA1BC19414A720029F589 /* NSCalendar+CalendarAdditions.swift in Sources */,
598 | 261FA1DB19414A720029F589 /* ListViewInterface.swift in Sources */,
599 | 261FA1DC19414A720029F589 /* ListWireframe.swift in Sources */,
600 | 261FA1CE19414A720029F589 /* AddViewInterface.swift in Sources */,
601 | 261FA1CF19414A720029F589 /* AddWireframe.swift in Sources */,
602 | );
603 | runOnlyForDeploymentPostprocessing = 0;
604 | };
605 | 261FA15C1941497E0029F589 /* Sources */ = {
606 | isa = PBXSourcesBuildPhase;
607 | buildActionMask = 2147483647;
608 | files = (
609 | 26D96FB219429B1A00F117F5 /* ListDataManager.swift in Sources */,
610 | 26D96FAF19429AD000F117F5 /* ManagedTodoItem.swift in Sources */,
611 | 26D96F9D19428C7E00F117F5 /* NSCalendar+CalendarAdditions.swift in Sources */,
612 | 26D96FAC1942967900F117F5 /* RelativeDateTests.swift in Sources */,
613 | 26D96FAE19429A9000F117F5 /* DataTests.swift in Sources */,
614 | 26D96FA71942913B00F117F5 /* ListModuleInterface.swift in Sources */,
615 | 26D96FA41942912A00F117F5 /* UpcomingDisplaySection.swift in Sources */,
616 | 26D96FA31942912A00F117F5 /* UpcomingDisplayItem.swift in Sources */,
617 | 26D96F9C19428C3600F117F5 /* CalendarTests.swift in Sources */,
618 | 26D96FA61942913600F117F5 /* ListViewInterface.swift in Sources */,
619 | 26D96FB019429AD000F117F5 /* CoreDataStore.swift in Sources */,
620 | 26D96FA11942912A00F117F5 /* UpcomingDisplayData.swift in Sources */,
621 | 26D96FA81942915D00F117F5 /* UpcomingItem.swift in Sources */,
622 | 26D96F9E19428D8100F117F5 /* NearTermDateRelation.swift in Sources */,
623 | 26D96FA51942912A00F117F5 /* ListViewController.swift in Sources */,
624 | 26D96FB119429B1A00F117F5 /* TodoItem.swift in Sources */,
625 | 26D96FA21942912A00F117F5 /* UpcomingDisplayDataCollection.swift in Sources */,
626 | );
627 | runOnlyForDeploymentPostprocessing = 0;
628 | };
629 | /* End PBXSourcesBuildPhase section */
630 |
631 | /* Begin PBXTargetDependency section */
632 | 261FA1621941497E0029F589 /* PBXTargetDependency */ = {
633 | isa = PBXTargetDependency;
634 | target = 261FA14D1941497E0029F589 /* VIPER-SWIFT */;
635 | targetProxy = 261FA1611941497E0029F589 /* PBXContainerItemProxy */;
636 | };
637 | /* End PBXTargetDependency section */
638 |
639 | /* Begin PBXVariantGroup section */
640 | 261FA1EA1942320E0029F589 /* Main.storyboard */ = {
641 | isa = PBXVariantGroup;
642 | children = (
643 | 261FA1EB1942320E0029F589 /* Base */,
644 | );
645 | name = Main.storyboard;
646 | sourceTree = "";
647 | };
648 | /* End PBXVariantGroup section */
649 |
650 | /* Begin XCBuildConfiguration section */
651 | 261FA1681941497E0029F589 /* Debug */ = {
652 | isa = XCBuildConfiguration;
653 | buildSettings = {
654 | ALWAYS_SEARCH_USER_PATHS = NO;
655 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
656 | CLANG_CXX_LIBRARY = "libc++";
657 | CLANG_ENABLE_MODULES = YES;
658 | CLANG_ENABLE_OBJC_ARC = YES;
659 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
660 | CLANG_WARN_BOOL_CONVERSION = YES;
661 | CLANG_WARN_COMMA = YES;
662 | CLANG_WARN_CONSTANT_CONVERSION = YES;
663 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
664 | CLANG_WARN_EMPTY_BODY = YES;
665 | CLANG_WARN_ENUM_CONVERSION = YES;
666 | CLANG_WARN_INFINITE_RECURSION = YES;
667 | CLANG_WARN_INT_CONVERSION = YES;
668 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
669 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
670 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
671 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
672 | CLANG_WARN_STRICT_PROTOTYPES = YES;
673 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
674 | CLANG_WARN_UNREACHABLE_CODE = YES;
675 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
676 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
677 | COPY_PHASE_STRIP = NO;
678 | ENABLE_STRICT_OBJC_MSGSEND = YES;
679 | ENABLE_TESTABILITY = YES;
680 | GCC_C_LANGUAGE_STANDARD = gnu99;
681 | GCC_DYNAMIC_NO_PIC = NO;
682 | GCC_NO_COMMON_BLOCKS = YES;
683 | GCC_OPTIMIZATION_LEVEL = 0;
684 | GCC_PREPROCESSOR_DEFINITIONS = (
685 | "DEBUG=1",
686 | "$(inherited)",
687 | );
688 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
689 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
690 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
691 | GCC_WARN_UNDECLARED_SELECTOR = YES;
692 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
693 | GCC_WARN_UNUSED_FUNCTION = YES;
694 | GCC_WARN_UNUSED_VARIABLE = YES;
695 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
696 | METAL_ENABLE_DEBUG_INFO = YES;
697 | ONLY_ACTIVE_ARCH = YES;
698 | SDKROOT = iphoneos;
699 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
700 | };
701 | name = Debug;
702 | };
703 | 261FA1691941497E0029F589 /* Release */ = {
704 | isa = XCBuildConfiguration;
705 | buildSettings = {
706 | ALWAYS_SEARCH_USER_PATHS = NO;
707 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
708 | CLANG_CXX_LIBRARY = "libc++";
709 | CLANG_ENABLE_MODULES = YES;
710 | CLANG_ENABLE_OBJC_ARC = YES;
711 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
712 | CLANG_WARN_BOOL_CONVERSION = YES;
713 | CLANG_WARN_COMMA = 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_INFINITE_RECURSION = YES;
719 | CLANG_WARN_INT_CONVERSION = YES;
720 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
721 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
722 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
723 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
724 | CLANG_WARN_STRICT_PROTOTYPES = YES;
725 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
726 | CLANG_WARN_UNREACHABLE_CODE = YES;
727 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
728 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
729 | COPY_PHASE_STRIP = YES;
730 | ENABLE_NS_ASSERTIONS = NO;
731 | ENABLE_STRICT_OBJC_MSGSEND = YES;
732 | GCC_C_LANGUAGE_STANDARD = gnu99;
733 | GCC_NO_COMMON_BLOCKS = YES;
734 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
735 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
736 | GCC_WARN_UNDECLARED_SELECTOR = YES;
737 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
738 | GCC_WARN_UNUSED_FUNCTION = YES;
739 | GCC_WARN_UNUSED_VARIABLE = YES;
740 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
741 | METAL_ENABLE_DEBUG_INFO = NO;
742 | SDKROOT = iphoneos;
743 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
744 | VALIDATE_PRODUCT = YES;
745 | };
746 | name = Release;
747 | };
748 | 261FA16B1941497E0029F589 /* Debug */ = {
749 | isa = XCBuildConfiguration;
750 | buildSettings = {
751 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
752 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
753 | INFOPLIST_FILE = "VIPER-SWIFT/Info.plist";
754 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
755 | PRODUCT_BUNDLE_IDENTIFIER = "com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}";
756 | PRODUCT_NAME = "$(TARGET_NAME)";
757 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
758 | SWIFT_VERSION = 4.0;
759 | };
760 | name = Debug;
761 | };
762 | 261FA16C1941497E0029F589 /* Release */ = {
763 | isa = XCBuildConfiguration;
764 | buildSettings = {
765 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
766 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
767 | INFOPLIST_FILE = "VIPER-SWIFT/Info.plist";
768 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
769 | PRODUCT_BUNDLE_IDENTIFIER = "com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}";
770 | PRODUCT_NAME = "$(TARGET_NAME)";
771 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
772 | SWIFT_VERSION = 4.0;
773 | };
774 | name = Release;
775 | };
776 | 261FA16E1941497E0029F589 /* Debug */ = {
777 | isa = XCBuildConfiguration;
778 | buildSettings = {
779 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/VIPER-SWIFT.app/VIPER-SWIFT";
780 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
781 | GCC_PREPROCESSOR_DEFINITIONS = (
782 | "DEBUG=1",
783 | "$(inherited)",
784 | );
785 | INFOPLIST_FILE = "VIPER-SWIFTTests/Info.plist";
786 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
787 | METAL_ENABLE_DEBUG_INFO = YES;
788 | PRODUCT_BUNDLE_IDENTIFIER = "com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}";
789 | PRODUCT_NAME = "$(TARGET_NAME)";
790 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
791 | SWIFT_VERSION = 4.0;
792 | TEST_HOST = "$(BUNDLE_LOADER)";
793 | };
794 | name = Debug;
795 | };
796 | 261FA16F1941497E0029F589 /* Release */ = {
797 | isa = XCBuildConfiguration;
798 | buildSettings = {
799 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/VIPER-SWIFT.app/VIPER-SWIFT";
800 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
801 | INFOPLIST_FILE = "VIPER-SWIFTTests/Info.plist";
802 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
803 | METAL_ENABLE_DEBUG_INFO = NO;
804 | PRODUCT_BUNDLE_IDENTIFIER = "com.mutualmobile.${PRODUCT_NAME:rfc1034identifier}";
805 | PRODUCT_NAME = "$(TARGET_NAME)";
806 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
807 | SWIFT_VERSION = 4.0;
808 | TEST_HOST = "$(BUNDLE_LOADER)";
809 | };
810 | name = Release;
811 | };
812 | /* End XCBuildConfiguration section */
813 |
814 | /* Begin XCConfigurationList section */
815 | 261FA1491941497E0029F589 /* Build configuration list for PBXProject "VIPER-SWIFT" */ = {
816 | isa = XCConfigurationList;
817 | buildConfigurations = (
818 | 261FA1681941497E0029F589 /* Debug */,
819 | 261FA1691941497E0029F589 /* Release */,
820 | );
821 | defaultConfigurationIsVisible = 0;
822 | defaultConfigurationName = Release;
823 | };
824 | 261FA16A1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFT" */ = {
825 | isa = XCConfigurationList;
826 | buildConfigurations = (
827 | 261FA16B1941497E0029F589 /* Debug */,
828 | 261FA16C1941497E0029F589 /* Release */,
829 | );
830 | defaultConfigurationIsVisible = 0;
831 | defaultConfigurationName = Release;
832 | };
833 | 261FA16D1941497E0029F589 /* Build configuration list for PBXNativeTarget "VIPER-SWIFTTests" */ = {
834 | isa = XCConfigurationList;
835 | buildConfigurations = (
836 | 261FA16E1941497E0029F589 /* Debug */,
837 | 261FA16F1941497E0029F589 /* Release */,
838 | );
839 | defaultConfigurationIsVisible = 0;
840 | defaultConfigurationName = Release;
841 | };
842 | /* End XCConfigurationList section */
843 |
844 | /* Begin XCVersionGroup section */
845 | 261FA18719414A720029F589 /* TODO.xcdatamodeld */ = {
846 | isa = XCVersionGroup;
847 | children = (
848 | 261FA18819414A720029F589 /* TODO.xcdatamodel */,
849 | );
850 | currentVersion = 261FA18819414A720029F589 /* TODO.xcdatamodel */;
851 | path = TODO.xcdatamodeld;
852 | sourceTree = "";
853 | versionGroupType = wrapper.xcdatamodel;
854 | };
855 | /* End XCVersionGroup section */
856 | };
857 | rootObject = 261FA1461941497E0029F589 /* Project object */;
858 | }
859 |
--------------------------------------------------------------------------------