Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
286df58
Add: 웹 뷰 Refactoring
simoniful Jul 9, 2022
209ca5f
Add: 뉴스 리스트 뷰 모델 구성 및 코디네이터 연결
simoniful Jul 10, 2022
6259f1a
Merge pull request #1 from simoniful/MVVM+C
simoniful Jul 10, 2022
e9f5971
Add: ListViewController 정리
simoniful Jul 10, 2022
0139c11
Merge branch 'master' of https://github.com/simoniful/iOS_News_MVVM-C…
simoniful Jul 10, 2022
621dc8f
Merge pull request #2 from simoniful/MVVM+C
simoniful Jul 10, 2022
c76d104
Add: List ViewModel Table 구성
simoniful Jul 10, 2022
a52e292
Merge branch 'master' of https://github.com/simoniful/iOS_News_MVVM-C…
simoniful Jul 10, 2022
f285ce4
Add: 화면 전환 시 애니메이션 수정
simoniful Jul 10, 2022
00e8c9c
Add: Scrap 뷰 관련 구성
simoniful Jul 11, 2022
8d234c6
Add: Tagsmaker 뷰 구성
simoniful Jul 12, 2022
91e8bc7
Refactor: ViewModel 기능 정리
simoniful Jul 12, 2022
ab6508f
Add: WebViewModel 테스트 케이스 정리
simoniful Jul 13, 2022
94c383b
Add: ListVeiwModel 테스트 구성
simoniful Jul 13, 2022
0f4bb0c
Add: ScrapViewModel 테스트 구성
simoniful Jul 14, 2022
5bea305
Add: TagmakerView 테스트 구성
simoniful Jul 14, 2022
5194c4a
Add: TagmakerViewModel 테스트 구성
simoniful Jul 14, 2022
d683875
Merge branch 'MVVM+C' of https://github.com/simoniful/iOS_News_MVVM-C…
simoniful Jul 14, 2022
8bb5d02
Refact: Minor modified
simoniful Jul 14, 2022
55f3b96
Add: README.md 수정
simoniful Jul 15, 2022
c9e85b8
Add: README.md 수정
simoniful Jul 15, 2022
d376233
Add: Readme.md 수정
simoniful Sep 22, 2022
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
270 changes: 203 additions & 67 deletions News.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion News.xcodeproj/xcshareddata/xcschemes/News.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
37 changes: 37 additions & 0 deletions News/Application/AppCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// AppCoordinator.swift
// News
//
// Created by Sang hun Lee on 2022/07/08.
//

import UIKit

final class AppCoordinator: Coordinator {
weak var delegate: CoordinatorDelegate?
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
var type: CoordinatorStyleCase = .app

init(_ navigationController: UINavigationController) {
self.navigationController = navigationController
navigationController.setNavigationBarHidden(true, animated: false)
}

func start() {
connectTabBarFlow()
}

private func connectTabBarFlow() {
let newsTabCoordinator = NewsTabCoordinator(self.navigationController)
newsTabCoordinator.delegate = self
newsTabCoordinator.start()
childCoordinators.append(newsTabCoordinator)
}
}

extension AppCoordinator: CoordinatorDelegate {
func didFinish(childCoordinator: Coordinator) {
finish()
}
}
13 changes: 9 additions & 4 deletions News/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
return true
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {

func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
}
Expand Down
9 changes: 6 additions & 3 deletions News/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?
var coordinator: AppCoordinator?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.backgroundColor = .systemBackground
let nav = UINavigationController()
coordinator = AppCoordinator(nav)
coordinator?.start()
window?.tintColor = .systemOrange
window?.rootViewController = NewsTabViewController()
window?.backgroundColor = .systemBackground
window?.rootViewController = nav
window?.makeKeyAndVisible()
}
}
Expand Down
38 changes: 38 additions & 0 deletions News/Coordinator/Coordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Coordinator.swift
// News
//
// Created by Sang hun Lee on 2022/07/08.
//

import UIKit

protocol Coordinator: AnyObject {
var delegate: CoordinatorDelegate? { get set }
var navigationController: UINavigationController { get set }
var childCoordinators: [Coordinator] { get set }
var type: CoordinatorStyleCase { get }

func start()
func finish()

init(_ navigationController: UINavigationController)
}

extension Coordinator {
func finish() {
childCoordinators.removeAll()
delegate?.didFinish(childCoordinator: self)
}

func changeAnimation() {
if let window = UIApplication.shared.windows.first {
UIView.transition(
with: window,
duration: 0.5,
options: .transitionCrossDissolve,
animations: nil
)
}
}
}
12 changes: 12 additions & 0 deletions News/Coordinator/CoordinatorDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// CoordinatorDelegate.swift
// News
//
// Created by Sang hun Lee on 2022/07/08.
//

import Foundation

protocol CoordinatorDelegate: AnyObject {
func didFinish(childCoordinator: Coordinator)
}
13 changes: 13 additions & 0 deletions News/Coordinator/CoordinatorStyleCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// CoordinatorStyleCase.swift
// News
//
// Created by Sang hun Lee on 2022/07/08.
//

import Foundation

enum CoordinatorStyleCase {
case app, tab
case news, bookmark
}
18 changes: 17 additions & 1 deletion News/Domain/Entity/NewsData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,27 @@ struct NewsData {
let display: Int
}

struct News {
// TODO: 관리에 있어서 Identifiable 준수 필요
struct News: Equatable {
let title: String
let originallink: String
let link: String
let desc: String
let pubDate: String
var isScraped: Bool

static func == (lhs: News, rhs: News) -> Bool {
return lhs.title == rhs.title
}
}

extension News {
init(scrapedNews: ScrapedNews) {
self.title = scrapedNews.title ?? ""
self.originallink = scrapedNews.title ?? ""
self.link = scrapedNews.link ?? ""
self.desc = scrapedNews.desc ?? ""
self.pubDate = scrapedNews.pubDate ?? ""
self.isScraped = scrapedNews.isScraped
}
}
4 changes: 4 additions & 0 deletions News/Extensions/String +.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ extension String {
return nil
}
}

var isBlank: Bool {
return self.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
37 changes: 37 additions & 0 deletions News/Extensions/UIViewController + Rx.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// UIViewController + Rx.swift
// News
//
// Created by Sang hun Lee on 2022/07/11.
//

import UIKit
import RxCocoa
import RxSwift

extension Reactive where Base: UIViewController {
var viewDidLoad: ControlEvent<Void> {
let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in }
return ControlEvent(events: source)
}

var viewWillAppear: ControlEvent<Void> {
let source = self.methodInvoked(#selector(Base.viewWillAppear)).map { _ in }
return ControlEvent(events: source)
}

var viewDidAppear: ControlEvent<Bool> {
let source = self.methodInvoked(#selector(Base.viewDidAppear)).map { $0.first as? Bool ?? false }
return ControlEvent(events: source)
}

var viewWillDisappear: ControlEvent<Bool> {
let source = self.methodInvoked(#selector(Base.viewWillDisappear)).map { $0.first as? Bool ?? false }
return ControlEvent(events: source)
}

var viewDidDisappear: ControlEvent<Void> {
let source = self.methodInvoked(#selector(Base.viewDidDisappear)).map { _ in () }
return ControlEvent(events: source)
}
}
4 changes: 2 additions & 2 deletions News/Network/NetworkError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ enum SearchError: Int, Error {
extension SearchError {
var errorDescription: String {
switch self {
case .badRequest: return "검색 API 요청에 오류가 있습니다. 요청 URL, 필수 요청 변수가 정확한지 확인 바랍니다"
case .badRequest: return "검색 API 요청에 오류가 있습니다.\n요청 URL, 변수가 정확한지 확인 바랍니다"
case .invalidSearchApi: return "검색 API 대상에 오타가 없는지 확인해 보세요."
case .systemError: return "서버 내부 에러가 발생하였습니다. 포럼에 올려주시면 신속히 조치하겠습니다."
case .systemError: return "서버 내부 에러가 발생하였습니다.\n포럼에 올려주시면 신속히 조치하겠습니다."
}
}
}
67 changes: 67 additions & 0 deletions News/Presentations/NewsList/Coordinator/NewsListCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// NewsListCoordinator.swift
// News
//
// Created by Sang hun Lee on 2022/07/08.
//

import UIKit

final class NewsListCoordinator: Coordinator {
var delegate: CoordinatorDelegate?
var navigationController: UINavigationController
var childCoordinators = [Coordinator]()
var type: CoordinatorStyleCase = .news

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

func start() {
let vc = NewsListViewController(
viewModel: NewsListViewModel(
coordinator: self,
searchUseCase: SearchUseCase(
repository: NewsSearchManager()
)
)
)
navigationController.pushViewController(vc, animated: true)
}

func pushNewsWebViewController(news: News, scrapedNews: ScrapedNews?) {
let vc = NewsWebViewController(
viewModel: NewsWebViewModel(
coordinator: self,
news: news,
scrapedNews: scrapedNews
)
)
vc.hidesBottomBarWhenPushed = true
navigationController.pushViewController(vc, animated: true)
}

func presentNewsTagmakerViewController(
tags: [String], newsTagmakerDelegate: NewsTagmakerDelegate
) {
let vc = UINavigationController(
rootViewController: NewsTagmakerViewController(
viewModel: NewsTagmakerViewModel(
coordinator: self,
newsTagmakerDelegate: newsTagmakerDelegate,
tags: tags
)
)
)
vc.modalPresentationStyle = .fullScreen
navigationController.present(vc, animated: true)
}

func dismissToNewsListViewController(message: String? = nil) {
navigationController.dismiss(animated: true) {
if let message = message {
self.navigationController.view.makeToast(message, position: .bottom)
}
}
}
}
Loading