Skip to content

Commit

Permalink
Merge pull request sergdort#35 from fabfelici/delete-post
Browse files Browse the repository at this point in the history
Supporting delete post
  • Loading branch information
sergdort authored Dec 10, 2017
2 parents d96da8d + 33a3cbf commit 0f6e3c9
Show file tree
Hide file tree
Showing 23 changed files with 203 additions and 121 deletions.
12 changes: 4 additions & 8 deletions CleanArchitectureRxSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
8A148DC8CA606C8F34807082 /* Pods_NetworkPlatform.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 763D40E220B6FF96E969B284 /* Pods_NetworkPlatform.framework */; };
8B0507E0C0AB1064B7372844 /* Pods_RealmPlatform.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 006BDFA0A26FDD0EBA50E777 /* Pods_RealmPlatform.framework */; };
9CBC9DB91790C744BC17C099 /* Pods_CleanArchitectureRxSwiftTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 550BE321D44EC009D885BBE1 /* Pods_CleanArchitectureRxSwiftTests.framework */; };
B60A97CE1FB0C17600009C51 /* EditPostNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60A97CD1FB0C17600009C51 /* EditPostNavigator.swift */; };
BC8D07731E9309D000B4D96A /* UidTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC8D07721E9309D000B4D96A /* UidTransform.swift */; };
BCD8C8AC1E73421300F79E3E /* Address+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD8C8AB1E73421300F79E3E /* Address+Mapping.swift */; };
BCD8C8AE1E73421E00F79E3E /* Album+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD8C8AD1E73421E00F79E3E /* Album+Mapping.swift */; };
Expand Down Expand Up @@ -375,6 +376,7 @@
A8E1F5AE93A531609690A036 /* Pods-RealmPlatformTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RealmPlatformTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RealmPlatformTests/Pods-RealmPlatformTests.debug.xcconfig"; sourceTree = "<group>"; };
B0092014AEC057C48B9745EA /* Pods-DomainTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DomainTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DomainTests/Pods-DomainTests.debug.xcconfig"; sourceTree = "<group>"; };
B5764703F1E249BEDFC31014 /* Pods_DomainTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DomainTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B60A97CD1FB0C17600009C51 /* EditPostNavigator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditPostNavigator.swift; sourceTree = "<group>"; };
BA0D3602A9ABB65C8AF19365 /* Pods_RealmPlatformTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RealmPlatformTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BC15FAFCFFF7EB7017614B45 /* Pods-NetworkPlatformTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NetworkPlatformTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-NetworkPlatformTests/Pods-NetworkPlatformTests.debug.xcconfig"; sourceTree = "<group>"; };
BC8D07721E9309D000B4D96A /* UidTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UidTransform.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -569,13 +571,6 @@
path = Encodable;
sourceTree = "<group>";
};
25707C721F23807C00F852F7 /* Repository */ = {
isa = PBXGroup;
children = (
);
name = Repository;
sourceTree = "<group>";
};
25707C731F2380E500F852F7 /* Cache */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -892,6 +887,7 @@
515F9401ED57113EEF898228 /* EditPost */ = {
isa = PBXGroup;
children = (
B60A97CD1FB0C17600009C51 /* EditPostNavigator.swift */,
2526A7151E5A2CD30078870E /* EditPostViewController.swift */,
515F9ACD2D474324015B691C /* EditPostViewModel.swift */,
);
Expand Down Expand Up @@ -1033,7 +1029,6 @@
isa = PBXGroup;
children = (
25707C731F2380E500F852F7 /* Cache */,
25707C721F23807C00F852F7 /* Repository */,
BD107F671E72A0DC0043D900 /* API */,
BD107F731E72B1790043D900 /* Entries */,
BD50EEF31E7AD99400CBEBD4 /* Network */,
Expand Down Expand Up @@ -2031,6 +2026,7 @@
515F977483234BB090F6D704 /* PostsViewController.swift in Sources */,
515F9083DB52FEDFEE97A5E6 /* PostsViewModel.swift in Sources */,
515F9590146BEE2A0626CFF1 /* PostTableViewCell.swift in Sources */,
B60A97CE1FB0C17600009C51 /* EditPostNavigator.swift in Sources */,
515F95CFED58045AB6B168A4 /* CreatePostViewController.swift in Sources */,
7BA4DC961F3AEA380043DAB6 /* PostItemViewModel.swift in Sources */,
515F9625B58BCFB77F4AF678 /* CreatePostNavigator.swift in Sources */,
Expand Down
13 changes: 9 additions & 4 deletions CleanArchitectureRxSwift/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand All @@ -30,7 +31,7 @@
<rect key="frame" x="0.0" y="28" width="375" height="82"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wsn-Eu-k9m" id="54K-Ut-RUc">
<rect key="frame" x="0.0" y="0.0" width="375" height="81.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="82"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="irm-SF-QMY">
Expand Down Expand Up @@ -224,9 +225,13 @@
</constraints>
</view>
<navigationItem key="navigationItem" id="FpO-rx-nwd">
<barButtonItem key="rightBarButtonItem" title="Edit" id="wmL-GG-UqC"/>
<rightBarButtonItems>
<barButtonItem title="Edit" id="wmL-GG-UqC"/>
<barButtonItem systemItem="trash" id="uEG-LJ-KaS" userLabel="Delete Button"/>
</rightBarButtonItems>
</navigationItem>
<connections>
<outlet property="deleteButton" destination="uEG-LJ-KaS" id="NO6-Dy-opq"/>
<outlet property="detailsTextView" destination="vu6-3Q-g43" id="0CY-zu-MDS"/>
<outlet property="editButton" destination="wmL-GG-UqC" id="cmt-p1-9HO"/>
<outlet property="titleTextField" destination="Z0e-ow-m8L" id="7Xb-cG-ojy"/>
Expand Down
5 changes: 3 additions & 2 deletions CleanArchitectureRxSwift/Scenes/AllPosts/PostsNavigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ class DefaultPostsNavigator: PostsNavigator {
let nc = UINavigationController(rootViewController: vc)
navigationController.present(nc, animated: true, completion: nil)
}

func toPost(_ post: Post) {
let navigator = DefaultEditPostNavigator(navigationController: navigationController)
let viewModel = EditPostViewModel(post: post, useCase: services.makePostsUseCase(), navigator: navigator)
let vc = storyBoard.instantiateViewController(ofType: EditPostViewController.self)
let viewModel = EditPostViewModel(post: post, useCase: services.makePostsUseCase())
vc.viewModel = viewModel
navigationController.pushViewController(vc, animated: true)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ final class CreatePostViewModel: ViewModelType {
return !$0.0.isEmpty && !$0.1.isEmpty && !$1
}


let save = input.saveTrigger.withLatestFrom(titleAndDetails)
.map { (title, content) in
return Post(body: content, title: title, uid: "5", userId: "7")
return Post(body: content, title: title)
}
.flatMapLatest { [unowned self] in
return self.createPostUseCase.save(post: $0)
Expand Down
19 changes: 19 additions & 0 deletions CleanArchitectureRxSwift/Scenes/EditPost/EditPostNavigator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation
import UIKit
import Domain

protocol EditPostNavigator {
func toPosts()
}

final class DefaultEditPostNavigator: EditPostNavigator {
private let navigationController: UINavigationController

init(navigationController: UINavigationController) {
self.navigationController = navigationController
}

func toPosts() {
navigationController.popViewController(animated: true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ final class EditPostViewController: UIViewController {
private let disposeBag = DisposeBag()

@IBOutlet weak var editButton: UIBarButtonItem!
@IBOutlet weak var deleteButton: UIBarButtonItem!
@IBOutlet weak var titleTextField: UITextField!
@IBOutlet weak var detailsTextView: UITextView!

Expand All @@ -15,20 +16,44 @@ final class EditPostViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()

let input = EditPostViewModel.Input(editTrigger: editButton.rx.tap.asDriver(),
title: titleTextField.rx.text.orEmpty.asDriver(),
details: detailsTextView.rx.text.orEmpty.asDriver())
let deleteTrigger = deleteButton.rx.tap.flatMap {
return Observable<Void>.create { observer in

let alert = UIAlertController(title: "Delete Post",
message: "Are you sure you want to delete this post?",
preferredStyle: .alert
)

[("Yes", UIAlertActionStyle.destructive, { _ -> () in observer.onNext() }),
("No", UIAlertActionStyle.cancel, { _ -> () in observer.onCompleted() })]
.map({ UIAlertAction(title: $0, style: $1, handler: $2) })
.forEach(alert.addAction)

self.present(alert, animated: true, completion: nil)

return Disposables.create()
}
}

let input = EditPostViewModel.Input(
editTrigger: editButton.rx.tap.asDriver(),
deleteTrigger: deleteTrigger.asDriverOnErrorJustComplete(),
title: titleTextField.rx.text.orEmpty.asDriver(),
details: detailsTextView.rx.text.orEmpty.asDriver()
)

let output = viewModel.transform(input: input)

output.editButtonTitle.drive(editButton.rx.title).addDisposableTo(disposeBag)
output.editing.drive(titleTextField.rx.isEnabled).addDisposableTo(disposeBag)
output.editing.drive(detailsTextView.rx.isEditable).addDisposableTo(disposeBag)
output.post.drive(postBinding).addDisposableTo(disposeBag)
output.save.drive().addDisposableTo(disposeBag)
output.error.drive(errorBinding).addDisposableTo(disposeBag)

[output.editButtonTitle.drive(editButton.rx.title),
output.editing.drive(titleTextField.rx.isEnabled),
output.editing.drive(detailsTextView.rx.isEditable),
output.post.drive(postBinding),
output.save.drive(),
output.error.drive(errorBinding),
output.delete.drive()]
.forEach({$0.addDisposableTo(disposeBag)})
}


var postBinding: UIBindingObserver<EditPostViewController, Post> {
return UIBindingObserver(UIElement: self, binding: { (vc, post) in
vc.titleTextField.text = post.title
Expand Down Expand Up @@ -60,4 +85,3 @@ extension Reactive where Base: UITextView {
})
}
}

19 changes: 17 additions & 2 deletions CleanArchitectureRxSwift/Scenes/EditPost/EditPostViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import RxCocoa
final class EditPostViewModel: ViewModelType {
private let post: Post
private let useCase: PostsUseCase
private let navigator: EditPostNavigator

init(post: Post, useCase: PostsUseCase) {
init(post: Post, useCase: PostsUseCase, navigator: EditPostNavigator) {
self.post = post
self.useCase = useCase
self.navigator = navigator
}

func transform(input: Input) -> Output {
Expand All @@ -24,7 +26,7 @@ final class EditPostViewModel: ViewModelType {
$0
}
let post = Driver.combineLatest(Driver.just(self.post), titleAndDetails) { (post, titleAndDetails) -> Post in
return Post(body: titleAndDetails.1, title: titleAndDetails.0, uid: "7", userId: "8")
return Post(body: titleAndDetails.1, title: titleAndDetails.0, uid: post.uid, userId: post.userId, createdAt: post.createdAt)
}.startWith(self.post)
let editButtonTitle = editing.map { editing -> String in
return editing == true ? "Save" : "Edit"
Expand All @@ -35,8 +37,19 @@ final class EditPostViewModel: ViewModelType {
.trackError(errorTracker)
.asDriverOnErrorJustComplete()
}

let deletePost = input.deleteTrigger.withLatestFrom(post)
.flatMapLatest { post in
return self.useCase.delete(post: post)
.trackError(errorTracker)
.asDriverOnErrorJustComplete()
}.do(onNext: {
self.navigator.toPosts()
})

return Output(editButtonTitle: editButtonTitle,
save: savePost,
delete: deletePost,
editing: editing,
post: post,
error: errorTracker.asDriver())
Expand All @@ -46,13 +59,15 @@ final class EditPostViewModel: ViewModelType {
extension EditPostViewModel {
struct Input {
let editTrigger: Driver<Void>
let deleteTrigger: Driver<Void>
let title: Driver<String>
let details: Driver<String>
}

struct Output {
let editButtonTitle: Driver<String>
let save: Driver<Void>
let delete: Driver<Void>
let editing: Driver<Bool>
let post: Driver<Post>
let error: Driver<Error>
Expand Down
2 changes: 1 addition & 1 deletion CoreDataPlatform/Entities/CDPost+CoreDataProperties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ extension CDPost {
@NSManaged public var title: String?
@NSManaged public var uid: String?
@NSManaged public var userId: String?

@NSManaged public var createdAt: String?
}
5 changes: 4 additions & 1 deletion CoreDataPlatform/Entities/CDPost+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ extension CDPost {
static var body: Attribute<String> { return Attribute("body")}
static var userId: Attribute<String> { return Attribute("userId")}
static var uid: Attribute<String> { return Attribute("uid")}
static var createdAt: Attribute<String> { return Attribute("createdAt")}
}

extension CDPost: DomainConvertibleType {
func asDomain() -> Post {
return Post(body: body!,
title: title!,
uid: uid!,
userId: userId!)
userId: userId!,
createdAt: createdAt!)
}
}

Expand All @@ -43,5 +45,6 @@ extension Post: CoreDataRepresentable {
entity.title = title
entity.body = body
entity.userId = userId
entity.createdAt = createdAt
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16E195" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="12141" systemVersion="16G29" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="CDAddress" representedClassName=".CDAddress" syncable="YES">
<attribute name="city" attributeType="String" syncable="YES"/>
<attribute name="street" attributeType="String" syncable="YES"/>
Expand Down Expand Up @@ -40,6 +40,7 @@
</entity>
<entity name="CDPost" representedClassName=".CDPost" syncable="YES">
<attribute name="body" attributeType="String" syncable="YES"/>
<attribute name="createdAt" attributeType="String" syncable="YES"/>
<attribute name="title" attributeType="String" syncable="YES"/>
<attribute name="uid" attributeType="String" indexed="YES" syncable="YES"/>
<attribute name="userId" attributeType="String" syncable="YES"/>
Expand Down Expand Up @@ -67,7 +68,7 @@
<element name="CDCompany" positionX="-18" positionY="45" width="128" height="105"/>
<element name="CDLocation" positionX="-36" positionY="27" width="128" height="90"/>
<element name="CDPhoto" positionX="0" positionY="54" width="128" height="120"/>
<element name="CDPost" positionX="-63" positionY="-18" width="128" height="105"/>
<element name="CDPost" positionX="-63" positionY="-18" width="128" height="120"/>
<element name="CDTodo" positionX="18" positionY="63" width="128" height="105"/>
<element name="CDUser" positionX="36" positionY="81" width="128" height="165"/>
</elements>
Expand Down
32 changes: 17 additions & 15 deletions CoreDataPlatform/Repository/Repository.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import Foundation
import CoreData
import RxSwift
import QueryKit

func abstractMethod() -> Never {
fatalError("abstract method")
protocol AbstractRepository {
associatedtype T
func query(with predicate: NSPredicate?,
sortDescriptors: [NSSortDescriptor]?) -> Observable<[T]>
func save(entity: T) -> Observable<Void>
func delete(entity: T) -> Observable<Void>
}

class AbstractRepository<T> {
func query(with predicate: NSPredicate? = nil,
sortDescriptors: [NSSortDescriptor]? = nil) -> Observable<[T]> {
abstractMethod()
}
func save(entity: T) -> Observable<Void> {
abstractMethod()
}
}

final class Repository<T: CoreDataRepresentable>: AbstractRepository<T> where T == T.CoreDataType.DomainType {
final class Repository<T: CoreDataRepresentable>: AbstractRepository where T == T.CoreDataType.DomainType {
private let context: NSManagedObjectContext
private let scheduler: ContextScheduler

Expand All @@ -25,7 +20,7 @@ final class Repository<T: CoreDataRepresentable>: AbstractRepository<T> where T
self.scheduler = ContextScheduler(context: context)
}

override func query(with predicate: NSPredicate? = nil,
func query(with predicate: NSPredicate? = nil,
sortDescriptors: [NSSortDescriptor]? = nil) -> Observable<[T]> {
let request = T.CoreDataType.fetchRequest()
request.predicate = predicate
Expand All @@ -35,10 +30,17 @@ final class Repository<T: CoreDataRepresentable>: AbstractRepository<T> where T
.subscribeOn(scheduler)
}

override func save(entity: T) -> Observable<Void> {
func save(entity: T) -> Observable<Void> {
return entity.sync(in: context)
.mapToVoid()
.flatMapLatest(context.rx.save)
.subscribeOn(scheduler)
}

func delete(entity: T) -> Observable<Void> {
return entity.sync(in: context)
.map({$0 as! NSManagedObject})
.flatMapLatest(context.rx.delete)
}

}
Loading

0 comments on commit 0f6e3c9

Please sign in to comment.