├── .gitignore
├── Set
├── .gitignore
└── Set
│ ├── Info.plist
│ ├── Supporting Files
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ └── AppDelegate.swift
│ └── Card.swift
├── Cassini
├── .gitignore
├── Cassini
│ ├── oval.jpg
│ ├── DemoURLs.swift
│ ├── Info.plist
│ ├── Supporting Files
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ └── AppDelegate.swift
│ └── CassiniViewController.swift
├── CassiniTests
│ ├── Info.plist
│ └── CassiniTests.swift
└── CassiniUITests
│ ├── Info.plist
│ └── CassiniUITests.swift
├── EmojiArt
├── .gitignore
├── EmojiArt
│ ├── EmojiCollectionViewCell.swift
│ ├── TextFieldCollectionViewCell.swift
│ ├── Info.plist
│ ├── EmojiArtDocumentTableViewController.swift
│ └── EmojiArtView.swift
├── EmojiArtTests
│ ├── Info.plist
│ └── EmojiArtTests.swift
├── EmojiArtUITests
│ ├── Info.plist
│ └── EmojiArtUITests.swift
└── Supporting Files
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ └── AppDelegate.swift
├── Concentration
├── .gitignore
├── Concentration.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── ruben.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── ruben.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── Concentration
│ ├── Extensions
│ ├── CollectionExtension.swift
│ ├── IntExtension.swift
│ └── MutableCollectionExtension.swift
│ ├── Info.plist
│ ├── Card.swift
│ └── Supporting Files
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ └── AppDelegate.swift
├── ImageGallery
├── .gitignore
└── ImageGallery
│ ├── Supporting Files
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── testImage.imageset
│ │ │ ├── testImage.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ └── AppDelegate.swift
│ ├── ItemViewController
│ ├── ItemViewController+UIScrollViewDelegate.swift
│ └── ItemViewController.swift
│ ├── Utilities
│ ├── URLUtilities.swift
│ └── UIViewControllerUtilities.swift
│ ├── GalleryViewController
│ ├── GalleryViewController+UICollectionViewDelegateFlowLayout.swift
│ ├── GalleryViewController+UICollectionViewDataSource.swift
│ ├── GalleryViewController+UICollectionViewDragDelegate.swift
│ └── GalleryViewController.swift
│ ├── Settings.swift
│ ├── ImageGallery.swift
│ └── Info.plist
├── Lecture8_PlayingCard
├── .gitignore
└── PlayingCard
│ ├── Assets.xcassets
│ ├── Contents.json
│ ├── J♠️.imageset
│ │ ├── jack.jpg
│ │ ├── jack2x.jpg
│ │ └── Contents.json
│ ├── J♣️.imageset
│ │ ├── jack.jpg
│ │ ├── jack2x.jpg
│ │ └── Contents.json
│ ├── J♥️.imageset
│ │ ├── jack.jpg
│ │ ├── jack2x.jpg
│ │ └── Contents.json
│ ├── J♦️.imageset
│ │ ├── jack.jpg
│ │ ├── jack2x.jpg
│ │ └── Contents.json
│ ├── K♠️.imageset
│ │ ├── king.jpg
│ │ ├── king2x.jpg
│ │ └── Contents.json
│ ├── K♣️.imageset
│ │ ├── king.jpg
│ │ ├── king2x.jpg
│ │ └── Contents.json
│ ├── K♥️.imageset
│ │ ├── king.jpg
│ │ ├── king2x.jpg
│ │ └── Contents.json
│ ├── K♦️.imageset
│ │ ├── king.jpg
│ │ ├── king2x.jpg
│ │ └── Contents.json
│ ├── Q♠️.imageset
│ │ ├── qeen.jpg
│ │ ├── queen2x.jpg
│ │ └── Contents.json
│ ├── Q♣️.imageset
│ │ ├── qeen.jpg
│ │ ├── queen2x.jpg
│ │ └── Contents.json
│ ├── Q♥️.imageset
│ │ ├── qeen.jpg
│ │ ├── queen2x.jpg
│ │ └── Contents.json
│ ├── Q♦️.imageset
│ │ ├── qeen.jpg
│ │ ├── queen2x.jpg
│ │ └── Contents.json
│ ├── cardback.imageset
│ │ ├── cardback.jpg
│ │ ├── cardback@2x.jpg
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Extensions
│ ├── CGFloatExtension.swift
│ └── IntExtension.swift
│ ├── PlayingCardDeck.swift
│ ├── Info.plist
│ ├── Supporting Files
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ └── AppDelegate.swift
│ ├── PlayingCard.swift
│ └── CardBehavior.swift
├── artwork
├── lecture-1.png
├── lecture-10.jpg
├── lecture-11.jpg
├── lecture-12.jpg
├── lecture-13.jpg
├── lecture-14.jpg
├── lecture-15.jpg
├── lecture-2.png
├── lecture-3.jpg
├── lecture-4.jpg
├── lecture-5.jpg
├── lecture-6.png
├── lecture-7.jpg
├── lecture-8.jpg
├── lecture-9.jpg
├── assignment-5.jpg
├── course_logo.png
├── assignment-1-preview.jpg
├── assignment-2-preview.jpg
├── assignment-3-preview.jpg
└── assignment-6-preview.jpg
├── ImageGallery_P6
├── ImageGallery_P6
│ ├── Gallery.imgallery
│ ├── Utilities
│ │ ├── UIViewUtilities.swift
│ │ ├── URLUtilities.swift
│ │ ├── UIViewControllerUtilities.swift
│ │ └── Settings.swift
│ ├── ItemViewController+UIScrollViewDelegate.swift
│ ├── GalleryViewController
│ │ ├── GalleryViewController+UICollectionViewDelegateFlowLayout.swift
│ │ ├── GalleryViewController+UICollectionViewDataSource.swift
│ │ └── GalleryViewController+UICollectionViewDragDelegate.swift
│ ├── ImageGallery.swift
│ ├── Supporting Files
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ └── AppDelegate.swift
│ ├── Info.plist
│ ├── DocumentBrowser
│ │ ├── ImageGalleryDocument.swift
│ │ └── DocumentBrowserViewController.swift
│ └── ItemViewController.swift
└── ImageGallery_P6.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── ruben.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ └── ruben.xcuserdatad
│ ├── xcschemes
│ └── xcschememanagement.plist
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
├── PlayingCard
├── PlayingCard
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── J♠️.imageset
│ │ │ ├── jack.jpg
│ │ │ ├── jack2x.jpg
│ │ │ └── Contents.json
│ │ ├── J♣️.imageset
│ │ │ ├── jack.jpg
│ │ │ ├── jack2x.jpg
│ │ │ └── Contents.json
│ │ ├── J♥️.imageset
│ │ │ ├── jack.jpg
│ │ │ ├── jack2x.jpg
│ │ │ └── Contents.json
│ │ ├── J♦️.imageset
│ │ │ ├── jack.jpg
│ │ │ ├── jack2x.jpg
│ │ │ └── Contents.json
│ │ ├── K♠️.imageset
│ │ │ ├── king.jpg
│ │ │ ├── king2x.jpg
│ │ │ └── Contents.json
│ │ ├── K♣️.imageset
│ │ │ ├── king.jpg
│ │ │ ├── king2x.jpg
│ │ │ └── Contents.json
│ │ ├── K♥️.imageset
│ │ │ ├── king.jpg
│ │ │ ├── king2x.jpg
│ │ │ └── Contents.json
│ │ ├── K♦️.imageset
│ │ │ ├── king.jpg
│ │ │ ├── king2x.jpg
│ │ │ └── Contents.json
│ │ ├── Q♠️.imageset
│ │ │ ├── qeen.jpg
│ │ │ ├── queen2x.jpg
│ │ │ └── Contents.json
│ │ ├── Q♣️.imageset
│ │ │ ├── qeen.jpg
│ │ │ ├── queen2x.jpg
│ │ │ └── Contents.json
│ │ ├── Q♥️.imageset
│ │ │ ├── qeen.jpg
│ │ │ ├── queen2x.jpg
│ │ │ └── Contents.json
│ │ ├── Q♦️.imageset
│ │ │ ├── qeen.jpg
│ │ │ ├── queen2x.jpg
│ │ │ └── Contents.json
│ │ ├── cardback.imageset
│ │ │ ├── cardback.jpg
│ │ │ ├── cardback@2x.jpg
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Extensions
│ │ └── IntExtension.swift
│ ├── PlayingCardDeck.swift
│ ├── Info.plist
│ ├── Supporting Files
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ └── AppDelegate.swift
│ ├── ViewController.swift
│ └── PlayingCard.swift
└── PlayingCard.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── ruben.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ └── ruben.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── EmojiArtL14
├── EmojiArtL14.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── ruben.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── ruben.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── EmojiArtL14
│ ├── EmojiCollectionViewCell.swift
│ ├── TextFieldCollectionViewCell.swift
│ ├── EmojiArt.swift
│ ├── Supporting Files
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ └── AppDelegate.swift
│ ├── EmojiArtDocument.swift
│ ├── Info.plist
│ └── DocumentBrowserViewController.swift
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/Set/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/Cassini/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/EmojiArt/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/Concentration/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/ImageGallery/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/artwork/lecture-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-1.png
--------------------------------------------------------------------------------
/artwork/lecture-10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-10.jpg
--------------------------------------------------------------------------------
/artwork/lecture-11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-11.jpg
--------------------------------------------------------------------------------
/artwork/lecture-12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-12.jpg
--------------------------------------------------------------------------------
/artwork/lecture-13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-13.jpg
--------------------------------------------------------------------------------
/artwork/lecture-14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-14.jpg
--------------------------------------------------------------------------------
/artwork/lecture-15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-15.jpg
--------------------------------------------------------------------------------
/artwork/lecture-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-2.png
--------------------------------------------------------------------------------
/artwork/lecture-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-3.jpg
--------------------------------------------------------------------------------
/artwork/lecture-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-4.jpg
--------------------------------------------------------------------------------
/artwork/lecture-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-5.jpg
--------------------------------------------------------------------------------
/artwork/lecture-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-6.png
--------------------------------------------------------------------------------
/artwork/lecture-7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-7.jpg
--------------------------------------------------------------------------------
/artwork/lecture-8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-8.jpg
--------------------------------------------------------------------------------
/artwork/lecture-9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/lecture-9.jpg
--------------------------------------------------------------------------------
/Cassini/Cassini/oval.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Cassini/Cassini/oval.jpg
--------------------------------------------------------------------------------
/artwork/assignment-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/assignment-5.jpg
--------------------------------------------------------------------------------
/artwork/course_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/course_logo.png
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Gallery.imgallery:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Untitled",
3 | "items": []
4 | }
5 |
6 |
7 |
--------------------------------------------------------------------------------
/artwork/assignment-1-preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/assignment-1-preview.jpg
--------------------------------------------------------------------------------
/artwork/assignment-2-preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/assignment-2-preview.jpg
--------------------------------------------------------------------------------
/artwork/assignment-3-preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/assignment-3-preview.jpg
--------------------------------------------------------------------------------
/artwork/assignment-6-preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/artwork/assignment-6-preview.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/qeen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/qeen.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/jack2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/king2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/queen2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/queen2x.jpg
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback@2x.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback.jpg
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback@2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/cardback@2x.jpg
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/Assets.xcassets/testImage.imageset/testImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/ImageGallery/ImageGallery/Supporting Files/Assets.xcassets/testImage.imageset/testImage.png
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Concentration/Concentration.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/EmojiArtL14/EmojiArtL14.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/PlayingCard/PlayingCard.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Concentration/Concentration.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/Concentration/Concentration.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rubenbaca/cs193p_iOS11/HEAD/ImageGallery_P6/ImageGallery_P6.xcodeproj/project.xcworkspace/xcuserdata/ruben.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Extensions/CGFloatExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGFloatExtension.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/16/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | // Extension for simple but useful uitilities
11 | extension CGFloat {
12 | var arc4random: CGFloat {
13 | return self * (CGFloat(arc4random_uniform(UInt32.max))/CGFloat(UInt32.max))
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/Assets.xcassets/testImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "testImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14.xcodeproj/xcuserdata/ruben.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | EmojiArtL14.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard.xcodeproj/xcuserdata/ruben.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | PlayingCard.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Concentration/Concentration.xcodeproj/xcuserdata/ruben.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Concentration.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/EmojiArt/EmojiArt/EmojiCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiCollectionViewCell.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 1/13/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// Collection view cell containing an emoji label
13 | ///
14 | class EmojiCollectionViewCell: UICollectionViewCell {
15 | ///
16 | /// The label shown in the collection view cell
17 | ///
18 | @IBOutlet weak var label: UILabel!
19 | }
20 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6.xcodeproj/xcuserdata/ruben.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ImageGallery_P6.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/J♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "jack.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "jack2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/K♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "king.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "king2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♠️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♣️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♥️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/Q♦️.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "qeen.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "queen2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "cardback.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "cardback@2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/EmojiCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiCollectionViewCell.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 1/13/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// Collection view cell containing an emoji label
13 | ///
14 | class EmojiCollectionViewCell: UICollectionViewCell {
15 | ///
16 | /// The label shown in the collection view cell
17 | ///
18 | @IBOutlet weak var label: UILabel!
19 | }
20 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/cardback.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "cardback.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "cardback@2x.jpg",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Concentration/Concentration/Extensions/CollectionExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CollectionExtension.swift
3 | // Concentration
4 | //
5 | // Created by Ruben on 12/2/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | // Extension for simple but useful uitilities
10 | extension Collection {
11 | ///
12 | /// If the collection contains only one element, return it. Otherwise,
13 | /// return nil.
14 | ///
15 | var oneAndOnly: Element? {
16 | return count == 1 ? first : nil
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Utilities/UIViewUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewUtilities.swift
3 | // ImageGallery_P6
4 | //
5 | // Created by Ruben on 3/17/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 | var snapshot: UIImage? {
13 | UIGraphicsBeginImageContext(bounds.size)
14 | drawHierarchy(in: bounds, afterScreenUpdates: true)
15 | let image = UIGraphicsGetImageFromCurrentImageContext()
16 | UIGraphicsEndImageContext()
17 | return image
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/ItemViewController+UIScrollViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemViewController+UIScrollViewDelegate.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/21/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | //
11 | // Confrom to `UIScrollViewDelegate`
12 | //
13 | extension ItemViewController: UIScrollViewDelegate {
14 |
15 | ///
16 | /// The view for zooming in the scrollView
17 | ///
18 | func viewForZooming(in scrollView: UIScrollView) -> UIView? {
19 | // If scrollView contains an imageView, return it
20 | return scrollView.subviews.first as? UIImageView
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/ItemViewController/ItemViewController+UIScrollViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemViewController+UIScrollViewDelegate.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/21/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | //
11 | // Confrom to `UIScrollViewDelegate`
12 | //
13 | extension ItemViewController: UIScrollViewDelegate {
14 |
15 | ///
16 | /// The view for zooming in the scrollView
17 | ///
18 | func viewForZooming(in scrollView: UIScrollView) -> UIView? {
19 | // If scrollView contains an imageView, return it
20 | return scrollView.subviews.first as? UIImageView
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Extensions/IntExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntExtension.swift
3 | // Concentration
4 | //
5 | // Created by Ruben on 12/2/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | // Extension for simple but useful uitilities
11 | extension Int {
12 |
13 | ///
14 | /// Get a random number between `self` and 0. If `self` is zero,
15 | /// zero will be returned.
16 | ///
17 | var arc4random: Int {
18 | if self > 0 {
19 | return Int(arc4random_uniform(UInt32(self)))
20 | }
21 | else if self < 0 {
22 | return -Int(arc4random_uniform(UInt32(abs(self))))
23 | }
24 | else {
25 | return 0
26 | }
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Extensions/IntExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntExtension.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // Extension for simple but useful uitilities
12 | extension Int {
13 |
14 | ///
15 | /// Get a random number between `self` and 0. If `self` is zero,
16 | /// zero will be returned.
17 | ///
18 | var arc4random: Int {
19 | if self > 0 {
20 | return Int(arc4random_uniform(UInt32(self)))
21 | }
22 | else if self < 0 {
23 | return -Int(arc4random_uniform(UInt32(abs(self))))
24 | }
25 | else {
26 | return 0
27 | }
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Extensions/IntExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IntExtension.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // Extension for simple but useful uitilities
12 | extension Int {
13 |
14 | ///
15 | /// Get a random number between `self` and 0. If `self` is zero,
16 | /// zero will be returned.
17 | ///
18 | var arc4random: Int {
19 | if self > 0 {
20 | return Int(arc4random_uniform(UInt32(self)))
21 | }
22 | else if self < 0 {
23 | return -Int(arc4random_uniform(UInt32(abs(self))))
24 | }
25 | else {
26 | return 0
27 | }
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Cassini/CassiniTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Cassini/CassiniUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArtTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArtUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Utilities/URLUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLUtilities.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Simple but useful utilities for `URL`
12 | ///
13 | extension URL {
14 | var imageURL: URL {
15 | // check to see if there is an embedded imgurl reference
16 | for query in query?.components(separatedBy: "&") ?? [] {
17 | let queryComponents = query.components(separatedBy: "=")
18 | if queryComponents.count == 2 {
19 | if queryComponents[0] == "imgurl", let url = URL(string: queryComponents[1].removingPercentEncoding ?? "") {
20 | return url
21 | }
22 | }
23 | }
24 | return self.baseURL ?? self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Utilities/URLUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLUtilities.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Simple but useful utilities for `URL`
12 | ///
13 | extension URL {
14 | var imageURL: URL {
15 | // check to see if there is an embedded imgurl reference
16 | for query in query?.components(separatedBy: "&") ?? [] {
17 | let queryComponents = query.components(separatedBy: "=")
18 | if queryComponents.count == 2 {
19 | if queryComponents[0] == "imgurl", let url = URL(string: queryComponents[1].removingPercentEncoding ?? "") {
20 | return url
21 | }
22 | }
23 | }
24 | return self.baseURL ?? self
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6.xcodeproj/xcuserdata/ruben.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Extensions/MutableCollectionExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MutableCollectionExtension.swift
3 | // Concentration
4 | //
5 | // Created by Ruben on 12/2/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | // Extension for simple but useful uitilities
11 | extension MutableCollection {
12 |
13 | /// Shuffle the elements of `self` in-place.
14 | mutating func shuffle() {
15 |
16 | // Shuffle logic retrieved from:
17 | // https://stackoverflow.com/questions/37843647/shuffle-array-swift-3/37843901
18 |
19 | // Empty and single-element collections don't shuffle
20 | if count < 2 { return }
21 |
22 | // Shuffle them
23 | for i in indices.dropLast() {
24 | let diff = distance(from: i, to: endIndex)
25 | let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff))))
26 | swapAt(i, j)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/PlayingCardDeck.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayingCardDeck.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a deck of playing cards
12 | ///
13 | struct PlayingCardDeck {
14 |
15 | ///
16 | /// Create a new deck of cards
17 | ///
18 | init() {
19 | for suit in PlayingCard.Suit.all {
20 | for rank in PlayingCard.Rank.all {
21 | cards.append(PlayingCard(suit: suit, rank: rank))
22 | }
23 | }
24 | }
25 |
26 | ///
27 | /// The collection of cards
28 | ///
29 | private(set) var cards = [PlayingCard]()
30 |
31 | ///
32 | /// Draw a card from the deck
33 | ///
34 | mutating func draw() -> PlayingCard? {
35 | // If there are cards, return a random one
36 | if cards.count > 0 {
37 | return cards.remove(at: cards.count.arc4random)
38 | }
39 | // No more cards available
40 | return nil
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/PlayingCardDeck.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayingCardDeck.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a deck of playing cards
12 | ///
13 | struct PlayingCardDeck {
14 |
15 | ///
16 | /// Create a new deck of cards
17 | ///
18 | init() {
19 | for suit in PlayingCard.Suit.all {
20 | for rank in PlayingCard.Rank.all {
21 | cards.append(PlayingCard(suit: suit, rank: rank))
22 | }
23 | }
24 | }
25 |
26 | ///
27 | /// The collection of cards
28 | ///
29 | private(set) var cards = [PlayingCard]()
30 |
31 | ///
32 | /// Draw a card from the deck
33 | ///
34 | mutating func draw() -> PlayingCard? {
35 | // If there are cards, return a random one
36 | if cards.count > 0 {
37 | return cards.remove(at: cards.count.arc4random)
38 | }
39 | // No more cards available
40 | return nil
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Cassini/CassiniTests/CassiniTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CassiniTests.swift
3 | // CassiniTests
4 | //
5 | // Created by Ruben on 1/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Cassini
11 |
12 | class CassiniTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArtTests/EmojiArtTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArtTests.swift
3 | // EmojiArtTests
4 | //
5 | // Created by Ruben on 1/12/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import EmojiArt
11 |
12 | class EmojiArtTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 rubenbaca
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Utilities/UIViewControllerUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewControllerUtilities.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/26/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// Simple but useful utilities for `UIViewController`
12 | ///
13 | extension UIViewController {
14 |
15 | ///
16 | /// The contents of the controller. It is `self` in all cases except for instances of
17 | /// `UINavigationController` where, if present, returns the controller's visible view
18 | /// controller (or self if none is set).
19 | ///
20 | /// This allows for great iphone/ipad compatibillity
21 | /// in just one UI.
22 | ///
23 | var contents: UIViewController {
24 |
25 | // Is this a navigation controller?
26 | if let navigationVC = self as? UINavigationController {
27 | return navigationVC.visibleViewController ?? self
28 | }
29 | else {
30 | return self
31 | }
32 |
33 | // TODO: this could work great with UITabViewController
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Utilities/UIViewControllerUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewControllerUtilities.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/26/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// Simple but useful utilities for `UIViewController`
12 | ///
13 | extension UIViewController {
14 |
15 | ///
16 | /// The contents of the controller. It is `self` in all cases except for instances of
17 | /// `UINavigationController` where, if present, returns the controller's visible view
18 | /// controller (or self if none is set).
19 | ///
20 | /// This allows for great iphone/ipad compatibillity
21 | /// in just one UI.
22 | ///
23 | var contents: UIViewController {
24 |
25 | // Is this a navigation controller?
26 | if let navigationVC = self as? UINavigationController {
27 | return navigationVC.visibleViewController ?? self
28 | }
29 | else {
30 | return self
31 | }
32 |
33 | // TODO: this could work great with UITabViewController
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Cassini/Cassini/DemoURLs.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoURLs.swift
3 | // Cassini
4 | //
5 | // Created by Ruben on 1/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// URL's containing big images.
12 | ///
13 | struct DemoURLs {
14 |
15 | // Stanford's Oval image
16 | static let stanford = Bundle.main.url(forResource: "oval", withExtension: "jpg")
17 |
18 | static var NASA: Dictionary = {
19 | let NASAURLStrings = [
20 | // (This Tesla image takes less time to download)
21 | "Cassini" : "https://insideevs.com/wp-content/uploads/2017/08/3840x2160-White-MS-Snowy-Mountain.jpg",
22 | // "Cassini" : "https://www.jpl.nasa.gov/images/cassini/20090202/pia03883-full.jpg",
23 | "Earth" : "https://www.nasa.gov/sites/default/files/wave_earth_mosaic_3.jpg",
24 | "Saturn" : "https://www.nasa.gov/sites/default/files/saturn_collage.jpg"
25 | ]
26 | var urls = Dictionary()
27 | for (key, value) in NASAURLStrings {
28 | urls[key] = URL(string: value)
29 | }
30 | return urls
31 | }()
32 | }
33 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/GalleryViewController/GalleryViewController+UICollectionViewDelegateFlowLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDelegateFlowLayout.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/19/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Adpot protocol UICollectionViewDelegateFlowLayout:
13 | //
14 | extension GalleryViewController: UICollectionViewDelegateFlowLayout {
15 |
16 | //
17 | // Asks the delegate for the size of the specified item’s cell.
18 | //
19 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
20 |
21 | // Get aspect ratio of the image to display
22 | let ratio = gallery.items[indexPath.item].ratio
23 |
24 | // Height is calculated based on the width and aspect ratio
25 | let height: CGFloat = (cellWidth * CGFloat(ratio.height)) / CGFloat(ratio.width)
26 |
27 | // The cell's size
28 | return CGSize(width: cellWidth, height: height)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/GalleryViewController/GalleryViewController+UICollectionViewDelegateFlowLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDelegateFlowLayout.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/19/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Adpot protocol UICollectionViewDelegateFlowLayout:
13 | //
14 | extension GalleryViewController: UICollectionViewDelegateFlowLayout {
15 |
16 | //
17 | // Asks the delegate for the size of the specified item’s cell.
18 | //
19 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
20 |
21 | // Get aspect ratio of the image to display
22 | let ratio = gallery.items[indexPath.item].ratio
23 |
24 | // Height is calculated based on the width and aspect ratio
25 | let height: CGFloat = (cellWidth * CGFloat(ratio.height)) / CGFloat(ratio.width)
26 |
27 | // The cell's size
28 | return CGSize(width: cellWidth, height: height)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArt/TextFieldCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextFieldCollectionViewCell.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 3/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// CollectionViewCell with an input textField.
12 | ///
13 | class TextFieldCollectionViewCell: UICollectionViewCell, UITextFieldDelegate {
14 |
15 | ///
16 | /// This is called inside `textFieldDidEndEditing`.
17 | ///
18 | /// You may set this to do custom things when the text field ends editing.
19 | ///
20 | var resignationHandler: (()->Void)?
21 |
22 | ///
23 | /// The textField used to get input from the user
24 | ///
25 | @IBOutlet weak var textField: UITextField! {
26 | didSet {
27 | textField.delegate = self
28 | }
29 | }
30 |
31 | ///
32 | /// Text field ended editing
33 | ///
34 | func textFieldDidEndEditing(_ textField: UITextField) {
35 | // If user provided a resignationHandler, call it
36 | resignationHandler?()
37 | }
38 |
39 | ///
40 | /// Text field should return
41 | ///
42 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
43 | textField.resignFirstResponder()
44 | return true
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Settings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Settings.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/21/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | ///
12 | /// Settings for the app
13 | ///
14 | struct Settings {
15 |
16 | ///
17 | /// Do not allow new instances
18 | ///
19 | private init() {}
20 |
21 | ///
22 | /// Contains storyboard segue identifiers
23 | ///
24 | struct StoryboardSegues {
25 |
26 | ///
27 | /// Segue that goes from a gallery item cell, to a item detail controller
28 | ///
29 | static let ShowItem = "ShowItem"
30 |
31 | ///
32 | /// Segue that shows the selected image gallery
33 | ///
34 | static let ShowGallery = "ShowGallery"
35 | }
36 |
37 | ///
38 | /// Contains storyboard identifiers, such as tableView cell identifiers
39 | ///
40 | struct StoryboardIdentifiers {
41 | ///
42 | /// CollectionViewCell that shows a gallery image
43 | ///
44 | static let ImageCell = "ImageCell"
45 |
46 | ///
47 | /// TableViewCell that shows a gallery document
48 | ///
49 | static let DocumentCell = "DocumentCell"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/TextFieldCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextFieldCollectionViewCell.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 3/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// CollectionViewCell with an input textField.
12 | ///
13 | class TextFieldCollectionViewCell: UICollectionViewCell, UITextFieldDelegate {
14 |
15 | ///
16 | /// This is called inside `textFieldDidEndEditing`.
17 | ///
18 | /// You may set this to do custom things when the text field ends editing.
19 | ///
20 | var resignationHandler: (()->Void)?
21 |
22 | ///
23 | /// The textField used to get input from the user
24 | ///
25 | @IBOutlet weak var textField: UITextField! {
26 | didSet {
27 | textField.delegate = self
28 | }
29 | }
30 |
31 | ///
32 | /// Text field ended editing
33 | ///
34 | func textFieldDidEndEditing(_ textField: UITextField) {
35 | // If user provided a resignationHandler, call it
36 | resignationHandler?()
37 | }
38 |
39 | ///
40 | /// Text field should return
41 | ///
42 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
43 | textField.resignFirstResponder()
44 | return true
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Utilities/Settings.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Settings.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/21/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | ///
12 | /// Settings for the app
13 | ///
14 | struct Settings {
15 |
16 | ///
17 | /// Do not allow new instances
18 | ///
19 | private init() {}
20 |
21 | ///
22 | /// Contains storyboard segue identifiers
23 | ///
24 | struct StoryboardSegues {
25 |
26 | ///
27 | /// Segue that goes from a gallery item cell, to a item detail controller
28 | ///
29 | static let ShowItem = "ShowItem"
30 |
31 | ///
32 | /// Segue that shows the selected image gallery
33 | ///
34 | static let ShowGallery = "ShowGallery"
35 | }
36 |
37 | ///
38 | /// Contains storyboard identifiers, such as tableView cell identifiers
39 | ///
40 | struct StoryboardIdentifiers {
41 | ///
42 | /// CollectionViewCell that shows a gallery image
43 | ///
44 | static let ImageCell = "ImageCell"
45 |
46 | ///
47 | /// TableViewCell that shows a gallery document
48 | ///
49 | static let DocumentCell = "DocumentCell"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/GalleryViewController/GalleryViewController+UICollectionViewDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDataSource.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/19/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Conform to `UICollectionViewDataSource`
13 | //
14 | extension GalleryViewController: UICollectionViewDataSource {
15 |
16 | ///
17 | /// Number of items in section
18 | ///
19 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
20 | // How many items does the gallery have?
21 | return gallery.items.count
22 | }
23 |
24 | ///
25 | /// Cell for row at indexPath
26 | ///
27 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
28 |
29 | // Deque reusable cell for an item's cell
30 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Settings.StoryboardIdentifiers.ImageCell, for: indexPath) as! ImageCollectionViewCell
31 |
32 | // Setup the cell
33 | cell.imageURL = gallery.items[indexPath.item].imageURL
34 |
35 | // Return it
36 | return cell
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/GalleryViewController/GalleryViewController+UICollectionViewDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDataSource.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/19/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Conform to `UICollectionViewDataSource`
13 | //
14 | extension GalleryViewController: UICollectionViewDataSource {
15 |
16 | ///
17 | /// Number of items in section
18 | ///
19 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
20 | // How many items does the gallery have?
21 | return gallery.items.count
22 | }
23 |
24 | ///
25 | /// Cell for row at indexPath
26 | ///
27 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
28 |
29 | // Deque reusable cell for an item's cell
30 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Settings.StoryboardIdentifiers.ImageCell, for: indexPath) as! ImageCollectionViewCell
31 |
32 | // Setup the cell
33 | cell.imageURL = gallery.items[indexPath.item].imageURL
34 |
35 | // Return it
36 | return cell
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Cassini/CassiniUITests/CassiniUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CassiniUITests.swift
3 | // CassiniUITests
4 | //
5 | // Created by Ruben on 1/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class CassiniUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArtUITests/EmojiArtUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArtUITests.swift
3 | // EmojiArtUITests
4 | //
5 | // Created by Ruben on 1/12/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class EmojiArtUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/EmojiArt.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArt.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 3/9/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | ///
12 | /// Model an EmojiArt. Composed of an URL image for the background and a bunch of emojis/label
13 | /// added into it with a respective size and location.
14 | ///
15 | struct EmojiArt: Codable {
16 |
17 | ///
18 | /// URL for the background image
19 | ///
20 | var url: URL
21 |
22 | ///
23 | /// The emojis that are dropped into the docuemnt
24 | ///
25 | var emojis: [EmojiInfo] = []
26 |
27 | ///
28 | /// Represents a dropped emoji: location, text and size
29 | ///
30 | struct EmojiInfo: Codable {
31 | let x: Int
32 | let y: Int
33 | let text: String
34 | let size: Int
35 | }
36 |
37 | ///
38 | /// Create new EmojiArt with given URL (should be an image URL), and a bunch of emojis
39 | ///
40 | init(url: URL, emojis: [EmojiInfo]) {
41 | self.url = url
42 | self.emojis = emojis
43 | }
44 |
45 | ///
46 | /// JSON Data representing the current object.
47 | ///
48 | var json: Data? {
49 | return try? JSONEncoder().encode(self)
50 | }
51 |
52 | ///
53 | /// Create object from given JSON Data.
54 | ///
55 | init?(json: Data) {
56 | if let newValue = try? JSONDecoder().decode(EmojiArt.self, from: json) {
57 | self = newValue
58 | }
59 | else {
60 | return nil
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Cassini/Cassini/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/ImageGallery.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageGallery.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a gallery of "images". It does not store images per se,
12 | /// just an URL where the image is retrieved from, as well as the aspect
13 | /// ratio of such image.
14 | ///
15 | class ImageGallery {
16 |
17 | ///
18 | /// Create new gallery with the given `name` and `items`
19 | ///
20 | init(name: String, items: [Item]) {
21 | self.name = name
22 | self.items = items
23 | }
24 |
25 | ///
26 | /// Create empty gallery with default name and no items
27 | ///
28 | init() {}
29 |
30 | ///
31 | /// Represents an item in the gallery.
32 | ///
33 | struct Item {
34 |
35 | ///
36 | /// URL where the image is to be retrieved
37 | ///
38 | var imageURL: URL
39 |
40 | ///
41 | /// The aspect ratio of the image
42 | ///
43 | var ratio: AspectRatio
44 | }
45 |
46 | ///
47 | /// Provides width and height aspect ratio. (i.e. 16:9, 4:3, etc.)
48 | ///
49 | struct AspectRatio {
50 | ///
51 | /// Width
52 | ///
53 | var width: Int
54 |
55 | ///
56 | /// Height
57 | ///
58 | var height: Int
59 | }
60 |
61 | ///
62 | /// The name of the gallery
63 | ///
64 | var name: String = "Untitled"
65 |
66 | ///
67 | /// List of items in the gallery
68 | ///
69 | var items = [Item]()
70 | }
71 |
--------------------------------------------------------------------------------
/Set/Set/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UIStatusBarHidden
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationPortraitUpsideDown
35 | UIInterfaceOrientationLandscapeLeft
36 | UIInterfaceOrientationLandscapeRight
37 |
38 | UISupportedInterfaceOrientations~ipad
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationPortraitUpsideDown
42 | UIInterfaceOrientationLandscapeLeft
43 | UIInterfaceOrientationLandscapeRight
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/ImageGallery.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageGallery.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a gallery of "images". It does not store images per se,
12 | /// just an URL where the image is retrieved from, as well as the aspect
13 | /// ratio of such image.
14 | ///
15 | class ImageGallery: Codable {
16 |
17 | ///
18 | /// Create new gallery with the given `name` and `items`
19 | ///
20 | init(name: String, items: [Item]) {
21 | self.name = name
22 | self.items = items
23 | }
24 |
25 | ///
26 | /// Create empty gallery with default name and no items
27 | ///
28 | init() {}
29 |
30 | ///
31 | /// Represents an item in the gallery.
32 | ///
33 | struct Item: Codable {
34 |
35 | ///
36 | /// URL where the image is to be retrieved
37 | ///
38 | var imageURL: URL
39 |
40 | ///
41 | /// The aspect ratio of the image
42 | ///
43 | var ratio: AspectRatio
44 | }
45 |
46 | ///
47 | /// Provides width and height aspect ratio. (i.e. 16:9, 4:3, etc.)
48 | ///
49 | struct AspectRatio: Codable {
50 | ///
51 | /// Width
52 | ///
53 | var width: Int
54 |
55 | ///
56 | /// Height
57 | ///
58 | var height: Int
59 | }
60 |
61 | ///
62 | /// The name of the gallery
63 | ///
64 | var name: String = "Untitled"
65 |
66 | ///
67 | /// List of items in the gallery
68 | ///
69 | var items = [Item]()
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArt/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | NSAppTransportSecurity
38 |
39 | NSAllowsArbitraryLoads
40 |
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Card.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Card.swift
3 | // Concentration
4 | //
5 | // Created by Ruben on 11/30/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a "Card" that is used in the "Concentration" game
12 | ///
13 | struct Card: Hashable {
14 |
15 | /// To conform to `Hashable` protocol
16 | var hashValue: Int { return identifier }
17 |
18 | /// To conform to `Equatable` protocol inherited form `Hashable`
19 | static func ==(lhs: Card, rhs: Card) -> Bool {
20 | return lhs.identifier == rhs.identifier
21 | }
22 |
23 | ///
24 | /// Is the current card facing up?
25 | ///
26 | var isFaceUp = false
27 |
28 | ///
29 | /// Is the current card already matched?
30 | ///
31 | /// A matched card means that the user playing the game already
32 | /// found both "matching" cards.
33 | ///
34 | var isMatched = false
35 |
36 | ///
37 | /// A unique identifier for the card.
38 | /// (The pair of matching cards have the same identifier)
39 | ///
40 | private var identifier: Int
41 |
42 | ///
43 | /// Create a card with the given identifier
44 | ///
45 | init() {
46 | self.identifier = Card.getUniqueIdentifier()
47 | }
48 |
49 | ///
50 | /// Static identifier that is increased every time a new one is
51 | /// requested by getUniqueIdentifier()
52 | ///
53 | private static var identifierFactory = 0
54 |
55 | ///
56 | /// Returns a unique id to be used as a card identifier
57 | ///
58 | private static func getUniqueIdentifier() -> Int {
59 | Card.identifierFactory += 1
60 | return Card.identifierFactory
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | NSAppTransportSecurity
38 |
39 | NSAllowsArbitraryLoads
40 |
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/EmojiArt/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Set/Set/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Cassini/Cassini/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Supporting Files/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Cassini/Cassini/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/Concentration/Concentration/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/EmojiArt/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Set/Set/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/GalleryViewController/GalleryViewController+UICollectionViewDragDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDragDelegate.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Adopt `UICollectionViewDragDelegate`:
13 | //
14 | // "The interface for initiating drags from a collection view."
15 | //
16 | extension GalleryViewController: UICollectionViewDragDelegate {
17 |
18 | //
19 | // Provide items to begin a drag associated with a given indexPath.
20 | // If an empty array is returned a drag session will not begin.
21 | //
22 | func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
23 |
24 | // Set local context to the collectionView
25 | session.localContext = collectionView
26 |
27 | // The item being dragged
28 | let item = gallery.items[indexPath.item]
29 |
30 | // For drags outside our app, the URL of the image will be provided
31 | let url = UIDragItem(itemProvider: NSItemProvider(object: item.imageURL as NSURL))
32 |
33 | // For local drags, the full `ImageGallery.Item` will be provided
34 | url.localObject = item
35 |
36 | return [url]
37 | }
38 |
39 | func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
40 | // Set local context to the collectionView
41 | session.localContext = collectionView
42 |
43 | // The item being dragged
44 | let item = gallery.items[indexPath.item]
45 |
46 | // For drags outside our app, the URL of the image will be provided
47 | let url = UIDragItem(itemProvider: NSItemProvider(object: item.imageURL as NSURL))
48 |
49 | // For local drags, the full `ImageGallery.Item` will be provided
50 | url.localObject = item
51 |
52 | return [url]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/EmojiArtDocument.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArtDocument.swift
3 | // EmojiArtL14
4 | //
5 | // Created by Ruben on 3/9/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// A `UIDocument` representing an EmojiArt document.
13 | ///
14 | class EmojiArtDocument: UIDocument {
15 |
16 | // Model: EmojiArt
17 | var emojiArt: EmojiArt?
18 |
19 | // Thumbnail image representing the document (i.e. icon that shows in the Files app)
20 | var thumbnail: UIImage?
21 |
22 | //
23 | // Override this method to return the document data to be saved.
24 | // Note: this method returns `Any` in case you want to return a `FileWrapper` instead of `Data`
25 | //
26 | override func contents(forType typeName: String) throws -> Any {
27 | return emojiArt?.json ?? Data()
28 | }
29 |
30 | //
31 | // Override this method to load the document data into the app’s data model.
32 | //
33 | override func load(fromContents contents: Any, ofType typeName: String?) throws {
34 | // Check if the contents passed to us are actually of type Data
35 | if let json = contents as? Data {
36 | emojiArt = EmojiArt(json: json)
37 | }
38 | else {
39 | print("Error trying to load EmojiArtDocument. Content is not JSON data")
40 | }
41 | }
42 |
43 | //
44 | // Returns a dictionary of file attributes to associate with the document file when writing
45 | // or updating it.
46 | //
47 | // We're overriding this to add a custom thumbnail image that represents our document.
48 | //
49 | override func fileAttributesToWrite(to url: URL, for saveOperation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] {
50 | var attributes = try super.fileAttributesToWrite(to: url, for: saveOperation)
51 | if let thumbnail = self.thumbnail {
52 | // Add our ustom thumbnail image
53 | attributes[URLResourceKey.thumbnailDictionaryKey] = [URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey:thumbnail]
54 | }
55 | return attributes
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/GalleryViewController/GalleryViewController+UICollectionViewDragDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController+UICollectionViewDragDelegate.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //
12 | // Adopt `UICollectionViewDragDelegate`:
13 | //
14 | // "The interface for initiating drags from a collection view."
15 | //
16 | extension GalleryViewController: UICollectionViewDragDelegate {
17 |
18 | //
19 | // Provide items to begin a drag associated with a given indexPath.
20 | // If an empty array is returned a drag session will not begin.
21 | //
22 | func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
23 |
24 | // Set local context to the collectionView
25 | session.localContext = collectionView
26 |
27 | // The item being dragged
28 | let item = gallery.items[indexPath.item]
29 |
30 | // For drags outside our app, the URL of the image will be provided
31 | let url = UIDragItem(itemProvider: NSItemProvider(object: item.imageURL as NSURL))
32 |
33 | // For local drags, the full `ImageGallery.Item` will be provided
34 | url.localObject = item
35 |
36 | return [url]
37 | }
38 |
39 | func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
40 | // Set local context to the collectionView
41 | session.localContext = collectionView
42 |
43 | // The item being dragged
44 | let item = gallery.items[indexPath.item]
45 |
46 | // For drags outside our app, the URL of the image will be provided
47 | let url = UIDragItem(itemProvider: NSItemProvider(object: item.imageURL as NSURL))
48 |
49 | // For local drags, the full `ImageGallery.Item` will be provided
50 | url.localObject = item
51 |
52 | return [url]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Cassini/Cassini/CassiniViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CassiniViewController.swift
3 | // Cassini
4 | //
5 | // Created by Ruben Baca on 1/7/18.
6 | // Copyright © 2018 Ruben Baca. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// Controller that allows user to select a Cassini image.
12 | ///
13 | class CassiniViewController: UIViewController {
14 |
15 | // MARK: - Navigation
16 |
17 | // In a storyboard-based application, you will often want to do a little
18 | // preparation before navigation
19 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
20 |
21 | // We prepare the image based on the segue's identifier
22 | guard let identifier = segue.identifier else {
23 | return // expected a valid identifier
24 | }
25 |
26 | // Destination must be an ImageViewController
27 | guard let imageViewController = segue.destination.contents as? ImageViewController else {
28 | return // expected a segue to ImageViewController class
29 | }
30 |
31 | // Setup destination's model (URL) and title
32 | imageViewController.imageURL = DemoURLs.NASA[identifier]
33 | imageViewController.title = (sender as? UIButton)?.currentTitle ?? "?"
34 | }
35 |
36 | }
37 |
38 | ///
39 | /// Simple but useful utilities for `UIViewController`
40 | ///
41 | extension UIViewController {
42 |
43 | ///
44 | /// The contents of the controller. It is `self` in all cases except for instances of
45 | /// `UINavigationController` where, if present, returns the controller's visible view
46 | /// controller (or self if none is set).
47 | ///
48 | /// This allows for great iphone/ipad compatibillity
49 | /// in just one UI.
50 | ///
51 | var contents: UIViewController {
52 |
53 | // Is this a navigation controller?
54 | if let navigationVC = self as? UINavigationController {
55 | return navigationVC.visibleViewController ?? self
56 | }
57 | else {
58 | return self
59 | }
60 |
61 | // TODO: this could work great with UITabViewController
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDocumentTypes
8 |
9 |
10 | CFBundleTypeIconFiles
11 |
12 | CFBundleTypeName
13 | JSON
14 | CFBundleTypeRole
15 | Viewer
16 | LSHandlerRank
17 | Alternate
18 | LSItemContentTypes
19 |
20 | public.json
21 |
22 |
23 |
24 | CFBundleExecutable
25 | $(EXECUTABLE_NAME)
26 | CFBundleIdentifier
27 | $(PRODUCT_BUNDLE_IDENTIFIER)
28 | CFBundleInfoDictionaryVersion
29 | 6.0
30 | CFBundleName
31 | $(PRODUCT_NAME)
32 | CFBundlePackageType
33 | APPL
34 | CFBundleShortVersionString
35 | 1.0
36 | CFBundleVersion
37 | 1
38 | LSRequiresIPhoneOS
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIMainStoryboardFile
43 | Main
44 | UIRequiredDeviceCapabilities
45 |
46 | armv7
47 |
48 | UISupportedInterfaceOrientations
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationLandscapeLeft
52 | UIInterfaceOrientationLandscapeRight
53 |
54 | UISupportedInterfaceOrientations~ipad
55 |
56 | UIInterfaceOrientationPortrait
57 | UIInterfaceOrientationPortraitUpsideDown
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationLandscapeRight
60 |
61 | UISupportsDocumentBrowser
62 |
63 | UTImportedTypeDeclarations
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// Main view controller
12 | ///
13 | class ViewController: UIViewController {
14 |
15 | ///
16 | /// The deck of cards (model)
17 | ///
18 | var deck = PlayingCardDeck()
19 |
20 | ///
21 | /// The playing card view (view)
22 | ///
23 | @IBOutlet weak var playingCardView: PlayingCardView! {
24 | didSet { setupGestureRecognizers() }
25 | }
26 |
27 | ///
28 | /// Flip the card
29 | ///
30 | @IBAction func flipCard(_ sender: UITapGestureRecognizer) {
31 | // Make sure tap was successful
32 | if sender.state == .ended {
33 | playingCardView.isFaceUp = !playingCardView.isFaceUp
34 | }
35 | }
36 |
37 | ///
38 | /// Get the next card on the deck
39 | ///
40 | @objc private func nextCard() {
41 | // Try to draw a card
42 | if let card = deck.draw() {
43 | // Configure the view to show the new card
44 | playingCardView.rank = card.rank.order
45 | playingCardView.suit = card.suit.rawValue
46 | }
47 | }
48 |
49 | ///
50 | /// Setup gesture recognizers on the playing card:
51 | /// - Swipe: Go to next card in the deck
52 | /// - Pinch: Zoom the card's face
53 | ///
54 | /// Note: Tap gesture recognizer (to flip the card) was added
55 | /// using interface builder.
56 | ///
57 | private func setupGestureRecognizers() {
58 | // Swipe gesture recognizer to go to next card
59 | let swipe = UISwipeGestureRecognizer(target: self, action: #selector(nextCard))
60 | swipe.direction = [.left, .right]
61 | playingCardView.addGestureRecognizer(swipe)
62 |
63 | // Pinch gesture recognizer to zoom the card's face
64 | let pinch = UIPinchGestureRecognizer(
65 | target: playingCardView,
66 | action: #selector(playingCardView.adjustFaceCardScale(gestureRecognizer:))
67 | )
68 | playingCardView.addGestureRecognizer(pinch)
69 | }
70 |
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/Set/Set/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Set
4 | //
5 | // Created by Ruben on 12/7/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/EmojiArt/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 1/12/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Cassini/Cassini/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Cassini
4 | //
5 | // Created by Ruben on 1/6/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Set/Set/Card.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Card.swift
3 | // Set
4 | //
5 | // Created by Ruben on 12/7/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a Card used in the `SetGame`
12 | ///
13 | struct Card {
14 |
15 | ///
16 | /// There are 4 different features a card might have. Each feature's value might vary based
17 | /// on the `Variant` options.
18 | ///
19 | /// These features and variants are completely generic and not tied to any specific ones. For
20 | /// instance, a "classic" game would contain:
21 | /// - Feature1: color
22 | /// - Feature2: shape
23 | /// - Feature3: shade
24 | /// - Feature4: number
25 | ///
26 | init(_ feature1: Variant, _ feature2: Variant, _ feature3: Variant, _ feature4: Variant) {
27 | self.feature1 = feature1
28 | self.feature2 = feature2
29 | self.feature3 = feature3
30 | self.feature4 = feature4
31 | }
32 |
33 | // Assignment 2 (Task #13): "13.Use an enum as a meaningful part of your solution."
34 |
35 | ///
36 | /// Each feature might contain one of three different variants.
37 | ///
38 | /// These variants are completely generic and not tied to any specific ones.
39 | ///
40 | enum Variant: Int {
41 | case v1 = 1
42 | case v2 = 2
43 | case v3 = 3
44 | }
45 |
46 | let feature1: Variant
47 | let feature2: Variant
48 | let feature3: Variant
49 | let feature4: Variant
50 | }
51 |
52 | // Conform to `CustomStringConvertible`
53 | extension Card: CustomStringConvertible {
54 | var description: String {
55 | return "[\(feature1.rawValue), \(feature2.rawValue), \(feature3.rawValue), \(feature4.rawValue)]"
56 | }
57 | }
58 |
59 | // Conform to `Equatable`
60 | extension Card: Equatable {
61 | static func ==(lhs: Card, rhs: Card) -> Bool {
62 | return (
63 | (lhs.feature1 == rhs.feature1) &&
64 | (lhs.feature2 == rhs.feature2) &&
65 | (lhs.feature3 == rhs.feature3) &&
66 | (lhs.feature4 == rhs.feature4)
67 | )
68 | }
69 | }
70 |
71 | // Conform to `Hashable`
72 | extension Card: Hashable {
73 | var hashValue: Int {
74 | return feature1.rawValue ^ feature2.rawValue ^ feature3.rawValue ^ feature4.rawValue
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Concentration/Concentration/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Concentration
4 | //
5 | // Created by Ruben on 11/29/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/17/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | CFBundleDevelopmentRegion
11 | $(DEVELOPMENT_LANGUAGE)
12 | CFBundleDocumentTypes
13 |
14 |
15 | CFBundleTypeIconFiles
16 |
17 | CFBundleTypeName
18 | ImageGallery
19 | CFBundleTypeRole
20 | Editor
21 | LSHandlerRank
22 | Owner
23 | LSItemContentTypes
24 |
25 | com.rubenbaca.imgallery
26 |
27 |
28 |
29 | CFBundleExecutable
30 | $(EXECUTABLE_NAME)
31 | CFBundleIdentifier
32 | $(PRODUCT_BUNDLE_IDENTIFIER)
33 | CFBundleInfoDictionaryVersion
34 | 6.0
35 | CFBundleName
36 | $(PRODUCT_NAME)
37 | CFBundlePackageType
38 | APPL
39 | CFBundleShortVersionString
40 | 1.0
41 | CFBundleVersion
42 | 1
43 | LSRequiresIPhoneOS
44 |
45 | UILaunchStoryboardName
46 | LaunchScreen
47 | UIMainStoryboardFile
48 | Main
49 | UIRequiredDeviceCapabilities
50 |
51 | armv7
52 |
53 | UISupportedInterfaceOrientations
54 |
55 | UIInterfaceOrientationPortrait
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 | UISupportedInterfaceOrientations~ipad
60 |
61 | UIInterfaceOrientationPortrait
62 | UIInterfaceOrientationPortraitUpsideDown
63 | UIInterfaceOrientationLandscapeLeft
64 | UIInterfaceOrientationLandscapeRight
65 |
66 | UISupportsDocumentBrowser
67 |
68 | UTExportedTypeDeclarations
69 |
70 |
71 | UTTypeConformsTo
72 |
73 | public.data
74 | public.content
75 |
76 | UTTypeDescription
77 | ImageGallery
78 | UTTypeIdentifier
79 | com.rubenbaca.imgallery
80 | UTTypeTagSpecification
81 |
82 | public.filename-extension
83 |
84 | imgallery
85 |
86 |
87 |
88 |
89 | UTImportedTypeDeclarations
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/PlayingCard/PlayingCard/PlayingCard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayingCard.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a playing card
12 | ///
13 | struct PlayingCard {
14 |
15 | /// Suit of the card
16 | var suit: Suit
17 |
18 | /// Rank of the card
19 | var rank: Rank
20 |
21 | ///
22 | /// Represents a Suit in a playing card
23 | ///
24 | enum Suit: String {
25 | case spades = "♠️"
26 | case hearts = "♥️"
27 | case clubs = "♣️"
28 | case diamonds = "♦️"
29 |
30 | ///
31 | /// Array containing all possible suits
32 | ///
33 | static var all: [Suit] = [.spades, .hearts, .clubs, .diamonds]
34 | }
35 |
36 | ///
37 | /// Represents the Rank in a playing card
38 | ///
39 | enum Rank {
40 | case ace
41 | case face(String) // ugly design
42 | case numeric(Int)
43 |
44 | ///
45 | /// The order of each Rank
46 | ///
47 | var order: Int {
48 | switch self {
49 | case .ace: return 1
50 | case .numeric(let pips): return pips
51 | case .face(let kind) where kind == "J": return 11
52 | case .face(let kind) where kind == "Q": return 12
53 | case .face(let kind) where kind == "K": return 13
54 | default: return 0 // ugly design
55 | }
56 | }
57 |
58 | ///
59 | /// Array containing all possible suits
60 | ///
61 | static var all: [Rank] {
62 | // Ace
63 | var allRanks: [Rank] = [.ace]
64 |
65 | // 2...10
66 | for pips in 2...10 {
67 | allRanks.append(.numeric(pips))
68 | }
69 |
70 | // Jack, Queen, King
71 | allRanks += [.face("J"), .face("Q"), .face("K")]
72 | return allRanks
73 | }
74 | }
75 | }
76 |
77 | // Make `PlayingCard` confrom to `CustomStringConvertible`
78 | extension PlayingCard: CustomStringConvertible {
79 | ///
80 | /// String representation of a `PlayingCard`
81 | ///
82 | var description: String {
83 | return "\(rank)\(suit)"
84 | }
85 | }
86 |
87 | // Make `PlayingCard.Suit` confrom to `CustomStringConvertible`
88 | extension PlayingCard.Suit: CustomStringConvertible {
89 | ///
90 | /// String representation of a `PlayingCard.Suit`
91 | ///
92 | var description: String {
93 | return rawValue
94 | }
95 | }
96 |
97 | // Make `PlayingCard.Rank` confrom to `CustomStringConvertible`
98 | extension PlayingCard.Rank: CustomStringConvertible {
99 | ///
100 | /// String representation of a `PlayingCard.Rank`
101 | ///
102 | var description: String {
103 | switch self {
104 | case .ace: return "A"
105 | case .numeric(let pips): return String(pips)
106 | case .face(let kind): return kind
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/PlayingCard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlayingCard.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/3/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import Foundation
9 |
10 | ///
11 | /// Represents a playing card
12 | ///
13 | struct PlayingCard {
14 |
15 | /// Suit of the card
16 | var suit: Suit
17 |
18 | /// Rank of the card
19 | var rank: Rank
20 |
21 | ///
22 | /// Represents a Suit in a playing card
23 | ///
24 | enum Suit: String {
25 | case spades = "♠️"
26 | case hearts = "♥️"
27 | case clubs = "♣️"
28 | case diamonds = "♦️"
29 |
30 | ///
31 | /// Array containing all possible suits
32 | ///
33 | static var all: [Suit] = [.spades, .hearts, .clubs, .diamonds]
34 | }
35 |
36 | ///
37 | /// Represents the Rank in a playing card
38 | ///
39 | enum Rank {
40 | case ace
41 | case face(String) // ugly design
42 | case numeric(Int)
43 |
44 | ///
45 | /// The order of each Rank
46 | ///
47 | var order: Int {
48 | switch self {
49 | case .ace: return 1
50 | case .numeric(let pips): return pips
51 | case .face(let kind) where kind == "J": return 11
52 | case .face(let kind) where kind == "Q": return 12
53 | case .face(let kind) where kind == "K": return 13
54 | default: return 0 // ugly design
55 | }
56 | }
57 |
58 | ///
59 | /// Array containing all possible suits
60 | ///
61 | static var all: [Rank] {
62 | // Ace
63 | var allRanks: [Rank] = [.ace]
64 |
65 | // 2...10
66 | for pips in 2...10 {
67 | allRanks.append(.numeric(pips))
68 | }
69 |
70 | // Jack, Queen, King
71 | allRanks += [.face("J"), .face("Q"), .face("K")]
72 | return allRanks
73 | }
74 | }
75 | }
76 |
77 | // Make `PlayingCard` confrom to `CustomStringConvertible`
78 | extension PlayingCard: CustomStringConvertible {
79 | ///
80 | /// String representation of a `PlayingCard`
81 | ///
82 | var description: String {
83 | return "\(rank)\(suit)"
84 | }
85 | }
86 |
87 | // Make `PlayingCard.Suit` confrom to `CustomStringConvertible`
88 | extension PlayingCard.Suit: CustomStringConvertible {
89 | ///
90 | /// String representation of a `PlayingCard.Suit`
91 | ///
92 | var description: String {
93 | return rawValue
94 | }
95 | }
96 |
97 | // Make `PlayingCard.Rank` confrom to `CustomStringConvertible`
98 | extension PlayingCard.Rank: CustomStringConvertible {
99 | ///
100 | /// String representation of a `PlayingCard.Rank`
101 | ///
102 | var description: String {
103 | switch self {
104 | case .ace: return "A"
105 | case .numeric(let pips): return String(pips)
106 | case .face(let kind): return kind
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // EmojiArtL14
4 | //
5 | // Created by Ruben on 3/9/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 | func application(_ app: UIApplication, open inputURL: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
45 | // Ensure the URL is a file URL
46 | guard inputURL.isFileURL else { return false }
47 |
48 | // Reveal / import the document at the URL
49 | guard let documentBrowserViewController = window?.rootViewController as? DocumentBrowserViewController else { return false }
50 |
51 | documentBrowserViewController.revealDocument(at: inputURL, importIfNeeded: true) { (revealedDocumentURL, error) in
52 | if let error = error {
53 | // Handle the error appropriately
54 | print("Failed to reveal the document at URL \(inputURL) with error: '\(error)'")
55 | return
56 | }
57 |
58 | // Present the Document View Controller for the revealed URL
59 | documentBrowserViewController.presentDocument(at: revealedDocumentURL!)
60 | }
61 |
62 | return true
63 | }
64 |
65 |
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ImageGallery_P6
4 | //
5 | // Created by Ruben on 3/16/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 | func application(_ app: UIApplication, open inputURL: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
45 | // Ensure the URL is a file URL
46 | guard inputURL.isFileURL else { return false }
47 |
48 | // Reveal / import the document at the URL
49 | guard let documentBrowserViewController = window?.rootViewController as? DocumentBrowserViewController else { return false }
50 |
51 | documentBrowserViewController.revealDocument(at: inputURL, importIfNeeded: true) { (revealedDocumentURL, error) in
52 | if let error = error {
53 | // Handle the error appropriately
54 | print("Failed to reveal the document at URL \(inputURL) with error: '\(error)'")
55 | return
56 | }
57 |
58 | // Present the Document View Controller for the revealed URL
59 | documentBrowserViewController.presentDocument(at: revealedDocumentURL!)
60 | }
61 |
62 | return true
63 | }
64 |
65 |
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/DocumentBrowser/ImageGalleryDocument.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Document.swift
3 | // ImageGallery_P6
4 | //
5 | // Created by Ruben on 3/16/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// UIDocument that represents an ImageGallery
12 | ///
13 | class ImageGalleryDocument: UIDocument {
14 |
15 | ///
16 | /// The image gallery for the document
17 | ///
18 | var gallery: ImageGallery?
19 |
20 | ///
21 | /// A thumbnail image representing the document. I.e. shown in Finder, as the document's icon
22 | ///
23 | var thumbnail: UIImage?
24 |
25 | //
26 | // Override this method to return the document data to be saved.
27 | //
28 | override func contents(forType typeName: String) throws -> Any {
29 | // Note: this method returns `Any` in case you need to return a FileWrapper. For regular
30 | // documents, returning `Data` is the way to go. Here, we'll return a JSON/Data representation
31 | // of the `ImageGallery`
32 | return try! JSONEncoder().encode(gallery)
33 | }
34 |
35 | //
36 | // Override this method to load the document data into the app’s data model.
37 | //
38 | override func load(fromContents contents: Any, ofType typeName: String?) throws {
39 | // We only support loading `Data`, which should be a JSON representation of an `ImageGallery`
40 | guard let data = contents as? Data else {
41 | // The thing we want to load is not valid Data
42 | throw ImageGalleryDocumentError.dataProblem
43 | }
44 |
45 | // Try to decode the Data as JSON, otherwise, error will be thrown to the caller
46 | gallery = try JSONDecoder().decode(ImageGallery.self, from: data)
47 | }
48 |
49 | //
50 | // Called or overridden to handle an error that occurs during an attempt to read, save, or
51 | // revert a document.
52 | //
53 | override func handleError(_ error: Error, userInteractionPermitted: Bool) {
54 | // TODO: here we would handle any errors thrown
55 | print("--- ERROR: \(error)")
56 | }
57 |
58 | //
59 | // Returns a dictionary of file attributes to associate with the document file when writing
60 | // or updating it.
61 | //
62 | // We're overriding this to add a custom thumbnail image that represents our document.
63 | //
64 | override func fileAttributesToWrite(to url: URL, for saveOperation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] {
65 |
66 | // Get all attributes for the document, so we can add a thumbnail image
67 | var attributes = try super.fileAttributesToWrite(to: url, for: saveOperation)
68 |
69 | // If we have a vaild thumbnail set, use it
70 | if let thumbnail = self.thumbnail {
71 | // Add our ustom thumbnail image
72 | attributes[URLResourceKey.thumbnailDictionaryKey] = [URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey:thumbnail]
73 | }
74 | return attributes
75 | }
76 | }
77 |
78 | ///
79 | /// Possible errors for ImageGalleryDocument operations
80 | ///
81 | enum ImageGalleryDocumentError: Error {
82 | ///
83 | /// Data problem. (i.e. we were asked to open a document with invalid Data)
84 | ///
85 | case dataProblem
86 |
87 | ///
88 | /// Problem decoding the data. (i.e. we got a corrupt/invalid JSON representation)
89 | ///
90 | case decodingProblem(String)
91 | }
92 |
--------------------------------------------------------------------------------
/Lecture8_PlayingCard/PlayingCard/CardBehavior.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardBehavior.swift
3 | // PlayingCard
4 | //
5 | // Created by Ruben on 12/16/17.
6 | // Copyright © 2017 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// Contains UIDynamicBehavior for a PlayingCard
12 | ///
13 | class CardBehavior: UIDynamicBehavior {
14 |
15 | ///
16 | /// Create a new CardBehavior for a PlayingCard
17 | ///
18 | override init() {
19 | super.init()
20 | addChildBehavior(collisionBehavior)
21 | addChildBehavior(itemBehavior)
22 | }
23 |
24 | ///
25 | /// Create a new CardBehavior for a PlayingCard in the given
26 | /// animator
27 | ///
28 | convenience init(in animator: UIDynamicAnimator) {
29 | self.init()
30 | animator.addBehavior(self)
31 | }
32 |
33 | ///
34 | /// Collision behavior
35 | ///
36 | private lazy var collisionBehavior: UICollisionBehavior = {
37 | let behavior = UICollisionBehavior()
38 | behavior.translatesReferenceBoundsIntoBoundary = true
39 | return behavior
40 | }()
41 |
42 | ///
43 | /// Item behavioor
44 | ///
45 | lazy var itemBehavior: UIDynamicItemBehavior = {
46 | let behavior = UIDynamicItemBehavior()
47 | //behavior.allowsRotation = false // I do want rotation
48 | behavior.elasticity = 1.0
49 | behavior.resistance = 0
50 | return behavior
51 | }()
52 |
53 | ///
54 | /// Make sure the given item is affected by all types of CardBehavior
55 | ///
56 | func addItem(_ item: UIDynamicItem) {
57 | collisionBehavior.addItem(item)
58 | itemBehavior.addItem(item)
59 | push(item)
60 | }
61 |
62 | ///
63 | /// Remove the give item from all types of CardBehavior
64 | ///
65 | func removeItem(_ item: UIDynamicItem) {
66 | collisionBehavior.removeItem(item)
67 | itemBehavior.removeItem(item)
68 | }
69 |
70 | ///
71 | /// Intantly push the item towards the center of the current bounds
72 | ///
73 | private func push(_ item: UIDynamicItem) {
74 |
75 | let push = UIPushBehavior(items: [item], mode: .instantaneous)
76 |
77 | // Push item towards the center
78 | if let referenceBounds = dynamicAnimator?.referenceView?.bounds {
79 | let center = CGPoint(x: referenceBounds.midX, y: referenceBounds.midY)
80 | switch (item.center.x, item.center.y) {
81 | case let (x, y) where x < center.x && y < center.y:
82 | push.angle = (CGFloat.pi/2).arc4random
83 | case let (x, y) where x > center.x && y < center.y:
84 | push.angle = CGFloat.pi-(CGFloat.pi/2).arc4random
85 | case let (x, y) where x < center.x && y > center.y:
86 | push.angle = (-CGFloat.pi/2).arc4random
87 | case let (x, y) where x > center.x && y > center.y:
88 | push.angle = CGFloat.pi+(CGFloat.pi/2).arc4random
89 | default:
90 | push.angle = (CGFloat.pi*2).arc4random
91 | }
92 | }
93 |
94 | push.magnitude = CGFloat(1) + CGFloat(2).arc4random
95 |
96 | // After item is pushed, we no longer need it
97 | push.action = { [unowned push, weak self] in
98 | self?.removeChildBehavior(push)
99 | }
100 | addChildBehavior(push)
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArt/EmojiArtDocumentTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArtDocumentTableViewController.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 1/12/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// Controller for handling emoji-art documents
13 | ///
14 | class EmojiArtDocumentTableViewController: UITableViewController {
15 |
16 | // MARK: Model - List of documents represented as strings
17 | var emojiArtDocuments = ["One", "Two", "Three"]
18 |
19 | // MARK: - Table view data source
20 |
21 | ///
22 | /// Number of sections in the table view
23 | ///
24 | override func numberOfSections(in tableView: UITableView) -> Int {
25 | return 1
26 | }
27 |
28 | ///
29 | /// Number of rows in the table view
30 | ///
31 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
32 | // One row for each element in the emojiArtDocuments array
33 | return emojiArtDocuments.count
34 | }
35 |
36 | ///
37 | /// Get the tableView cell for the given indexPath
38 | ///
39 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
40 | // Reusable cell to populate
41 | let cell = tableView.dequeueReusableCell(withIdentifier: "DocumentCell", for: indexPath)
42 |
43 | // Setup the cell's content
44 | cell.textLabel?.text = emojiArtDocuments[indexPath.row]
45 |
46 | // Return the cell
47 | return cell
48 | }
49 |
50 |
51 | ///
52 | /// Override to support conditional editing of the table view. (i.e. swipe to delete)
53 | ///
54 | override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
55 | // Return false if you do not want the specified item to be editable.
56 | return true
57 | }
58 |
59 | ///
60 | /// Override to support editing the table view.
61 | ///
62 | override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
63 | // Delete
64 | if editingStyle == .delete {
65 | // Update model (delete record)
66 | emojiArtDocuments.remove(at: indexPath.row)
67 |
68 | // Delete the row from the data source
69 | tableView.deleteRows(at: [indexPath], with: .fade)
70 | }
71 | }
72 |
73 | ///
74 | /// Add a new document with an auto-generated name
75 | ///
76 | @IBAction func newEmojiArt(_ sender: UIBarButtonItem) {
77 | // Add a new document to the model (with auto-generated name)
78 | emojiArtDocuments.append("Document".madeUnique(withRespectTo: emojiArtDocuments))
79 |
80 | // Reload tableView
81 | tableView.reloadData()
82 | }
83 |
84 | //
85 | // Called to notify the view controller that its view is about to layout its subviews.
86 | //
87 | override func viewWillLayoutSubviews() {
88 | super.viewWillLayoutSubviews()
89 |
90 | // Make sure the split-view controller's diplay mode is the one we want.
91 | if splitViewController?.preferredDisplayMode != .primaryOverlay {
92 | // The primary view controller is layered on top of the secondary view controller,
93 | // leaving the secondary view controller partially visible.
94 | splitViewController?.preferredDisplayMode = .primaryOverlay
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/DocumentBrowser/DocumentBrowserViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentBrowserViewController.swift
3 | // ImageGallery_P6
4 | //
5 | // Created by Ruben on 3/16/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
12 |
13 | //
14 | // View did load
15 | //
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 |
19 | // Setup view controller
20 | delegate = self
21 | allowsDocumentCreation = true
22 | allowsPickingMultipleItems = false
23 | }
24 |
25 |
26 | // MARK: UIDocumentBrowserViewControllerDelegate
27 |
28 | //
29 | // Asks the delegate to create a new document.
30 | //
31 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {
32 |
33 | // To create a new document, we'll use the "Gallery.imgallery" template that ships with the app
34 | let newDocumentURL: URL = Bundle.main.url(forResource: "Gallery", withExtension: "imgallery")!
35 |
36 | // Call handler that imports the document with the given URL
37 | importHandler(newDocumentURL, .copy)
38 | }
39 |
40 | //
41 | // Tells the delegate that the user has selected one or more documents.
42 | //
43 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {
44 |
45 | // Make sure we have a valid URL (we only support picking one document at a time)
46 | guard let sourceURL = documentURLs.first else { return }
47 |
48 | // Present the Document View Controller for the document that was picked.
49 | presentDocument(at: sourceURL)
50 | }
51 |
52 | //
53 | // Tells the delegate that a document has been successfully imported.
54 | //
55 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {
56 | // Present the Document View Controller for the new newly created document
57 | presentDocument(at: destinationURL)
58 | }
59 |
60 | //
61 | // Tells the delegate that the document browser failed to import the specified document.
62 | //
63 | func documentBrowser(_ controller: UIDocumentBrowserViewController, failedToImportDocumentAt documentURL: URL, error: Error?) {
64 | // TODO: we should display a message to the user here
65 | print("==== FAILED")
66 | }
67 |
68 | // MARK: Document Presentation
69 |
70 | //
71 | // Present document for the given url
72 | //
73 | func presentDocument(at documentURL: URL) {
74 |
75 | // We'll get a view controller from the `Main` storyboard
76 | let storyBoard = UIStoryboard(name: "Main", bundle: nil)
77 |
78 | // Our gallery view controller is embedded in a navigation controller
79 | let navigationVC = storyBoard.instantiateViewController(withIdentifier: "GalleryControllerEntry") as! UINavigationController
80 | let documentViewController = navigationVC.contents as! GalleryViewController
81 |
82 | // Setup/prepare VC before presenting it
83 | documentViewController.document = ImageGalleryDocument(fileURL: documentURL)
84 |
85 | // Present the navigation VC to the user
86 | present(navigationVC, animated: true, completion: nil)
87 | }
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/EmojiArt/EmojiArt/EmojiArtView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmojiArtView.swift
3 | // EmojiArt
4 | //
5 | // Created by Ruben on 1/12/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// View for EmojiArt. Contains/shows the given image.
13 | ///
14 | class EmojiArtView: UIView {
15 |
16 | ///
17 | /// The background image
18 | ///
19 | var backgroundImage: UIImage? {
20 | didSet {
21 | // When image is set, we need to re-draw ourselves
22 | setNeedsDisplay()
23 | }
24 | }
25 |
26 | // Only override draw() if you perform custom drawing.
27 | // An empty implementation adversely affects performance during animation.
28 | override func draw(_ rect: CGRect) {
29 | // Set backgroundImage as the background
30 | backgroundImage?.draw(in: bounds)
31 | }
32 |
33 | // Init with frame
34 | override init(frame: CGRect) {
35 | super.init(frame: frame)
36 | setup()
37 | }
38 |
39 | // Init with coder
40 | required init?(coder aDecoder: NSCoder) {
41 | super.init(coder: aDecoder)
42 | setup()
43 | }
44 |
45 | ///
46 | /// Do initialization setup. Called after init(frame:) and init(coder:)
47 | ///
48 | private func setup() {
49 | // Register `self` to accept drop interactions
50 | addInteraction(UIDropInteraction(delegate: self))
51 | }
52 |
53 | ///
54 | /// Add UILabel with the given `attributedString` and centered at `centerPoint`
55 | ///
56 | private func addLabel(with attributedString: NSAttributedString, centeredAt centerPoint: CGPoint) {
57 | let label = UILabel()
58 |
59 | // Setup label's color, text, size, etc.
60 | label.backgroundColor = .clear
61 | label.attributedText = attributedString
62 | label.sizeToFit()
63 | label.center = centerPoint
64 |
65 | // Add gesture recognizers to the label (i.e. pan to move, pinch to zoom, etc.)
66 | addEmojiArtGestureRecognizers(to: label)
67 |
68 | // Add subview
69 | self.addSubview(label)
70 | }
71 | }
72 |
73 | //
74 | // Make `EmojiArtView` conform to `UIDropInteractionDelegate`
75 | //
76 | extension EmojiArtView: UIDropInteractionDelegate {
77 |
78 | //
79 | // What to do when performing a drop
80 | //
81 | func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
82 | // Copy item(s)
83 | return UIDropProposal(operation: .copy)
84 | }
85 |
86 | //
87 | // Determine if we can accept the given drop/session
88 | //
89 | func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
90 | return session.canLoadObjects(ofClass: NSAttributedString.self)
91 | }
92 |
93 | //
94 | // Perform the given drop
95 | //
96 | func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
97 |
98 | // Process any dropped attributed strings
99 | session.loadObjects(ofClass: NSAttributedString.self) { providers in
100 |
101 | // The location where the drop happens. Used to drop label in correct place
102 | let dropPoint = session.location(in: self)
103 |
104 | // Process each dropped attributed string
105 | for attributedString in providers as? [NSAttributedString] ?? [] {
106 | // Add a label with the dropped string
107 | self.addLabel(with: attributedString, centeredAt: dropPoint)
108 | }
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/ItemViewController/ItemViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemViewController.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// View controller that displays a given `ImageGallery.Item`
12 | ///
13 | class ItemViewController: UIViewController {
14 |
15 | // TODO: Should properly reflect "fetching" and "failed" states as in ImageCollectionViewCell
16 |
17 | // MARK: Public
18 |
19 | ///
20 | /// The image to display
21 | ///
22 | var galleryItem: ImageGallery.Item? {
23 | didSet {
24 | if galleryItem != nil {
25 | fetchImage(galleryItem!.imageURL)
26 | }
27 | }
28 | }
29 |
30 | // MARK: Private
31 |
32 | ///
33 | /// Fetch image using given `url`
34 | ///
35 | private func fetchImage(_ url: URL) {
36 |
37 | // TODO: should show "loading" animation
38 |
39 | DispatchQueue.global(qos: .userInitiated).async {
40 | guard let data = try? Data(contentsOf: url.imageURL) else {
41 | // TODO: should reflect "failed" state
42 | return
43 | }
44 | guard let image = UIImage(data: data) else {
45 | // TODO: should reflect "failed" state
46 | return
47 | }
48 |
49 | DispatchQueue.main.async {
50 | self.imageView = UIImageView(image: image)
51 | }
52 | }
53 | }
54 |
55 | ///
56 | /// The imageView to display
57 | ///
58 | private var imageView: UIImageView? {
59 | didSet {
60 | if imageView != nil {
61 | // Adapt view to fit image
62 | imageView!.sizeToFit()
63 |
64 | // Add imageView to scrollView
65 | scrollView.addSubview(imageView!)
66 |
67 | // Update scrollView accordingly
68 | updateScrollView()
69 | }
70 | else {
71 | // Show a blank screen
72 | scrollView.subviews.forEach { $0.removeFromSuperview() }
73 | }
74 | }
75 | }
76 |
77 | ///
78 | /// Update scrollView to properly fit the image
79 | ///
80 | private func updateScrollView() {
81 |
82 | if imageView != nil {
83 |
84 | // The size of the image
85 | let imageSize = imageView?.image?.size ?? CGSize.zero
86 |
87 | // Size of the display
88 | let displaySize = scrollView.bounds.size
89 |
90 | // Scrollview content-size must fit the image
91 | scrollView.contentSize = imageSize
92 |
93 | // A scale that will fit the whole image on screen
94 | let zoomScaleThatFitsWholeImage = min(displaySize.width/imageSize.width,
95 | displaySize.height/imageSize.height)
96 |
97 | scrollView.minimumZoomScale = zoomScaleThatFitsWholeImage
98 | scrollView.zoomScale = zoomScaleThatFitsWholeImage
99 | scrollView.maximumZoomScale = 3.0
100 | }
101 |
102 | }
103 |
104 | ///
105 | /// ScrollView showing the image
106 | ///
107 | @IBOutlet private weak var scrollView: UIScrollView! {
108 | didSet {
109 | setupScrollView()
110 | }
111 | }
112 |
113 | ///
114 | /// Setup scrollView. Called right after the scrollView is set.
115 | ///
116 | private func setupScrollView() {
117 | scrollView.delegate = self
118 | }
119 |
120 | ///
121 | /// View did layout subviews
122 | ///
123 | override func viewDidLayoutSubviews() {
124 | super.viewDidLayoutSubviews()
125 |
126 | // Keep scrollView updated to fit the new bounds
127 | updateScrollView()
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/ImageGallery_P6/ImageGallery_P6/ItemViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemViewController.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/20/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 | import UIKit
9 |
10 | ///
11 | /// View controller that displays a given `ImageGallery.Item`
12 | ///
13 | class ItemViewController: UIViewController {
14 |
15 | // TODO: Should properly reflect "fetching" and "failed" states as in ImageCollectionViewCell
16 |
17 | // MARK: Public
18 |
19 | ///
20 | /// The image to display
21 | ///
22 | var galleryItem: ImageGallery.Item? {
23 | didSet {
24 | if galleryItem != nil {
25 | fetchImage(galleryItem!.imageURL)
26 | }
27 | }
28 | }
29 |
30 | // MARK: Private
31 |
32 | ///
33 | /// Fetch image using given `url`
34 | ///
35 | private func fetchImage(_ url: URL) {
36 |
37 | // TODO: should show "loading" animation
38 | // TODO: should also use cache
39 |
40 | DispatchQueue.global(qos: .userInitiated).async {
41 | guard let data = try? Data(contentsOf: url.imageURL) else {
42 | // TODO: should reflect "failed" state
43 | return
44 | }
45 | guard let image = UIImage(data: data) else {
46 | // TODO: should reflect "failed" state
47 | return
48 | }
49 |
50 | DispatchQueue.main.async {
51 | self.imageView = UIImageView(image: image)
52 | }
53 | }
54 | }
55 |
56 | ///
57 | /// The imageView to display
58 | ///
59 | private var imageView: UIImageView? {
60 | didSet {
61 | if imageView != nil {
62 | // Adapt view to fit image
63 | imageView!.sizeToFit()
64 |
65 | // Add imageView to scrollView
66 | scrollView.addSubview(imageView!)
67 |
68 | // Update scrollView accordingly
69 | updateScrollView()
70 | }
71 | else {
72 | // Show a blank screen
73 | scrollView.subviews.forEach { $0.removeFromSuperview() }
74 | }
75 | }
76 | }
77 |
78 | ///
79 | /// Update scrollView to properly fit the image
80 | ///
81 | private func updateScrollView() {
82 |
83 | if imageView != nil {
84 |
85 | // The size of the image
86 | let imageSize = imageView?.image?.size ?? CGSize.zero
87 |
88 | // Size of the display
89 | let displaySize = scrollView.bounds.size
90 |
91 | // Scrollview content-size must fit the image
92 | scrollView.contentSize = imageSize
93 |
94 | // A scale that will fit the whole image on screen
95 | let zoomScaleThatFitsWholeImage = min(displaySize.width/imageSize.width,
96 | displaySize.height/imageSize.height)
97 |
98 | scrollView.minimumZoomScale = zoomScaleThatFitsWholeImage
99 | scrollView.zoomScale = zoomScaleThatFitsWholeImage
100 | scrollView.maximumZoomScale = 3.0
101 | }
102 |
103 | }
104 |
105 | ///
106 | /// ScrollView showing the image
107 | ///
108 | @IBOutlet private weak var scrollView: UIScrollView! {
109 | didSet {
110 | setupScrollView()
111 | }
112 | }
113 |
114 | ///
115 | /// Setup scrollView. Called right after the scrollView is set.
116 | ///
117 | private func setupScrollView() {
118 | scrollView.delegate = self
119 | }
120 |
121 | ///
122 | /// View did layout subviews
123 | ///
124 | override func viewDidLayoutSubviews() {
125 | super.viewDidLayoutSubviews()
126 |
127 | // Keep scrollView updated to fit the new bounds
128 | updateScrollView()
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/EmojiArtL14/EmojiArtL14/DocumentBrowserViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentBrowserViewController.swift
3 | // EmojiArtL14
4 | //
5 | // Created by Ruben on 3/9/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// A view controller for browsing and performing actions on documents stored locally and in the cloud.
13 | ///
14 | class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
15 |
16 | //
17 | // View did load
18 | //
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 |
22 | // UIDocumentBrowserViewControllerDelegate
23 | delegate = self
24 |
25 | // This will change to true if we're on iPad
26 | allowsDocumentCreation = false
27 |
28 | // We can only open one document at a time
29 | allowsPickingMultipleItems = false
30 |
31 | // If necessary, setup a "template" document used for creating new documents
32 | setupTemplate()
33 |
34 | // Only allow document creation if we got a valid template
35 | if template != nil {
36 | // Allow creation only if we have a valid template file
37 | allowsDocumentCreation = FileManager.default.createFile(atPath: template!.path, contents: Data())
38 | }
39 | }
40 |
41 | ///
42 | /// If necessary, setup a "template" document used for creating new documents.
43 | ///
44 | private func setupTemplate() {
45 | // Templates are only setup on iPad (we only create documents on iPad because iPhones cannot drag n' drop from outside
46 | // our app)
47 | if UIDevice.current.userInterfaceIdiom == .pad {
48 | template = try? FileManager.default.url(
49 | for: .applicationSupportDirectory,
50 | in: .userDomainMask,
51 | appropriateFor: nil,
52 | create: true)
53 | .appendingPathComponent("Untitled.json")
54 | }
55 | }
56 |
57 | ///
58 | /// A URL where the "template/blank" document is stored. Used for creating new documents.
59 | ///
60 | private var template: URL?
61 |
62 | // MARK: UIDocumentBrowserViewControllerDelegate
63 |
64 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didRequestDocumentCreationWithHandler importHandler: @escaping (URL?, UIDocumentBrowserViewController.ImportMode) -> Void) {
65 | importHandler(template, .copy)
66 | }
67 |
68 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {
69 | guard let sourceURL = documentURLs.first else { return }
70 |
71 | // Present the Document View Controller for the first document that was picked.
72 | // If you support picking multiple items, make sure you handle them all.
73 | presentDocument(at: sourceURL)
74 | }
75 |
76 | func documentBrowser(_ controller: UIDocumentBrowserViewController, didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {
77 | // Present the Document View Controller for the new newly created document
78 | presentDocument(at: destinationURL)
79 | }
80 |
81 | func documentBrowser(_ controller: UIDocumentBrowserViewController, failedToImportDocumentAt documentURL: URL, error: Error?) {
82 | // Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user.
83 | }
84 |
85 | // MARK: Document Presentation
86 |
87 | func presentDocument(at documentURL: URL) {
88 |
89 | // Used to instansiate a new MVC
90 | let storyBoard = UIStoryboard(name: "Main", bundle: nil)
91 |
92 | // Note: this "DocumentMVC" identifier is setup in Interface Builder
93 | // (click MVC -> Identity inspector -> Storyboard ID)
94 | let documentVC = storyBoard.instantiateViewController(withIdentifier: "DocumentMVC")
95 |
96 | // Setup destination's view controller model
97 | if let emojiArtVC = documentVC.contents as? EmojiArtViewController {
98 | emojiArtVC.document = EmojiArtDocument(fileURL: documentURL)
99 | // Present the document view controller
100 | present(documentVC, animated: true)
101 | }
102 | }
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/ImageGallery/ImageGallery/GalleryViewController/GalleryViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GalleryViewController.swift
3 | // ImageGallery
4 | //
5 | // Created by Ruben on 1/19/18.
6 | // Copyright © 2018 Ruben. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///
12 | /// Controller that displays an `ImageGallery` inside a collection view.
13 | /// Users are able to click on an item in the gallery and navigate to a new
14 | /// controller showing the item if full detail.
15 | ///
16 | class GalleryViewController: UIViewController {
17 |
18 | // MARK: Public
19 |
20 | ///
21 | /// The image gallery containing all images (url's) that are to be displayed
22 | ///
23 | var gallery = ImageGallery() {
24 | didSet {
25 | // When someone sets the gallery, update controller's title to reflect the gallery name
26 | title = gallery.name
27 | }
28 | }
29 |
30 | // MARK: Private
31 |
32 | ///
33 | /// Collection view that displays the image gallery
34 | ///
35 | @IBOutlet private weak var collectionView: UICollectionView! { didSet { setupCollectionView() } }
36 |
37 | ///
38 | /// Setup collectionView's delegation/gestures. Called during initial setup.
39 | ///
40 | private func setupCollectionView() {
41 | // Delegation
42 | collectionView.dataSource = self
43 | collectionView.delegate = self
44 | collectionView.dropDelegate = self
45 | collectionView.dragDelegate = self
46 |
47 | // UI Gestures
48 | let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchToResize(gesture:)))
49 | collectionView.addGestureRecognizer(pinchGesture)
50 | }
51 |
52 | ///
53 | /// Handle pinch gesture recognizer. It will scale the width of the collection view cell's accordingly without
54 | /// getting too big nor too small.
55 | ///
56 | @objc private func pinchToResize(gesture recognizer: UIPinchGestureRecognizer) {
57 |
58 | // Process .changed state
59 | if recognizer.state == .changed {
60 |
61 | // Change width and reset scale
62 | cellWidth *= recognizer.scale
63 | recognizer.scale = 1.0
64 |
65 | // Make sure cellWidth is not too big nor too small
66 | if cellWidth > collectionView.bounds.size.width {
67 | // Cap the width to a max. of the collectionView's bound width
68 | cellWidth = collectionView.bounds.size.width
69 | }
70 | else if cellWidth < 80.0 {
71 | // Minimun width of 80
72 | cellWidth = 80.0
73 | }
74 |
75 | //
76 | // invalidateLayout(): Invalidates the current layout and triggers a layout update.
77 | // You can call this method at any time to update the layout information. This method invalidates the
78 | // layout of the collection view itself and returns right away. Thus, you can call this method multiple
79 | // times from the same block of code without triggering multiple layout updates. The actual layout
80 | // update occurs during the next view layout update cycle.
81 | //
82 | collectionView.collectionViewLayout.invalidateLayout()
83 | }
84 | }
85 |
86 | ///
87 | /// The width of each collectionViewCell
88 | ///
89 | private(set) lazy var cellWidth: CGFloat = collectionView.bounds.width / 2.1
90 |
91 | //
92 | // Subclasses override this method and use it to configure the new view controller prior to it being displayed
93 | //
94 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
95 |
96 | // Segue must! contain an identifier. We want to crash if we missed one.
97 | switch segue.identifier! {
98 |
99 | // Show gallery item
100 | case Settings.StoryboardSegues.ShowItem:
101 | // Sender must be ImageCollectionViewCell (crash otherwise)
102 | showItem(for: segue, cell: sender as! ImageCollectionViewCell)
103 |
104 | // Other(s): ignore them
105 | default:
106 | break
107 | }
108 | }
109 |
110 | ///
111 | /// Perform segue that shows the selected gallery item.
112 | ///
113 | private func showItem(for segue: UIStoryboardSegue, cell: ImageCollectionViewCell) {
114 |
115 | // Destination must! be an ItemViewController
116 | let itemVC = segue.destination.contents as! ItemViewController
117 |
118 | // Make sure we can retriee an indexPath for the given cell
119 | guard let indexPath = collectionView.indexPath(for: cell) else {
120 | print("Couldn't find indexPath for selected cell")
121 | return
122 | }
123 |
124 | // Setup destination's model.
125 | itemVC.galleryItem = gallery.items[indexPath.item]
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------