diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKit.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKit.xcscheme
new file mode 100644
index 0000000..222c885
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKit.xcscheme
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKitTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKitTests.xcscheme
new file mode 100644
index 0000000..7d90eee
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/ComposableLogsSheetKitTests.xcscheme
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Package.resolved b/Package.resolved
index cd1cea7..77e5e4c 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -1,5 +1,23 @@
{
"pins" : [
+ {
+ "identity" : "combine-schedulers",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/combine-schedulers",
+ "state" : {
+ "revision" : "aa3e575929f2bcc5bad012bd2575eae716cbcdf7",
+ "version" : "0.8.0"
+ }
+ },
+ {
+ "identity" : "logssheetkit",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/riiid/LogsSheetKit",
+ "state" : {
+ "revision" : "5bb7cc405d718e86f9362e6a335230e2e295801b",
+ "version" : "0.9.0"
+ }
+ },
{
"identity" : "spindicator",
"kind" : "remoteSourceControl",
@@ -8,6 +26,60 @@
"revision" : "43600857729d9efff046dc6673e6f94e095882c7",
"version" : "1.6.4"
}
+ },
+ {
+ "identity" : "swift-case-paths",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/swift-case-paths",
+ "state" : {
+ "revision" : "7346701ea29da0a85d4403cf3d7a589a58ae3dee",
+ "version" : "0.9.2"
+ }
+ },
+ {
+ "identity" : "swift-collections",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/apple/swift-collections",
+ "state" : {
+ "revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
+ "version" : "1.0.3"
+ }
+ },
+ {
+ "identity" : "swift-composable-architecture",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/swift-composable-architecture",
+ "state" : {
+ "revision" : "9ea8c763061287052a68d5e6723fed45e898b7d9",
+ "version" : "0.40.2"
+ }
+ },
+ {
+ "identity" : "swift-custom-dump",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/swift-custom-dump",
+ "state" : {
+ "revision" : "819d9d370cd721c9d87671e29d947279292e4541",
+ "version" : "0.6.0"
+ }
+ },
+ {
+ "identity" : "swift-identified-collections",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/swift-identified-collections",
+ "state" : {
+ "revision" : "bfb0d43e75a15b6dfac770bf33479e8393884a36",
+ "version" : "0.4.1"
+ }
+ },
+ {
+ "identity" : "xctest-dynamic-overlay",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
+ "state" : {
+ "revision" : "30314f1ece684dd60679d598a9b89107557b67d9",
+ "version" : "0.4.1"
+ }
}
],
"version" : 2
diff --git a/Package.swift b/Package.swift
index 11c9b37..17cd3ab 100644
--- a/Package.swift
+++ b/Package.swift
@@ -3,26 +3,31 @@
import PackageDescription
let package = Package(
- name: "LogsSheetKit",
+ name: "ComposableLogsSheetKit",
platforms: [
.iOS(.v14)
],
products: [
.library(
- name: "LogsSheetKit",
- targets: ["LogsSheetKit"]),
+ name: "ComposableLogsSheetKit",
+ targets: ["ComposableLogsSheetKit"]),
],
dependencies: [
- .package(url: "https://github.com/ivanvorobei/SPIndicator", .upToNextMajor(from: "1.6.0"))
+ .package(url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "0.40.0")),
+ .package(url: "https://github.com/riiid/LogsSheetKit", .upToNextMajor(from: "0.9.0"))
],
targets: [
.target(
- name: "LogsSheetKit",
+ name: "ComposableLogsSheetKit",
dependencies: [
- "SPIndicator"
+ "LogsSheetKit",
+ .product(name: "ComposableArchitecture", package: "swift-composable-architecture")
]),
.testTarget(
- name: "LogsSheetKitTests",
- dependencies: ["LogsSheetKit"]),
+ name: "ComposableLogsSheetKitTests",
+ dependencies: [
+ "ComposableLogsSheetKit",
+ "LogsSheetKit"
+ ]),
]
)
diff --git a/Sources/ComposableLogsSheetKit/Extensions/TCA/Reducer+Log.swift b/Sources/ComposableLogsSheetKit/Extensions/TCA/Reducer+Log.swift
new file mode 100644
index 0000000..627025f
--- /dev/null
+++ b/Sources/ComposableLogsSheetKit/Extensions/TCA/Reducer+Log.swift
@@ -0,0 +1,40 @@
+//
+// Reducer+Log.swift
+//
+//
+// Created by Yessen Yermukhanbet on 2022/10/05.
+// Copyright © 2022 Riiid Inc. All rights reserved.
+//
+
+import Foundation
+import ComposableArchitecture
+
+extension Reducer where State: LoggableState {
+ /// Saves each action run through the reducer as the log message if debug build configuration is on
+ /// - Parameters:
+ /// - isDebug: is debug configuration on
+ public func log(isDebug: Bool) -> Self {
+ .init { state, action, environment in
+ if isDebug {
+ state.logs.append(.init(message: "\(action)"))
+ }
+ return self.run(&state, action, environment)
+ }
+ }
+
+ /// Saves the custom log message if debug build configuration is on
+ /// - Parameters:
+ /// - isDebug: is debug configuration on
+ /// - message: custom log message
+ public func log(
+ isDebug: Bool,
+ with message: @escaping ((Action) -> String)
+ ) -> Self {
+ .init { state, action, environment in
+ if isDebug {
+ state.logs.append(.init(message: message(action)))
+ }
+ return self.run(&state, action, environment)
+ }
+ }
+}
diff --git a/Sources/ComposableLogsSheetKit/LoggableState.swift b/Sources/ComposableLogsSheetKit/LoggableState.swift
new file mode 100644
index 0000000..e2a66f4
--- /dev/null
+++ b/Sources/ComposableLogsSheetKit/LoggableState.swift
@@ -0,0 +1,30 @@
+//
+// File.swift
+//
+//
+// Created by Yessen Yermukhanbet on 2022/10/05.
+// Copyright © 2022 Riiid Inc. All rights reserved.
+//
+
+import Foundation
+import LogsSheetKit
+
+public protocol LoggableState: Equatable {
+ var logs: [ActionLog] { get set }
+}
+
+extension LoggableState {
+ var logs: [ActionLog] {
+ get {
+ return GlobalLogs.shared.logs
+ }
+ set {
+ GlobalLogs.shared.logs = newValue
+ }
+ }
+}
+
+struct GlobalLogs {
+ static var shared: GlobalLogs = GlobalLogs()
+ var logs: [ActionLog] = []
+}
diff --git a/Sources/LogsSheetKit/ActionLog.swift b/Sources/LogsSheetKit/ActionLog.swift
deleted file mode 100644
index 88d51c9..0000000
--- a/Sources/LogsSheetKit/ActionLog.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// ActionLog.swift
-//
-//
-// Created by Yessen Yermukhanbet on 2022/10/04.
-// Copyright © 2022 Riiid Inc. All rights reserved.
-//
-
-import Foundation
-
-public struct ActionLog: Equatable, Identifiable {
- public var id: UUID = .init()
- public var message: String
- public var timeStamp: Date = Date()
-
- public init(message: String) {
- self.message = message
- }
-}
diff --git a/Sources/LogsSheetKit/LogsSheet.swift b/Sources/LogsSheetKit/LogsSheet.swift
deleted file mode 100644
index eeb82c4..0000000
--- a/Sources/LogsSheetKit/LogsSheet.swift
+++ /dev/null
@@ -1,146 +0,0 @@
-//
-// LogsSheet.swift
-//
-// Created by Jiyeon Song on 2022/06/17.
-// Copyright © 2022 Riiid Inc. All rights reserved.
-//
-
-import SPIndicator
-import SwiftUI
-
-public struct LogsSheet: View {
- @Environment(\.presentationMode) private var presentationMode: Binding
-
- private let logs: [ActionLog]
- private let clearAction: () -> Void
-
- @State private var isAscending: Bool = false
- @State private var showCopiedIndicator: Bool = false
- @State private var searchText: String = ""
-
- public init(logs: [ActionLog], clearAction: @escaping () -> Void) {
- self.logs = logs
- self.clearAction = clearAction
- }
-
- private var filteredLogs: [ActionLog] {
- let sortedLogs: [ActionLog] = logs
- .sorted(by: {
- isAscending
- ? $0.timeStamp < $1.timeStamp
- : $0.timeStamp > $1.timeStamp
- })
- return searchText.isEmpty
- ? sortedLogs
- : sortedLogs.filter { $0.message.localizedCaseInsensitiveContains(searchText) }
- }
-
- public var body: some View {
- NavigationView {
- List {
- ForEach(filteredLogs) { log in
- Section(header: Text(log.timeStamp, formatter: dateFormatter)) {
- ScrollView(.horizontal, showsIndicators: false) {
- Button(
- action: {
- UIPasteboard.general.string = dateFormatter.string(from: log.timeStamp) + "\n" + log.message
- showCopiedIndicator = true
- },
- label: {
- Text(log.message)
- .font(Font.system(size: 12, design: .monospaced))
- .foregroundColor(.primary)
- .multilineTextAlignment(.leading)
- .padding()
- }
- )
- }
- .listRowInsets(.init())
- }
- }
- }
- .SPIndicator(
- isPresent: $showCopiedIndicator,
- title: "Copied to clipboard",
- duration: 3.0
- )
- .listStyle(.grouped)
- .navigationBarTitle("Logs for Debug")
- .modified {
- if #available(iOS 15.0, *) {
- $0.searchable(text: $searchText)
- } else {
- $0
- }
- }
- .toolbar {
- ToolbarItemGroup(placement: .bottomBar) {
- Button(
- action: {
- UIPasteboard.general.string = logs
- .map { dateFormatter.string(from: $0.timeStamp) + "\n" + $0.message }
- .joined(separator: "\n")
- showCopiedIndicator = true
- },
- label: {
- Text("Copy All")
- }
- )
- Spacer()
- Button(
- action: clearAction,
- label: {
- Text("Clear")
- }
- )
- }
- ToolbarItem(placement: .automatic) {
- Button(
- action: { isAscending.toggle() },
- label: {
- Image(systemName: isAscending ? "arrow.up.arrow.down.circle.fill" : "arrow.up.arrow.down.circle")
- .renderingMode(.template)
- .foregroundColor(.secondary)
- }
- )
- }
- ToolbarItem(placement: .destructiveAction) {
- Button(
- action: { presentationMode.wrappedValue.dismiss() },
- label: {
- Image(systemName: "xmark.circle.fill")
- .renderingMode(.template)
- .foregroundColor(.secondary)
- }
- )
- }
- }
- }
- }
-}
-
-private let dateFormatter: ISO8601DateFormatter = {
- let formatter: ISO8601DateFormatter = .init()
- formatter.timeZone = TimeZone.autoupdatingCurrent
- return formatter
-}()
-
-// MARK: Previewer
-
-struct LogsSheet_Previews: PreviewProvider {
- static private let logsStub: [ActionLog] = [
- ActionLog(message: "stub action log"),
- ActionLog(message: "stub action log"),
- ActionLog(message: "stub action log")
- ]
-
- static var previews: some View {
- Group {
- LogsSheet(logs: [], clearAction: {})
- .previewDisplayName("LogsSheet | empty")
-
- LogsSheet(logs: logsStub, clearAction: {})
- .previewDisplayName("LogsSheet | non empty")
- }
- }
-}
diff --git a/Sources/LogsSheetKit/View+Modified.swift b/Sources/LogsSheetKit/View+Modified.swift
deleted file mode 100644
index 2afbe61..0000000
--- a/Sources/LogsSheetKit/View+Modified.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// View+Modified.swift
-//
-// Created by Dongkyu Kim on 2022/06/30.
-// Copyright © 2022 Riiid Inc. All rights reserved.
-//
-
-import SwiftUI
-
-extension View {
- func modified(@ViewBuilder modification: (Self) -> Modified) -> some View {
- return modification(self)
- }
-}
diff --git a/Tests/ComposableLogsSheetKitTests/LoggableStateTests.swift b/Tests/ComposableLogsSheetKitTests/LoggableStateTests.swift
new file mode 100644
index 0000000..d3b5daa
--- /dev/null
+++ b/Tests/ComposableLogsSheetKitTests/LoggableStateTests.swift
@@ -0,0 +1,42 @@
+//
+// LoggableStateTests.swift
+//
+//
+// Created by Yessen Yermukhanbet on 2022/10/05.
+// Copyright © 2022 Riiid Inc. All rights reserved.
+//
+
+import XCTest
+import LogsSheetKit
+@testable import ComposableLogsSheetKit
+
+final class LoggableStateTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ GlobalLogs.shared.logs = [] // Clean up before each test
+ }
+
+ private struct StubState: LoggableState { }
+
+ func testLoggableStateAtTheBeginningLogsEmpty() {
+ let stub: StubState = StubState()
+ XCTAssertTrue(stub.logs.count == 0)
+ }
+
+ func testLoggableStateAppendsLogs() {
+ var stub: StubState = StubState()
+
+ let logs: [ActionLog] = [
+ ActionLog(message: "stub"),
+ ActionLog(message: "stub"),
+ ActionLog(message: "stub"),
+ ]
+
+ for log in logs {
+ stub.logs.append(log)
+ }
+
+ XCTAssertTrue(stub.logs.count == logs.count)
+ }
+}
diff --git a/Tests/LogsSheetKitTests/LogsSheetKitTests.swift b/Tests/LogsSheetKitTests/LogsSheetKitTests.swift
deleted file mode 100644
index 317f789..0000000
--- a/Tests/LogsSheetKitTests/LogsSheetKitTests.swift
+++ /dev/null
@@ -1,7 +0,0 @@
-import XCTest
-@testable import LogsSheetKit
-
-final class LogsSheetKitTests: XCTestCase {
- func testExample() throws {
- }
-}