diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 0000000..b4d6094 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,9 @@ + +# exclude files +--exclude Carthage,Pods + +# change rules +--stripunusedargs closure-only + +# disable rules +--disable strongOutlets,numberFormatting,emptyBraces,andOperator diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..1eaf353 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,41 @@ +disabled_rules: + - colon + - comma + - control_statement + - identifier_name + - type_name + - trailing_comma + - multiple_closures_with_trailing_closure + - opening_brace + +opt_in_rules: + - empty_count + - sorted_imports + - anyobject_protocol + +excluded: + - Carthage + - Pods + - vendor/bundle + +force_cast: error + +force_try: + severity: error + +type_body_length: + - 300 + - 400 + +function_body_length: + - 200 + - 300 + +file_length: + - 500 + - 1000 + +line_length: 200 + +nesting: + type_level: 3 diff --git a/FireTodo.xcodeproj/project.pbxproj b/FireTodo.xcodeproj/project.pbxproj index cd50d26..8e29ec9 100644 --- a/FireTodo.xcodeproj/project.pbxproj +++ b/FireTodo.xcodeproj/project.pbxproj @@ -349,6 +349,7 @@ isa = PBXNativeTarget; buildConfigurationList = 160702982337231400A57BE8 /* Build configuration list for PBXNativeTarget "FireTodo" */; buildPhases = ( + 166451F82340FE0400E0E7AB /* SwiftLint */, 678E1EE18A824791FD50167E /* [CP] Check Pods Manifest.lock */, 160702802337231300A57BE8 /* Sources */, 160702812337231300A57BE8 /* Frameworks */, @@ -412,6 +413,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 166451F82340FE0400E0E7AB /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "${SRCROOT}/Pods/SwiftLint/swiftlint\n"; + }; 6332EE6E8916A88AE530C93A /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/FireTodo/AppDelegate.swift b/FireTodo/AppDelegate.swift index 6731a78..b601e3d 100644 --- a/FireTodo/AppDelegate.swift +++ b/FireTodo/AppDelegate.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import UIKit import Firebase +import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -19,4 +19,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { } } - diff --git a/FireTodo/Combine/Auth+Combine.swift b/FireTodo/Combine/Auth+Combine.swift index 27387e7..9000754 100644 --- a/FireTodo/Combine/Auth+Combine.swift +++ b/FireTodo/Combine/Auth+Combine.swift @@ -26,7 +26,7 @@ extension CombineAuth { let listener = addListener(auth) { auth, user in _ = subscriber.receive((auth, user)) } - self._cancel = { removeListener($0, listener) } + _cancel = { removeListener($0, listener) } } public func request(_ demand: Subscribers.Demand) {} @@ -53,7 +53,7 @@ extension CombineAuth { self.removeListener = removeListener } - public func receive(subscriber: S) where S : Subscriber, S.Failure == Failure, S.Input == Output { + public func receive(subscriber: S) where S: Subscriber, S.Failure == Failure, S.Input == Output { subscriber.receive(subscription: Subscription( subscriber: subscriber, auth: auth, diff --git a/FireTodo/ContentView.swift b/FireTodo/ContentView.swift index 66a5c0c..00c4e76 100644 --- a/FireTodo/ContentView.swift +++ b/FireTodo/ContentView.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import SwiftUI import Combine +import SwiftUI struct ContentView: View { @EnvironmentObject private var store: AppStore @@ -19,11 +19,9 @@ struct ContentView: View { return AnyView(SignUpView()) } } - }()) - .onAppear { self.store.dispatch(AuthAction.subscribe()) } - .onDisappear { - self.store.dispatch(AuthAction.subscribe()) - } + }()) + .onAppear { self.store.dispatch(AuthAction.subscribe()) } + .onDisappear { self.store.dispatch(AuthAction.subscribe()) } } } diff --git a/FireTodo/Firebase/Model.swift b/FireTodo/Firebase/Model.swift index d4a2618..59c57b4 100644 --- a/FireTodo/Firebase/Model.swift +++ b/FireTodo/Firebase/Model.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import Foundation import FireSnapshot +import Foundation /// Name space for Cloud Firestore document models. enum Model { diff --git a/FireTodo/Firebase/Snapshot+Identifiable.swift b/FireTodo/Firebase/Snapshot+Identifiable.swift index e580a3d..d9971f7 100644 --- a/FireTodo/Firebase/Snapshot+Identifiable.swift +++ b/FireTodo/Firebase/Snapshot+Identifiable.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import Foundation import FireSnapshot +import Foundation extension Snapshot: Identifiable { public var id: String { diff --git a/FireTodo/Redux/Auth/AuthAction.swift b/FireTodo/Redux/Auth/AuthAction.swift index df26c2f..7e8acf4 100644 --- a/FireTodo/Redux/Auth/AuthAction.swift +++ b/FireTodo/Redux/Auth/AuthAction.swift @@ -2,12 +2,12 @@ // Copyright © Suguru Kishimoto. All rights reserved. // +import Combine +import Firebase +import FireSnapshot import Foundation import ReSwift import ReSwiftThunk -import Firebase -import FireSnapshot -import Combine enum AuthAction: Action { case finishInitialLoad @@ -36,8 +36,8 @@ enum AuthAction: Action { finishInitialLoad() return AuthAction.updateUser(user: nil) } - } - .sink(receiveValue: dispatch) + } + .sink(receiveValue: dispatch) dispatch(AuthAction.subscribeAuthChange(cancellable: cancellable)) } diff --git a/FireTodo/Redux/Auth/AuthState.swift b/FireTodo/Redux/Auth/AuthState.swift index 5dcec9c..15ada17 100644 --- a/FireTodo/Redux/Auth/AuthState.swift +++ b/FireTodo/Redux/Auth/AuthState.swift @@ -2,17 +2,18 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import Foundation -import ReSwift +import Combine import Firebase import FireSnapshot -import Combine +import Foundation +import ReSwift struct AuthState: StateType { enum LoadingState { case initial case loaded } + var loadingState: LoadingState = .initial var user: Snapshot? var listenerHandle: AuthStateDidChangeListenerHandle? diff --git a/FireTodo/Redux/EditTask/EditTaskAction.swift b/FireTodo/Redux/EditTask/EditTaskAction.swift index 756db33..ace073c 100644 --- a/FireTodo/Redux/EditTask/EditTaskAction.swift +++ b/FireTodo/Redux/EditTask/EditTaskAction.swift @@ -2,9 +2,9 @@ // Copyright © Suguru Kishimoto. All rights reserved. // +import FireSnapshot import Foundation import ReSwift -import FireSnapshot enum EditTaskAction: Action { case startRequest @@ -13,7 +13,7 @@ enum EditTaskAction: Action { case reset static func saveTask(_ taskData: Model.Task, userID: String) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { dispatch, _ in dispatch(EditTaskAction.startRequest) Snapshot(data: taskData, path: Model.Path.tasks(userID: userID)).create { result in dispatch(EditTaskAction.endRequest) @@ -28,7 +28,7 @@ enum EditTaskAction: Action { } static func updateTask(_ taskData: Model.Task, taskID: String, userID: String) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { dispatch, _ in dispatch(EditTaskAction.startRequest) Snapshot(data: taskData, path: Model.Path.task(userID: userID, taskID: taskID)).update { result in dispatch(EditTaskAction.endRequest) diff --git a/FireTodo/Redux/Main/AppStore.swift b/FireTodo/Redux/Main/AppStore.swift index 5d637f5..f51b3ce 100644 --- a/FireTodo/Redux/Main/AppStore.swift +++ b/FireTodo/Redux/Main/AppStore.swift @@ -2,9 +2,9 @@ // Copyright © Suguru Kishimoto. All rights reserved. // +import Combine import Foundation import ReSwift -import Combine final class AppStore: StoreSubscriber, DispatchingStoreType, ObservableObject { private let store: Store diff --git a/FireTodo/Redux/Middleware/Logging/LoggingMiddleware.swift b/FireTodo/Redux/Middleware/Logging/LoggingMiddleware.swift index b6eaf24..2ca8e40 100644 --- a/FireTodo/Redux/Middleware/Logging/LoggingMiddleware.swift +++ b/FireTodo/Redux/Middleware/Logging/LoggingMiddleware.swift @@ -6,7 +6,7 @@ import Foundation import ReSwift func createLoggingMiddleware() -> Middleware { - return { dispatch, getState in + return { _, _ in { next in { action in print("> \(action)") diff --git a/FireTodo/Redux/SignUp/SignUpAction.swift b/FireTodo/Redux/SignUp/SignUpAction.swift index 878a189..ce8d0a7 100644 --- a/FireTodo/Redux/SignUp/SignUpAction.swift +++ b/FireTodo/Redux/SignUp/SignUpAction.swift @@ -2,11 +2,11 @@ // Copyright © Suguru Kishimoto. All rights reserved. // +import Firebase +import FireSnapshot import Foundation import ReSwift import ReSwiftThunk -import Firebase -import FireSnapshot enum SignUpAction: Action { case signUpStarted @@ -31,7 +31,7 @@ enum SignUpAction: Action { } private static func createUser(with uid: String, name: String, db: Firestore = .firestore()) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { dispatch, _ in let user = Model.User(username: name) Snapshot.init(data: user, path: Model.Path.user(userID: uid)).create { result in switch result { diff --git a/FireTodo/Redux/Tasks/TasksAction.swift b/FireTodo/Redux/Tasks/TasksAction.swift index 65a3106..854c437 100644 --- a/FireTodo/Redux/Tasks/TasksAction.swift +++ b/FireTodo/Redux/Tasks/TasksAction.swift @@ -2,10 +2,10 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import Foundation -import ReSwift import Firebase import FireSnapshot +import Foundation +import ReSwift enum TasksAction: Action { case updateTasks(tasks: [Snapshot]) @@ -13,7 +13,7 @@ enum TasksAction: Action { case removeListener static func subscribe(userID: String) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { dispatch, _ in let listener = Snapshot.listen(Model.Path.tasks(userID: userID)) { result in switch result { case let .success(tasks): @@ -36,13 +36,13 @@ enum TasksAction: Action { } static func deleteTask(_ task: Snapshot) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { _, _ in task.remove() } } static func toggleTaskCompleted(_ task: Snapshot) -> AppThunkAction { - AppThunkAction { dispatch, getState in + AppThunkAction { _, _ in task.data.completed.toggle() task.update() } diff --git a/FireTodo/Redux/Tasks/TasksReducer.swift b/FireTodo/Redux/Tasks/TasksReducer.swift index 13e7e8c..759e28a 100644 --- a/FireTodo/Redux/Tasks/TasksReducer.swift +++ b/FireTodo/Redux/Tasks/TasksReducer.swift @@ -15,7 +15,7 @@ enum TasksReducer { case let .updateTasks(tasks): state.tasks = tasks return state - case .registerListener(let listener): + case let .registerListener(listener): state.tasksListener = listener return state case .removeListener: diff --git a/FireTodo/Redux/Tasks/TasksState.swift b/FireTodo/Redux/Tasks/TasksState.swift index cebeb21..f4782b1 100644 --- a/FireTodo/Redux/Tasks/TasksState.swift +++ b/FireTodo/Redux/Tasks/TasksState.swift @@ -2,10 +2,10 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import Foundation -import ReSwift import Firebase import FireSnapshot +import Foundation +import ReSwift struct TasksState: StateType { var tasks: [Snapshot] = [] diff --git a/FireTodo/SceneDelegate.swift b/FireTodo/SceneDelegate.swift index b03de57..75fb212 100644 --- a/FireTodo/SceneDelegate.swift +++ b/FireTodo/SceneDelegate.swift @@ -2,12 +2,11 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import UIKit -import SwiftUI import ReSwift +import SwiftUI +import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? private lazy var main: AppMain = .init() @@ -37,4 +36,3 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func sceneDidEnterBackground(_ scene: UIScene) { } } - diff --git a/FireTodo/Views/Common/LoadingView.swift b/FireTodo/Views/Common/LoadingView.swift index 48e7a67..1e42afa 100644 --- a/FireTodo/Views/Common/LoadingView.swift +++ b/FireTodo/Views/Common/LoadingView.swift @@ -9,6 +9,7 @@ struct LoadingView: View { init(isLoading: Bool) { self.isLoading = isLoading } + var body: some View { ZStack { if isLoading { @@ -25,8 +26,10 @@ struct LoadingView: View { } } +#if DEBUG struct LoadingView_Previews: PreviewProvider { static var previews: some View { LoadingView(isLoading: true) } } +#endif diff --git a/FireTodo/Views/Common/RightDownFloatButton.swift b/FireTodo/Views/Common/RightDownFloatButton.swift index ac1784b..62252b9 100644 --- a/FireTodo/Views/Common/RightDownFloatButton.swift +++ b/FireTodo/Views/Common/RightDownFloatButton.swift @@ -5,11 +5,11 @@ import SwiftUI struct RightDownFloatButton: View { - private let action: () -> Void init(action: @escaping () -> Void = {}) { self.action = action } + var body: some View { VStack { Spacer() @@ -29,9 +29,10 @@ struct RightDownFloatButton: View { } } +#if DEBUG struct RightDownFloatButton_Previews: PreviewProvider { static var previews: some View { RightDownFloatButton() } } - +#endif diff --git a/FireTodo/Views/EditTask/ColorSelectView.swift b/FireTodo/Views/EditTask/ColorSelectView.swift index d9ff14a..222e260 100644 --- a/FireTodo/Views/EditTask/ColorSelectView.swift +++ b/FireTodo/Views/EditTask/ColorSelectView.swift @@ -28,8 +28,10 @@ struct ColorSelectView: View { } } +#if DEBUG struct ColorSelectView_Previews: PreviewProvider { static var previews: some View { ColorSelectView(color: .red, selected: true) } } +#endif diff --git a/FireTodo/Views/EditTask/EditTaskView.swift b/FireTodo/Views/EditTask/EditTaskView.swift index 15a0fce..92e847a 100644 --- a/FireTodo/Views/EditTask/EditTaskView.swift +++ b/FireTodo/Views/EditTask/EditTaskView.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import SwiftUI import FireSnapshot +import SwiftUI class EditTaskViewModel: ObservableObject { @Published var title: String = "" @@ -46,7 +46,7 @@ struct EditTaskView: View { init(task: Snapshot? = nil) { self.task = task - viewModel = EditTaskViewModel(task: task) + viewModel = EditTaskViewModel(task: task) } var body: some View { @@ -72,7 +72,7 @@ struct EditTaskView: View { withAnimation { self.viewModel.color = color } - } + } } Spacer() @@ -117,8 +117,10 @@ struct EditTaskView: View { } } +#if DEBUG struct EditTaskView_Previews: PreviewProvider { static var previews: some View { - EditTaskView() + EditTaskView().environmentObject(AppMain().store) } } +#endif diff --git a/FireTodo/Views/Profile/ProfileView.swift b/FireTodo/Views/Profile/ProfileView.swift index 74aa8ec..57da33e 100644 --- a/FireTodo/Views/Profile/ProfileView.swift +++ b/FireTodo/Views/Profile/ProfileView.swift @@ -32,7 +32,7 @@ struct ProfileView: View { .overlay( Capsule(style: .continuous) .stroke(Color.primary, lineWidth: 2.0) - ) + ) } .disabled(self.store.state.authState.user == nil) @@ -52,13 +52,17 @@ struct ProfileView: View { ActionSheet.Button.destructive(Text("Sign Out")) { self.store.dispatch(AuthAction.signOut()) }, - ActionSheet.Button.cancel()]) + ActionSheet.Button.cancel(), + ] + ) } } } -//struct ProfileView_Previews: PreviewProvider { -// static var previews: some View { -// ProfileView() -// } -//} +#if DEBUG +struct ProfileView_Previews: PreviewProvider { + static var previews: some View { + ProfileView().environmentObject(AppMain().store) + } +} +#endif diff --git a/FireTodo/Views/SignUp/SignUpView.swift b/FireTodo/Views/SignUp/SignUpView.swift index 197fca3..e37c590 100644 --- a/FireTodo/Views/SignUp/SignUpView.swift +++ b/FireTodo/Views/SignUp/SignUpView.swift @@ -10,6 +10,7 @@ struct SignUpView: View { private var canRegister: Bool { name.count >= 3 && name.count <= 16 } + var body: some View { GeometryReader { geometry in ZStack { @@ -25,7 +26,6 @@ struct SignUpView: View { } .padding() - Button(action: { self.store.dispatch(SignUpAction.signUp(with: self.name)) }) { @@ -36,7 +36,7 @@ struct SignUpView: View { .overlay( Capsule(style: .continuous) .stroke(self.canRegister ? Color.primary : Color.gray, lineWidth: 2.0) - ) + ) } .opacity(self.canRegister ? 1.0 : 0.5) .disabled(!self.canRegister) @@ -50,9 +50,9 @@ struct SignUpView: View { } #if DEBUG -struct SignUpView_Previews: PreviewProvider { - static var previews: some View { - SignUpView() + struct SignUpView_Previews: PreviewProvider { + static var previews: some View { + SignUpView().environmentObject(AppMain().store) + } } -} #endif diff --git a/FireTodo/Views/Tasks/TasksRow.swift b/FireTodo/Views/Tasks/TasksRow.swift index d99213e..fde11b9 100644 --- a/FireTodo/Views/Tasks/TasksRow.swift +++ b/FireTodo/Views/Tasks/TasksRow.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import SwiftUI import FireSnapshot +import SwiftUI struct TasksRow: View { private let task: Snapshot @@ -13,6 +13,7 @@ struct TasksRow: View { self.task = task self.onTapCompleted = onTapCompleted } + var body: some View { VStack { HStack(spacing: 16.0) { @@ -48,8 +49,10 @@ struct TasksRow: View { } } -//struct TasksRow_Previews: PreviewProvider { -// static var previews: some View { -// TasksRow(task: .init(title: "test")) {} -// } -//} +#if DEBUG +struct TasksRow_Previews: PreviewProvider { + static var previews: some View { + TasksRow(task: Snapshot(data: .init(), path: Model.Path.tasks(userID: "xxx"))) {} + } +} +#endif diff --git a/FireTodo/Views/Tasks/TasksView.swift b/FireTodo/Views/Tasks/TasksView.swift index 582f013..64f2e9b 100644 --- a/FireTodo/Views/Tasks/TasksView.swift +++ b/FireTodo/Views/Tasks/TasksView.swift @@ -2,8 +2,8 @@ // Copyright © Suguru Kishimoto. All rights reserved. // -import SwiftUI import FireSnapshot +import SwiftUI class DeleteActionSheetState: ObservableObject { @Published var showActionSheet: Bool = false @@ -71,8 +71,7 @@ struct TasksView: View { Image(systemName: "person.crop.circle.fill") .resizable() .frame(width: 30.0, height: 30.0) - } - ) + }) } .background( EmptyView().sheet(isPresented: $showEditTask) { @@ -97,7 +96,9 @@ struct TasksView: View { self.store.dispatch(TasksAction.deleteTask(task)) } }, - ActionSheet.Button.cancel()]) + ActionSheet.Button.cancel(), + ] + ) } .onAppear { if let userID = self.store.state.authState.user?.reference.documentID { @@ -110,8 +111,10 @@ struct TasksView: View { } } +#if DEBUG struct TasksView_Previews: PreviewProvider { static var previews: some View { - TasksView() + TasksView().environmentObject(AppMain().store) } } +#endif diff --git a/Podfile b/Podfile index dad446c..b0595f5 100644 --- a/Podfile +++ b/Podfile @@ -1,6 +1,10 @@ source 'https://cdn.cocoapods.org/' platform :ios, '13.0' +# Tools +pod 'SwiftFormat/CLI', '~> 0.40.0' +pod 'SwiftLint', '~> 0.35.0' + target 'FireTodo' do use_frameworks! # Firebase diff --git a/Podfile.lock b/Podfile.lock index 3f00d00..e1c5722 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -122,6 +122,8 @@ PODS: - ReSwiftThunk/Core (= 1.2.0) - ReSwiftThunk/Core (1.2.0): - ReSwift (~> 5.0) + - SwiftFormat/CLI (0.40.12) + - SwiftLint (0.35.0) DEPENDENCIES: - Firebase/Auth @@ -130,10 +132,14 @@ DEPENDENCIES: - FireSnapshot (~> 0.1) - ReSwift (~> 5.0) - ReSwiftThunk (~> 1.2) + - SwiftFormat/CLI (~> 0.40.0) + - SwiftLint (~> 0.35.0) SPEC REPOS: https://cdn.cocoapods.org/: - FireSnapshot + - SwiftFormat + - SwiftLint https://github.com/CocoaPods/Specs.git: - BoringSSL-GRPC - Firebase @@ -182,7 +188,9 @@ SPEC CHECKSUMS: Protobuf: 67fb42ba613def994e61854de2b3164f13790cc4 ReSwift: 628f1a9b3ee52e3b3ca2a644435472fd77afafe1 ReSwiftThunk: 23c8ea9092d9dc94b72005f19352dbd37fa42533 + SwiftFormat: 73667bbb741386b0febf0bd1a1b8c502aa9d1c98 + SwiftLint: 5553187048b900c91aa03552807681bb6b027846 -PODFILE CHECKSUM: 4d4cb6396afd5778bcac238e3a77027705402de9 +PODFILE CHECKSUM: ceb8b846a35663172ff47edadcc9210f653fd031 COCOAPODS: 1.8.1 diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100755 index 0000000..713528c --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,5 @@ +#!/bin/sh +cd `dirname $0` +cd ../ + +./Pods/SwiftFormat/CommandLineTool/swiftformat FireTodo --config '.swiftformat'