Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2e10a74
feat(networking): creating network layer
Aug 28, 2019
2efe45b
Merge pull request #1 from GuihAntunes/feature/network_layer
GuihAntunes Aug 28, 2019
98154e4
refactor(endpoint): including starting index on endpoint build
Aug 28, 2019
6b7d67d
feat(bookslist): adding books list screen feature
Aug 30, 2019
78eecdd
Merge pull request #2 from GuihAntunes/feature/books_list
GuihAntunes Aug 30, 2019
15124df
feat(book detail): adding book detail screen
Aug 30, 2019
a52f8dc
feat(open link): adding open buy link feature
Aug 30, 2019
6155455
Merge pull request #3 from GuihAntunes/feature/book_detail
GuihAntunes Aug 30, 2019
13b6689
feat(favorites): adding core data logic to CoreDataClient class
Aug 30, 2019
3f287c1
Merge pull request #4 from GuihAntunes/feature/favorites
GuihAntunes Aug 30, 2019
936a766
fix(favorites): fixing favorites images saving logic
Sep 2, 2019
b387f95
refactor(view models): adding dependency injection for services and i…
Sep 2, 2019
4240be4
Merge pull request #5 from GuihAntunes/feature/favorites
GuihAntunes Sep 2, 2019
adf9fc0
chore(lint): adding swiftlint to project
Sep 2, 2019
3247994
chore(lint): adjustments for warning of swiftlint
Sep 2, 2019
f63be83
Merge pull request #6 from GuihAntunes/chore/lint
GuihAntunes Sep 2, 2019
7d96b23
Merge pull request #7 from GuihAntunes/develop
GuihAntunes Sep 2, 2019
67e10b3
Update README.md
GuihAntunes Sep 2, 2019
0c1d1f8
Merge pull request #9 from GuihAntunes/develop
GuihAntunes Sep 2, 2019
8a65a8e
Update README.md
GuihAntunes Sep 2, 2019
c5f7cbb
Update README.md
GuihAntunes Sep 2, 2019
a763465
Update README.md
GuihAntunes Sep 2, 2019
4b7102a
Merge pull request #10 from GuihAntunes/develop
GuihAntunes Sep 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ DerivedData/
*.perspectivev3
!default.perspectivev3
xcuserdata/
*.DS_Store
##xcshareddata

## Other
*.moved-aside
Expand Down Expand Up @@ -46,7 +48,9 @@ playground.xcworkspace
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
iOSBooks/Pods/
iOSBooks/iOSBooks.xcworkspace
iOSBooks/Podfile.lock

# Carthage
#
Expand Down
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,27 @@
# iOSBooks
# iOSBooks
# Requisitos
- Xcode 10
- Swift 5
- Cocoapods

# Antes de rodar o projeto
Antes de rodar o projeto, por favor, rode 'pod install' dentro da pasta onde se encontra o Podfile através do terminal e abra o arquivo .xcworkspace após a instalação das dependências.

# Arquitetura
- **Model:** Representa os dados da aplicação
- **View:** Camada de apresentação visual
- **ViewModel:** Camada de regras de apresentação e regras de negócio (se houver alguma no frontend)
- **Service:** Camada que busca os dados da internet
- **Coordinator:** Camada que orquestra os fluxos de apresentação do app
- **Injector:** Camada que injeta as dependências de cada tela/view model do app

# Fluxo de camadas do app (Como as camadas se comunicam)

AppDelegate -> Coordinator (Injector) <-> ViewModel (Service) <-> View

# Dependencias
- **Kingfisher:** Biblioteca de image loader e cacher para baixar as imagens da Internet
- **PromisesKit:** Biblioteca para tratar código assíncrono com mais facilidade
- **SwiftLint:** Linter para análise de code style
- **Quick:** Biblioteca para auxiliar em criação de cenários em testes unitários
- **Nimble:** Biblioteca para auxiliar em criação de cenários em testes unitários
Binary file removed iOSBooks/.DS_Store
Binary file not shown.
46 changes: 46 additions & 0 deletions iOSBooks/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Pods
- iOSBooksTests
included:
- iOSBooks
whitelist_rules:
- colon
- implicitly_unwrapped_optional
- empty_count
- force_cast
- force_try
- force_unwrapping
- first_where
- last_where
- legacy_random
- nslocalizedstring_key
- overridden_super_call
- private_over_fileprivate
- redundant_nil_coalescing
- redundant_optional_initialization
- redundant_string_enum_value
- sorted_first_last
- sorted_imports
- statement_position
colon: warning
empty_count: warning
force_cast: error
force_try: error
force_unwrapping: error
first_where: warning
implicitly_unwrapped_optional:
severity: error
last_where: warning
legacy_random: warning
nslocalizedstring_key: warning
overridden_super_call:
severity: warning
private_over_fileprivate:
severity: warning
redundant_nil_coalescing: warning
redundant_optional_initialization: warning
redundant_string_enum_value: warning
sorted_first_last: warning
sorted_imports: warning
statement_position:
severity: warning
20 changes: 20 additions & 0 deletions iOSBooks/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'

target 'iOSBooks' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

# Pods for iOSBooks
pod 'PromiseKit'
pod 'Kingfisher', "~>5.1"
pod 'SwiftLint'

target 'iOSBooksTests' do
inherit! :search_paths
# Pods for testing
pod 'Quick', '~> 2.1.0'
pod 'Nimble', '~> 8.0.1'
end

end
402 changes: 381 additions & 21 deletions iOSBooks/iOSBooks.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

61 changes: 57 additions & 4 deletions iOSBooks/iOSBooks/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@
// Copyright © 2019 Guilherme Antunes. All rights reserved.
//

import CoreData
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?


var coordinator: AppCoordinator?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

window = UIWindow(frame: UIScreen.main.bounds)
guard let window = window else {
print("window is unexpectedly nil")
return false
}
coordinator = AppCoordinator(window: window)
coordinator?.start()

return true
}

Expand All @@ -38,9 +47,53 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}

func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
window = nil
}

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Book")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()

// MARK: - Core Data Saving support

func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "back_arrow.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "back_arrow@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "back_arrow@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 0 additions & 24 deletions iOSBooks/iOSBooks/Base.lproj/Main.storyboard

This file was deleted.

96 changes: 96 additions & 0 deletions iOSBooks/iOSBooks/BookDetail/View/BookDetail.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Book Detail View Controller-->
<scene sceneID="fw4-DL-XOb">
<objects>
<viewController storyboardIdentifier="BookDetailViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="6rU-Uw-H3q" customClass="BookDetailViewController" customModule="iOSBooks" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="c9M-V1-kX2">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TpO-b0-I35">
<rect key="frame" x="12" y="56" width="300" height="300"/>
<constraints>
<constraint firstAttribute="width" constant="300" id="RkD-TA-uR1"/>
<constraint firstAttribute="height" constant="300" id="ze3-T2-UB5"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="DsL-0l-xi7">
<rect key="frame" x="12" y="368" width="390" height="528"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="768-XD-nlZ">
<rect key="frame" x="0.0" y="0.0" width="390" height="23.5"/>
<fontDescription key="fontDescription" name="AvenirNext-Bold" family="Avenir Next" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mU9-Pt-17a">
<rect key="frame" x="0.0" y="35.5" width="390" height="23.5"/>
<fontDescription key="fontDescription" name="AvenirNext-DemiBold" family="Avenir Next" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="baa-VJ-mqK">
<rect key="frame" x="0.0" y="71" width="390" height="23.5"/>
<fontDescription key="fontDescription" name="AvenirNext-Italic" family="Avenir Next" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AgA-qA-aED">
<rect key="frame" x="0.0" y="106.5" width="390" height="421.5"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
<fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="17"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4yx-Iu-LCN">
<rect key="frame" x="330" y="56" width="72" height="37"/>
<fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="18"/>
<state key="normal" title="Favoritar">
<color key="titleColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="saveBook:" destination="6rU-Uw-H3q" eventType="touchUpInside" id="tMi-uV-QFL"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="DsL-0l-xi7" firstAttribute="leading" secondItem="SrW-hW-4OI" secondAttribute="leading" constant="12" id="A9U-Mz-1My"/>
<constraint firstItem="DsL-0l-xi7" firstAttribute="top" secondItem="TpO-b0-I35" secondAttribute="bottom" constant="12" id="NTd-sh-A5j"/>
<constraint firstItem="SrW-hW-4OI" firstAttribute="trailing" secondItem="4yx-Iu-LCN" secondAttribute="trailing" constant="12" id="P14-Py-Px5"/>
<constraint firstItem="TpO-b0-I35" firstAttribute="leading" secondItem="SrW-hW-4OI" secondAttribute="leading" constant="12" id="Psc-l9-6GA"/>
<constraint firstAttribute="bottom" secondItem="DsL-0l-xi7" secondAttribute="bottom" id="chY-Lh-qBo"/>
<constraint firstItem="SrW-hW-4OI" firstAttribute="trailing" secondItem="DsL-0l-xi7" secondAttribute="trailing" constant="12" id="doA-ib-ugT"/>
<constraint firstItem="4yx-Iu-LCN" firstAttribute="top" secondItem="SrW-hW-4OI" secondAttribute="top" constant="12" id="gS0-BO-Ivy"/>
<constraint firstItem="TpO-b0-I35" firstAttribute="top" secondItem="SrW-hW-4OI" secondAttribute="top" constant="12" id="y6M-gB-GD3"/>
</constraints>
<viewLayoutGuide key="safeArea" id="SrW-hW-4OI"/>
</view>
<connections>
<outlet property="bookAuthorsLabel" destination="mU9-Pt-17a" id="3vw-bk-jyF"/>
<outlet property="bookImageView" destination="TpO-b0-I35" id="XbF-1j-3nc"/>
<outlet property="bookTitleLabel" destination="768-XD-nlZ" id="z92-Hg-c8F"/>
<outlet property="buyLinkLabel" destination="baa-VJ-mqK" id="2ro-Qf-yqx"/>
<outlet property="descriptionTextView" destination="AgA-qA-aED" id="zGM-Go-3v2"/>
<outlet property="favoriteButton" destination="4yx-Iu-LCN" id="pHx-y7-Mep"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="7Zi-CG-FdX" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-7" y="-1"/>
</scene>
</scenes>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</document>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// BookDetailViewController+Safari.swift
// iOSBooks
//
// Created by Guilherme Antunes Ferreira on 30/08/19.
// Copyright © 2019 Guilherme Antunes. All rights reserved.
//

import UIKit

extension BookDetailViewController {
@objc func openBuyLink() {
guard let buyLink = viewModel?.getBookBuyLinkURL() else { return }
UIApplication.shared.open(buyLink, options: [:], completionHandler: nil)
}
}
Loading