├── TransNotion
├── Debug.xcconfig
├── Release.xcconfig
├── Assets.xcassets
│ ├── Contents.json
│ ├── notion_icon.imageset
│ │ ├── notion_icon.png
│ │ └── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── en.lproj
│ └── Localizable.strings
├── Service
│ ├── Database
│ │ ├── Remote
│ │ │ ├── DatabaseEntity.swift
│ │ │ ├── DatabasePathBuilder.swift
│ │ │ ├── CollectionReference+Combine.swift
│ │ │ ├── DocumentReference+Combine.swift
│ │ │ └── Database.swift
│ │ └── Local
│ │ │ └── LocalStore.swift
│ ├── Logger
│ │ └── ErrorLogger.swift
│ └── Auth
│ │ ├── Auth.swift
│ │ └── OAuth.swift
├── ja.lproj
│ └── Localizable.strings
├── Entity
│ ├── Me.swift
│ ├── Credential.swift
│ └── User.swift
├── Modifier
│ └── Placeholder.swift
├── Secret.swift.sample
├── ContentView.swift
├── Extension
│ ├── Notion.Object.Page+Extension.swift
│ └── JSONCoder+Extension.swift
├── Style
│ ├── Toggle.swift
│ ├── Button.swift
│ └── Color+Extension.swift
├── Environment
│ ├── Environment+notion.swift
│ └── Environment+Window.swift
├── RootView.swift
├── Domain
│ ├── NotionWebView
│ │ ├── NotionWebViewPage.swift
│ │ └── NotionWebView.swift
│ ├── Login
│ │ └── LoginView.swift
│ ├── NotionPages
│ │ └── NotionPagesView.swift
│ └── NotionPage
│ │ └── NotionPage.swift
├── AppDelegate.swift
├── TransNotionApp.swift
└── Info.plist
├── .gitignore
├── TransNotion.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
├── xcshareddata
│ └── xcschemes
│ │ └── TransNotion.xcscheme
└── project.pbxproj
├── Makefile
├── TransNotionTests
├── Info.plist
└── TransNotionTests.swift
├── TransNotionUITests
├── Info.plist
└── TransNotionUITests.swift
└── scripts
└── secret.sh
/TransNotion/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Debug-Secret.xcconfig"
2 |
--------------------------------------------------------------------------------
/TransNotion/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Release-Secret.xcconfig"
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | Secret.swift
3 | GoogleService-Info.plist
4 | GoogleService*.plist
5 | *-Secret.xcconfig
6 |
--------------------------------------------------------------------------------
/TransNotion/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TransNotion/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TransNotion/Assets.xcassets/notion_icon.imageset/notion_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bannzai/TransNotion-Swift/HEAD/TransNotion/Assets.xcassets/notion_icon.imageset/notion_icon.png
--------------------------------------------------------------------------------
/TransNotion/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TransNotion
4 |
5 | Created by Yudai.Hirose on 2021/05/15.
6 |
7 | */
8 |
9 | "Login with Notion" = "Login with Notion";
10 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Remote/DatabaseEntity.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol DatabaseEntity: Codable {
4 | associatedtype WhereKey: CodingKey & RawRepresentable where WhereKey.RawValue == String
5 | }
6 |
--------------------------------------------------------------------------------
/TransNotion.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TransNotion/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/TransNotion/ja.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | TransNotion
4 |
5 | Created by Yudai.Hirose on 2021/05/15.
6 |
7 | */
8 |
9 | "Login with Notion" = "Notionでログイン";
10 | "Translate this page" = "このページを翻訳する";
11 |
--------------------------------------------------------------------------------
/TransNotion/Entity/Me.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Me: Identifiable, Equatable {
4 | let id: ID
5 | var userID: UserID { UserID(rawValue: id.rawValue) }
6 |
7 | struct ID: RawRepresentable, Equatable, Hashable {
8 | let rawValue: String
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/TransNotion/Modifier/Placeholder.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | extension View {
4 | @ViewBuilder func placeholder(when showPlaceholder: Bool) -> some View {
5 | if showPlaceholder {
6 | redacted(reason: .placeholder)
7 | } else {
8 | unredacted()
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/TransNotion.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | .PHONY: secret
5 | secret:
6 | echo $(DEVELOPMENT_GOOGLE_SERVICE_INFO_PLIST) | base64 -D > TransNotion/GoogleService-Info-dev.plist
7 | echo $(DEBUG_SECRET_XCCONFIG) | base64 -D > TransNotion/Debug-Secret.xcconfig
8 | echo $(RELEASE_SECRET_XCCONFIG) | base64 -D > TransNotion/Release-Secret.xcconfig
9 | ./scripts/secret.sh
10 |
--------------------------------------------------------------------------------
/TransNotion/Secret.swift.sample:
--------------------------------------------------------------------------------
1 |
2 |
3 | enum Secret {
4 | static let notionOAuthClientID = "NOTION_OAUTH_CLIENT_ID"
5 | static let notionOAuthRedirectURI = "NOTION_OAUTH_REDIRECT_URI"
6 | static let notionOAuthCallbackCustomURLScheme = "NOTION_OAUTH_CALLBACK_CUSTOM_URL_SCHEME"
7 | static let notionOAuthClientSecret = "NOTION_OAUTH_CLIENT_SECRET"
8 | }
9 |
--------------------------------------------------------------------------------
/TransNotion/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 | var body: some View {
12 | NotionPagesView()
13 | }
14 | }
15 |
16 | struct ContentView_Previews: PreviewProvider {
17 | static var previews: some View {
18 | ContentView()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/TransNotion/Assets.xcassets/notion_icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "notion_icon.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/TransNotion/Extension/Notion.Object.Page+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notion.Object.Page+Extension.swift
3 | // TransNotion
4 | //
5 | // Created by 廣瀬雄大 on 2021/06/22.
6 | //
7 |
8 | import Foundation
9 | import notion
10 |
11 | extension Object.Page {
12 | private var publishedPageID: String {
13 | id.replacingOccurrences(of: "-", with: "")
14 | }
15 |
16 | func pageURL() -> URL? {
17 | .init(string: "https://www.notion.so/\(publishedPageID)")
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TransNotion/Entity/Credential.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Credential.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import Foundation
9 |
10 | struct Credential: Codable {
11 | let accessToken: String
12 | let workspaceName: String
13 | // NOTE: workspaceIcon is exists into document. But exactly not contains in response
14 | let workspaceIcon: String?
15 | let botId: String
16 | }
17 |
18 | struct Credentials: Codable, LocalStoreKey {
19 | var elements: [Credential]
20 | }
21 |
--------------------------------------------------------------------------------
/TransNotion/Service/Logger/ErrorLogger.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorLogger.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import Foundation
9 | import FirebaseCrashlytics
10 |
11 | protocol ErrorLogger {
12 | func record(error: Swift.Error)
13 | }
14 | private struct _ErrorLogger: ErrorLogger {
15 | func record(error: Error) {
16 | print("error: \(error)")
17 | Crashlytics.crashlytics().record(error: error)
18 | }
19 | }
20 |
21 | let errorLogger: ErrorLogger = _ErrorLogger()
22 |
--------------------------------------------------------------------------------
/TransNotion/Style/Toggle.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct CheckBoxToggleStyle: ToggleStyle {
4 | func makeBody(configuration: Configuration) -> some View {
5 | return HStack {
6 | configuration.label
7 | Spacer()
8 | Image(systemName: configuration.isOn ? "checkmark.square" : "square")
9 | .resizable()
10 | .frame(width: 20, height: 20)
11 | .padding()
12 | .onTapGesture { configuration.isOn.toggle() }
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TransNotion/Style/Button.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct PrimaryButtonStyle: ButtonStyle {
4 | @Environment(\.isEnabled) var isEnabled
5 | let width: CGFloat
6 |
7 | func makeBody(configuration: Configuration) -> some View {
8 | configuration.label
9 | .opacity(configuration.isPressed ? 0.2 : 1.0)
10 | .frame(maxWidth: width)
11 | .padding(.vertical, 14)
12 | .background(isEnabled ? Color.appPrimary : Color.appPrimary.opacity(0.4))
13 | .foregroundColor(.white)
14 | .cornerRadius(4)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TransNotion/Environment/Environment+notion.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Environment+notion.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/17.
6 | //
7 |
8 | import Foundation
9 | import notion
10 | import SwiftUI
11 |
12 | struct NotionAPIClientKey: EnvironmentKey {
13 | static let defaultValue: notion.Session = .shared
14 | }
15 |
16 | extension EnvironmentValues {
17 | var notion: notion.Session {
18 | get {
19 | self[NotionAPIClientKey.self]
20 | }
21 | set {
22 | self[NotionAPIClientKey.self] = newValue
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/TransNotion/Entity/User.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import FirebaseFirestore
3 | import FirebaseFirestoreSwift
4 |
5 | struct UserID: RawRepresentable, Codable, DocumentIDWrappable, Hashable {
6 | let rawValue: String
7 |
8 | static func wrap(_ documentReference: DocumentReference) throws -> UserID {
9 | UserID(rawValue: documentReference.documentID)
10 | }
11 | }
12 |
13 | struct User: DatabaseEntity, Equatable, Identifiable {
14 | @DocumentID var id: UserID?
15 | let anonymousUserID: UserID
16 |
17 | enum CodingKeys: String, CodingKey {
18 | case anonymousUserID
19 | }
20 | typealias WhereKey = CodingKeys
21 | }
22 |
--------------------------------------------------------------------------------
/TransNotion/Extension/JSONCoder+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONCoder+Extension.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import Foundation
9 |
10 | extension JSONDecoder {
11 | static let convertFromSnakeCase: JSONDecoder = {
12 | let decoder = JSONDecoder()
13 | decoder.keyDecodingStrategy = .convertFromSnakeCase
14 | return decoder
15 | }()
16 | }
17 | extension JSONEncoder {
18 | static let convertToSnakeCase: JSONEncoder = {
19 | let encoder = JSONEncoder()
20 | encoder.keyEncodingStrategy = .convertToSnakeCase
21 | return encoder
22 | }()
23 | }
24 |
--------------------------------------------------------------------------------
/TransNotion/Style/Color+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Color+Extension.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension SwiftUI.Color {
11 | // #4c5870
12 | static let appPrimary: Color = Color(red: 76 / 255, green: 88 / 255, blue: 112 / 255)
13 |
14 | // #3d3d3b
15 | static let appGray: Color = Color(red: 61 / 255, green: 61 / 255, blue: 59 / 255)
16 |
17 | // #a2a9af
18 | static let background: Color = Color(red: 162 / 255, green: 162 / 255, blue: 175 / 255)
19 |
20 | // #ebedec
21 | static let textColor: Color = Color(red: 235 / 255, green: 237 / 255, blue: 236 / 255)
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Remote/DatabasePathBuilder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import FirebaseFirestore
3 |
4 | struct DatabaseDocumentPathBuilder {
5 | let path: String
6 | }
7 |
8 | struct DatabaseCollectionPathBuilder {
9 | let path: String
10 | var args: (key: Entity.WhereKey, relations: [CollectionRelation])? = nil
11 | var isGroup: Bool = false
12 |
13 | static func users() -> DatabaseCollectionPathBuilder { .init(path: "/users") }
14 | }
15 |
16 | enum CollectionRelation {
17 | case equal(Any)
18 | case less(Any)
19 | case lessOrEqual(Any)
20 | case greater(Any)
21 | case greaterOrEqual(Any)
22 | case notEqual(Any)
23 | case contains([Any])
24 | }
25 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Remote/CollectionReference+Combine.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Combine
3 | import FirebaseFirestore
4 | import FirebaseFirestoreSwift
5 |
6 | extension CollectionReference {
7 | // MARK: - Add
8 | func add(value: T) -> AnyPublisher {
9 | return Future { [weak self] promise in
10 | do {
11 | _ = try self?.addDocument(from: value, encoder: Firestore.Encoder()) { error in
12 | if let error = error {
13 | promise(.failure(error))
14 | }
15 | promise(.success(value))
16 | }
17 | } catch {
18 | promise(.failure(error))
19 | }
20 | }.eraseToAnyPublisher()
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/TransNotionTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/TransNotionUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/scripts/secret.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | set -eu
3 | set -o pipefail
4 |
5 | SECRET_FILE_PATH=`dirname $0`/../TransNotion
6 | cd $SECRET_FILE_PATH
7 |
8 | echo $(pwd -P)
9 |
10 | cp -i Secret.swift.sample Secret.swift
11 |
12 | echo 'Start to replace from NOTION_OAUTH_CLIENT_ID, NOTION_OAUTH_REDIRECT_URI, NOTION_OAUTH_CALLBACK_CUSTOM_URL_SCHEME, NOTION_OAUTH_CLIENT_SECRET'
13 |
14 | sed -i '' -e "s;NOTION_OAUTH_CLIENT_ID;$NOTION_OAUTH_CLIENT_ID;" Secret.swift
15 | sed -i '' -e "s;NOTION_OAUTH_REDIRECT_URI;$NOTION_OAUTH_REDIRECT_URI;" Secret.swift
16 | sed -i '' -e "s;NOTION_OAUTH_CALLBACK_CUSTOM_URL_SCHEME;$NOTION_OAUTH_CALLBACK_CUSTOM_URL_SCHEME;" Secret.swift
17 | sed -i '' -e "s;NOTION_OAUTH_CLIENT_SECRET;$NOTION_OAUTH_CLIENT_SECRET;" Secret.swift
18 |
19 | echo 'Done to replace from NOTION_OAUTH_CLIENT_ID, NOTION_OAUTH_REDIRECT_URI, NOTION_OAUTH_CALLBACK_CUSTOM_URL_SCHEME, NOTION_OAUTH_CLIENT_SECRET'
20 |
--------------------------------------------------------------------------------
/TransNotion/RootView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootView.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import SwiftUI
9 | import notion
10 |
11 | struct RootView: View {
12 | @EnvironmentObject var state: TransNotionApp.State
13 | var body: some View {
14 | if state.isLogin, let credential = state.credential {
15 | ContentView()
16 | .environment(\.notion, {
17 | let session = notion.Session.shared
18 | session.setAuthorization(token: credential.accessToken)
19 | return session
20 | }())
21 | } else {
22 | LoginView()
23 | .environmentObject(state)
24 | }
25 | }
26 | }
27 |
28 | struct RootView_Previews: PreviewProvider {
29 | static var previews: some View {
30 | RootView()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TransNotion/Environment/Environment+Window.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Widnow.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import UIKit
9 | import SwiftUI
10 |
11 | typealias KeyWindowClosure = () -> UIWindow?
12 |
13 | struct KeyWindowKey: EnvironmentKey {
14 | static let defaultValue: KeyWindowClosure = {
15 | UIApplication
16 | .shared
17 | .connectedScenes
18 | .filter({ $0.activationState == .foregroundActive })
19 | .map({ $0 as? UIWindowScene })
20 | .compactMap({ $0 })
21 | .flatMap(\.windows)
22 | .first(where: \.isKeyWindow)
23 | }
24 | }
25 |
26 | extension EnvironmentValues {
27 | var keyWindow: KeyWindowClosure {
28 | get {
29 | self[KeyWindowKey.self]
30 | }
31 | set {
32 | self[KeyWindowKey.self] = newValue
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/TransNotion/Domain/NotionWebView/NotionWebViewPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotionWebViewPage.swift
3 | // TransNotion
4 | //
5 | // Created by 廣瀬雄大 on 2021/06/22.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct NotionWebViewPage: View {
11 | @State var url: URL
12 | @State var isLoading = false
13 |
14 | var body: some View {
15 | VStack {
16 | NotionWebView(url: $url, isLoading: $isLoading)
17 |
18 | Spacer()
19 |
20 | Button("Translate this page") {
21 | print("TODO: Translate and extract currnet page")
22 | print("URL: \(url)", "isLoading: \(isLoading)")
23 | }
24 | .buttonStyle(PrimaryButtonStyle(width: .infinity))
25 | .padding(.horizontal, 20)
26 | .disabled(isLoading)
27 | .placeholder(when: isLoading)
28 |
29 | Spacer().frame(height: 40)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TransNotion/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import UIKit
9 | import Firebase
10 |
11 | let isPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
12 |
13 | final class AppDelegate: NSObject, UIApplicationDelegate {
14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
15 | if !isPreview {
16 | setupFirebase()
17 | }
18 |
19 | return true
20 | }
21 | }
22 |
23 | private func setupFirebase() {
24 | #if DEBUG
25 | FirebaseApp.configure(options: FirebaseOptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-dev", ofType: "plist")!)!)
26 | #else
27 | FirebaseApp.configure(options: FirebaseOptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info-prod", ofType: "plist")!)!)
28 | #endif
29 | }
30 |
--------------------------------------------------------------------------------
/TransNotionTests/TransNotionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransNotionTests.swift
3 | // TransNotionTests
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import XCTest
9 | @testable import TransNotion
10 |
11 | class TransNotionTests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() throws {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Local/LocalStore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalStore.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol LocalStoreKey {
11 | static var localStoreKey: String { get }
12 | }
13 |
14 | extension LocalStoreKey {
15 | static var localStoreKey: String { "local_store_\(type(of: self))" }
16 | }
17 |
18 | struct LocalStore {
19 | func isExists() -> Bool {
20 | UserDefaults.standard.dictionaryRepresentation().keys.contains(where: { $0 == Coder.localStoreKey })
21 | }
22 |
23 | func write(for coder: Coder) throws {
24 | let data = try JSONEncoder().encode(coder)
25 | UserDefaults.standard.set(data, forKey: Coder.localStoreKey)
26 | }
27 |
28 | func read() throws -> Coder? {
29 | guard let data = UserDefaults.standard.data(forKey: Coder.localStoreKey) else {
30 | return nil
31 | }
32 | let decoded = try JSONDecoder().decode(Coder.self, from: data)
33 | return decoded
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/TransNotion/TransNotionApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransNotionApp.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct TransNotionApp: App {
12 | @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
13 |
14 | var body: some Scene {
15 | WindowGroup {
16 | RootView()
17 | .environmentObject(State())
18 | }
19 | }
20 | }
21 |
22 | extension TransNotionApp {
23 | final class State: ObservableObject {
24 | @Published var isLogin: Bool = {
25 | let store = LocalStore()
26 | do {
27 | let credentials = try store.read()
28 | return credentials?.elements.last != nil
29 | } catch {
30 | print(error)
31 | return false
32 | }
33 | }()
34 | var credential: Credential? {
35 | let store = LocalStore()
36 | do {
37 | let credentials = try store.read()
38 | return credentials?.elements.last
39 | } catch {
40 | errorLogger.record(error: error)
41 | return nil
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/TransNotionUITests/TransNotionUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransNotionUITests.swift
3 | // TransNotionUITests
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import XCTest
9 |
10 | class TransNotionUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/TransNotion/Service/Auth/Auth.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import FirebaseAuth
3 | import Combine
4 |
5 | protocol Auth {
6 | func auth() -> AnyPublisher
7 | }
8 |
9 | protocol Authentificated {
10 | func authentificated() -> Me
11 | }
12 |
13 | fileprivate class _Auth: Auth, Authentificated {
14 | var me: Me?
15 | init() { }
16 |
17 | func auth() -> AnyPublisher {
18 | Future { promise in
19 | FirebaseAuth.Auth.auth().signInAnonymously() { (result, error) in
20 | if let error = error {
21 | promise(.failure(error))
22 | return
23 | }
24 | guard let result = result else {
25 | fatalError("unexpected pattern about result and error is nil")
26 | }
27 | let id = Me.ID(rawValue: result.user.uid)
28 | self.store(meID: id)
29 |
30 | let me = Me(id: id)
31 | self.me = me
32 | promise(.success(me))
33 | }
34 | }.eraseToAnyPublisher()
35 | }
36 |
37 | func authentificated() -> Me {
38 | me!
39 | }
40 |
41 | // MARK: - Private
42 | private enum StoreKey {
43 | static let firebaseUserID: String = "firebaseUserID"
44 | }
45 | private func store(meID: Me.ID) {
46 | guard UserDefaults.standard.string(forKey: StoreKey.firebaseUserID) == nil else {
47 | return
48 | }
49 | UserDefaults.standard.setValue(meID.rawValue, forKey: StoreKey.firebaseUserID)
50 | }
51 | }
52 |
53 | private var _auth = _Auth()
54 | internal var auth: Auth { _auth }
55 | internal var authentificated: Authentificated { _auth }
56 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Remote/DocumentReference+Combine.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Combine
3 | import FirebaseFirestore
4 | import FirebaseFirestoreSwift
5 |
6 | extension DocumentReference {
7 | // MARK: - Get
8 | enum GetDocumentError: Error {
9 | case snapshotIsNotFound
10 | case snapshotDecodeFailure
11 | }
12 | func get() -> AnyPublisher {
13 | Future { [weak self] promise in
14 | self?.getDocument(source: .default, completion: { (snapshot, error) in
15 | if let error = error {
16 | promise(.failure(error))
17 | }
18 | guard let snapshot = snapshot else {
19 | return promise(.failure(GetDocumentError.snapshotIsNotFound))
20 | }
21 |
22 | do {
23 | guard let decoded = try snapshot.data(as: T.self) else {
24 | return promise(.failure(GetDocumentError.snapshotDecodeFailure))
25 | }
26 | promise(.success(decoded))
27 | } catch {
28 | promise(.failure(error))
29 | }
30 | })
31 | }.eraseToAnyPublisher()
32 | }
33 |
34 |
35 | // MARK: - Set
36 | func set(from value: T) -> AnyPublisher {
37 | Future { [weak self] promise in
38 | do {
39 | try self?.setData(from: value, merge: true, encoder: Firestore.Encoder()) { error in
40 | guard let error = error else {
41 | promise(.success(value))
42 | return
43 | }
44 | promise(.failure(error))
45 | }
46 | } catch {
47 | promise(.failure(error))
48 | }
49 | }.eraseToAnyPublisher()
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/TransNotion/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/TransNotion/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleURLTypes
6 |
7 |
8 | CFBundleTypeRole
9 | Editor
10 | CFBundleURLSchemes
11 |
12 | $(NOTION_OATUH_CALLBACK_CUSTOM_URL_SCHEME)
13 |
14 |
15 |
16 | CFBundleDevelopmentRegion
17 | $(DEVELOPMENT_LANGUAGE)
18 | CFBundleExecutable
19 | $(EXECUTABLE_NAME)
20 | CFBundleIdentifier
21 | $(PRODUCT_BUNDLE_IDENTIFIER)
22 | CFBundleInfoDictionaryVersion
23 | 6.0
24 | CFBundleName
25 | $(PRODUCT_NAME)
26 | CFBundlePackageType
27 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
28 | CFBundleShortVersionString
29 | 1.0
30 | CFBundleVersion
31 | 1
32 | LSRequiresIPhoneOS
33 |
34 | UIApplicationSceneManifest
35 |
36 | UIApplicationSupportsMultipleScenes
37 |
38 |
39 | UIApplicationSupportsIndirectInputEvents
40 |
41 | UILaunchScreen
42 |
43 | UIRequiredDeviceCapabilities
44 |
45 | armv7
46 |
47 | UISupportedInterfaceOrientations
48 |
49 | UIInterfaceOrientationPortrait
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 | UISupportedInterfaceOrientations~ipad
54 |
55 | UIInterfaceOrientationPortrait
56 | UIInterfaceOrientationPortraitUpsideDown
57 | UIInterfaceOrientationLandscapeLeft
58 | UIInterfaceOrientationLandscapeRight
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/TransNotion/Domain/NotionWebView/NotionWebView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotionWebView.swift
3 | // TransNotion
4 | //
5 | // Created by 廣瀬雄大 on 2021/06/22.
6 | //
7 |
8 | import SwiftUI
9 | import UIKit
10 | import WebKit
11 |
12 | struct NotionWebView: UIViewRepresentable {
13 | @Binding var url: URL
14 | @Binding var isLoading: Bool
15 |
16 | @EnvironmentObject var state: TransNotionApp.State
17 | @ObservedObject var observer: Observer = .init()
18 |
19 | func makeUIView(context: Context) -> WKWebView {
20 | let webView = WKWebView(frame: .zero)
21 | webView.allowsBackForwardNavigationGestures = true
22 | webView.navigationDelegate = context.coordinator
23 |
24 | observer.observations.append(
25 | webView.observe(\.isLoading, changeHandler: { webView, change in
26 | DispatchQueue.main.async {
27 | isLoading = webView.isLoading
28 | webView.isUserInteractionEnabled = !webView.isLoading
29 | }
30 | })
31 | )
32 | observer.observations.append(
33 | webView.observe(\.url, changeHandler: { webView, _ in
34 | DispatchQueue.main.async {
35 | if let url = webView.url {
36 | self.url = url
37 | }
38 | }
39 | })
40 | )
41 |
42 | webView.load(URLRequest(url: url))
43 |
44 | return webView
45 | }
46 |
47 | func updateUIView(_ uiView: WKWebView, context: Context) {
48 |
49 | }
50 |
51 | // MARK: - Coordinate
52 | final class Coordinator: NSObject {
53 | let webView: NotionWebView
54 |
55 | init(webView: NotionWebView) {
56 | self.webView = webView
57 | }
58 | }
59 | func makeCoordinator() -> Coordinator {
60 | Coordinator(webView: self)
61 | }
62 |
63 | // MARK: - Observer
64 | final class Observer: ObservableObject {
65 | fileprivate var observations: [NSKeyValueObservation] = []
66 | }
67 | }
68 |
69 | private let allowHosts: [String] = ["www.notion.so", "notion.so"]
70 | extension NotionWebView.Coordinator: WKNavigationDelegate {
71 | public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
72 | guard let url = navigationAction.request.url, let host = url.host, allowHosts.contains(host) else {
73 | decisionHandler(.cancel)
74 | return
75 | }
76 | decisionHandler(.allow)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/TransNotion.xcodeproj/xcshareddata/xcschemes/TransNotion.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/TransNotion/Service/Database/Remote/Database.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Combine
3 | import FirebaseFirestore
4 | import FirebaseFirestoreSwift
5 | import CoreLocation
6 |
7 | protocol Database {
8 | func fetch(path: DatabaseDocumentPathBuilder) -> AnyPublisher
9 | func create(path: DatabaseCollectionPathBuilder, value: T) -> AnyPublisher
10 | func createWithID(path: DatabaseCollectionPathBuilder, value: T, identifier: String) -> AnyPublisher
11 | func update(path: DatabaseDocumentPathBuilder, value: T) -> AnyPublisher
12 | }
13 |
14 | private let database = Firestore.firestore()
15 | struct FirestoreDatabase: Database {
16 | static let shared = FirestoreDatabase()
17 | private init() { }
18 |
19 | // MARK: - Fetch
20 | func fetch(path: DatabaseDocumentPathBuilder) -> AnyPublisher {
21 | database.document(path.path).get()
22 | }
23 |
24 | struct DecodeError {
25 | let index: Int
26 | let error: Error
27 | let data: [String: Any]
28 | }
29 |
30 | // MARK: - Modifier
31 | func create(path: DatabaseCollectionPathBuilder, value: T) -> AnyPublisher {
32 | database.collection(path.path).document().set(from: value)
33 | }
34 |
35 | func createWithID(path: DatabaseCollectionPathBuilder, value: T, identifier: String) -> AnyPublisher {
36 | database.collection(path.path).document(identifier).set(from: value)
37 | }
38 |
39 | func update(path: DatabaseDocumentPathBuilder, value: T) -> AnyPublisher {
40 | database.document(path.path).set(from: value)
41 | }
42 | }
43 |
44 | // MARK: - Private
45 | private extension FirestoreDatabase {
46 | func buildCollectionQuery(for path: DatabaseCollectionPathBuilder) -> FirebaseFirestore.Query {
47 | var query = path.isGroup ? database.collectionGroup(path.path) : database.collection(path.path)
48 | if let args = path.args {
49 | args.relations.forEach { relation in
50 | switch relation {
51 | case let .equal(value):
52 | query = query.whereField(args.key.rawValue, isEqualTo: value)
53 | case let .less(value):
54 | query = query.whereField(args.key.rawValue, isLessThan: value)
55 | case let .lessOrEqual(value):
56 | query = query.whereField(args.key.rawValue, isLessThanOrEqualTo: value)
57 | case let .greater(value):
58 | query = query.whereField(args.key.rawValue, isGreaterThan: value)
59 | case let .greaterOrEqual(value):
60 | query = query.whereField(args.key.rawValue, isGreaterThanOrEqualTo: value)
61 | case let .notEqual(value):
62 | query = query.whereField(args.key.rawValue, isNotEqualTo: value)
63 | case let .contains(values):
64 | query = query.whereField(args.key.rawValue, in: values)
65 | }
66 | }
67 | }
68 | return query
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/TransNotion/Domain/Login/LoginView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginView.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/15.
6 | //
7 |
8 | import SwiftUI
9 | import AuthenticationServices
10 | import Combine
11 |
12 | struct LoginView: View {
13 | @ObservedObject var viewModel: ViewModel = .init()
14 | @EnvironmentObject var state: TransNotionApp.State
15 |
16 | var body: some View {
17 | ZStack {
18 | Color.background.edgesIgnoringSafeArea(.all)
19 |
20 | VStack {
21 | Text("TransNotion").font(.title).foregroundColor(.textColor)
22 | Button(action: {
23 | viewModel.startNotionOAuth()
24 | }, label: {
25 | HStack {
26 | Image("notion_icon")
27 | .resizable()
28 | .frame(width: 32, height: 32)
29 | Text("Login with Notion")
30 | .foregroundColor(.black)
31 | }
32 | .frame(width: 240, height: 44)
33 | .background(Color.white)
34 | .cornerRadius(4)
35 | })
36 | }
37 | }
38 | .onAppear {
39 | viewModel.onAppear(state: state)
40 | }
41 | }
42 | }
43 |
44 | extension LoginView {
45 | class ViewModel: ObservableObject {
46 | @Environment(\.keyWindow) var keyWindow
47 | @Published var credential: Credential?
48 | @Published var error: Error?
49 | var cancellables: [AnyCancellable] = []
50 | let localStore = LocalStore()
51 | @Published var state: TransNotionApp.State!
52 |
53 | func onAppear(state: TransNotionApp.State) {
54 | self.state = state
55 | }
56 |
57 | func startNotionOAuth() {
58 | guard let window = keyWindow() else {
59 | fatalError("unexpected window is not found")
60 | }
61 | NotionOAuth(window: window)
62 | .start()
63 | .receive(on: DispatchQueue.main)
64 | .sink (receiveCompletion: { [weak self] (completion) in
65 | print("Completion:", completion)
66 | switch completion {
67 | case .failure(let error):
68 | print("Failure:", error)
69 | self?.error = error
70 | return
71 | case .finished:
72 | return
73 | }
74 | }, receiveValue: { [weak self] (credential) in
75 | print("Success:", credential)
76 | self?.credential = credential
77 | self?.store(credential: credential)
78 | })
79 | .store(in: &cancellables)
80 | }
81 |
82 | private func store(credential: Credential) {
83 | do {
84 | var credentials: Credentials
85 | switch try localStore.read() {
86 | case nil:
87 | credentials = .init(elements: [])
88 | case let _credentials?:
89 | credentials = _credentials
90 | }
91 |
92 | credentials.elements.append(credential)
93 | try localStore.write(for: credentials)
94 | state.isLogin = true
95 | } catch {
96 | errorLogger.record(error: error)
97 | }
98 | }
99 | }
100 | }
101 |
102 | struct LoginView_Previews: PreviewProvider {
103 | static var previews: some View {
104 | LoginView()
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/TransNotion/Service/Auth/OAuth.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OAuth.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/16.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 | import AuthenticationServices
11 |
12 | private let authorizeURL: URL = URL(string: "https://api.notion.com/v1/oauth/authorize?client_id=\(Secret.notionOAuthClientID)&redirect_uri=\(Secret.notionOAuthRedirectURI)&response_type=code")!
13 | private let tokenURL: URL = URL(string: "https://api.notion.com/v1/oauth/token")!
14 | private let basicAuthHeader: String = {
15 | let base = "\(Secret.notionOAuthClientID):\(Secret.notionOAuthClientSecret)"
16 | return base.data(using: .utf8)!.base64EncodedString()
17 | }()
18 |
19 | final class NotionOAuth: NSObject {
20 | let window: ASPresentationAnchor
21 | init(window: UIWindow) {
22 | self.window = window
23 | }
24 | func start() -> AnyPublisher {
25 | requestAuthentification()
26 | .flatMap(requestCredential(code:))
27 | .eraseToAnyPublisher()
28 | }
29 | }
30 |
31 | extension NotionOAuth {
32 | typealias TemporaryAuthentificationCode = String
33 | enum RequestAuthentificationError: Swift.Error {
34 | case sessionError(Swift.Error)
35 | case codeNotFound
36 | }
37 |
38 | func requestAuthentification() -> AnyPublisher {
39 | Future { completion in
40 | let session = ASWebAuthenticationSession(url: authorizeURL, callbackURLScheme: Secret.notionOAuthCallbackCustomURLScheme) { (url, error) in
41 | if let error = error {
42 | completion(.failure(.sessionError(error)))
43 | } else if let url = url {
44 | completion(.success(url))
45 | }
46 | }
47 | session.presentationContextProvider = self
48 | session.prefersEphemeralWebBrowserSession = true
49 | session.start()
50 | }
51 | .tryMap { url in
52 | guard let code = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first(where: { $0.name == "code" })?.value else {
53 | throw RequestAuthentificationError.codeNotFound
54 | }
55 | return code
56 | }
57 | .eraseToAnyPublisher()
58 | }
59 |
60 | struct RequestCredentialBody: Encodable {
61 | let grantType: String = "authorization_code"
62 | let code: TemporaryAuthentificationCode
63 | let redirectUri: String = Secret.notionOAuthRedirectURI
64 | }
65 | enum RequestCredentialError: LocalizedError {
66 | case notStableResponse
67 | case emptyData
68 | }
69 | func requestCredential(code: TemporaryAuthentificationCode) -> AnyPublisher {
70 | var request = URLRequest(url: tokenURL)
71 | request.httpMethod = "POST"
72 | request.allHTTPHeaderFields = [
73 | "Authorization": "Basic \(basicAuthHeader)",
74 | "Content-Type": "application/json",
75 | ]
76 | request.httpBody = try! JSONEncoder
77 | .convertToSnakeCase
78 | .encode(
79 | RequestCredentialBody(code: code)
80 | )
81 | return URLSession.shared.dataTaskPublisher(for: request)
82 | .tryMap { (data, response) in
83 | guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
84 | throw RequestCredentialError.notStableResponse
85 | }
86 | if data.isEmpty {
87 | throw RequestCredentialError.emptyData
88 | }
89 | return data
90 | }
91 | .decode(type: Credential.self, decoder: JSONDecoder.convertFromSnakeCase)
92 | .eraseToAnyPublisher()
93 | }
94 | }
95 |
96 | extension NotionOAuth: ASWebAuthenticationPresentationContextProviding {
97 | func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
98 | window
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/TransNotion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "abseil",
6 | "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "ff5f5f0a3d3266836b9d722bb73cabdf7057482e",
10 | "version": "0.20200225.3"
11 | }
12 | },
13 | {
14 | "package": "BoringSSL-GRPC",
15 | "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git",
16 | "state": {
17 | "branch": null,
18 | "revision": "15889fadef7078dfa1392b0e2b08f3d0e9797104",
19 | "version": "0.7.1"
20 | }
21 | },
22 | {
23 | "package": "Firebase",
24 | "repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git",
25 | "state": {
26 | "branch": null,
27 | "revision": "f2b8de559b084a56f65bff79f4e736b46d0dafd3",
28 | "version": "8.0.0"
29 | }
30 | },
31 | {
32 | "package": "GoogleAppMeasurement",
33 | "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git",
34 | "state": {
35 | "branch": null,
36 | "revision": "48fcea0c0a74fc89131696aa995043eaa971ccb1",
37 | "version": "8.0.0"
38 | }
39 | },
40 | {
41 | "package": "GoogleDataTransport",
42 | "repositoryURL": "https://github.com/google/GoogleDataTransport.git",
43 | "state": {
44 | "branch": null,
45 | "revision": "369716b8d7518a530ce3c3a251436d72546debd8",
46 | "version": "8.4.0"
47 | }
48 | },
49 | {
50 | "package": "GoogleUtilities",
51 | "repositoryURL": "https://github.com/google/GoogleUtilities.git",
52 | "state": {
53 | "branch": null,
54 | "revision": "58359415d4ea29ebdc8fa5b41ce96c434d76d901",
55 | "version": "7.4.1"
56 | }
57 | },
58 | {
59 | "package": "gRPC",
60 | "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git",
61 | "state": {
62 | "branch": null,
63 | "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5",
64 | "version": "1.28.4"
65 | }
66 | },
67 | {
68 | "package": "GTMSessionFetcher",
69 | "repositoryURL": "https://github.com/google/gtm-session-fetcher.git",
70 | "state": {
71 | "branch": null,
72 | "revision": "91ed3d188eb95705fef3c249453b81f32dc557d1",
73 | "version": "1.5.0"
74 | }
75 | },
76 | {
77 | "package": "leveldb",
78 | "repositoryURL": "https://github.com/firebase/leveldb.git",
79 | "state": {
80 | "branch": null,
81 | "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
82 | "version": "1.22.2"
83 | }
84 | },
85 | {
86 | "package": "nanopb",
87 | "repositoryURL": "https://github.com/firebase/nanopb.git",
88 | "state": {
89 | "branch": null,
90 | "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77",
91 | "version": "2.30908.0"
92 | }
93 | },
94 | {
95 | "package": "notion",
96 | "repositoryURL": "git@github.com:noppefoxwolf/notion.git",
97 | "state": {
98 | "branch": null,
99 | "revision": "b90657c73a432f3f3a3191eed6311d2935859861",
100 | "version": "0.1.1"
101 | }
102 | },
103 | {
104 | "package": "Promises",
105 | "repositoryURL": "https://github.com/google/promises.git",
106 | "state": {
107 | "branch": null,
108 | "revision": "afa9a1ace74e116848d4f743599ab83e584ff8cb",
109 | "version": "1.2.12"
110 | }
111 | },
112 | {
113 | "package": "SwiftProtobuf",
114 | "repositoryURL": "https://github.com/apple/swift-protobuf.git",
115 | "state": {
116 | "branch": null,
117 | "revision": "1f62db409f2c9b0223a3f68567b4a01333aae778",
118 | "version": "1.17.0"
119 | }
120 | }
121 | ]
122 | },
123 | "version": 1
124 | }
125 |
--------------------------------------------------------------------------------
/TransNotion/Domain/NotionPages/NotionPagesView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotionPagesView.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/17.
6 | //
7 |
8 | import SwiftUI
9 | import Combine
10 | import notion
11 |
12 | struct NotionPagesView: View {
13 | struct URLContainer: Identifiable {
14 | let id = UUID()
15 | let url: URL
16 | }
17 |
18 | @ObservedObject var viewModel: ViewModel = .init()
19 | @State var url: URLContainer?
20 |
21 | var body: some View {
22 | NavigationView {
23 | VStack {
24 | List(viewModel.topPages, children: \.children) { page in
25 | Button(action: { url = page.base.pageURL().map(URLContainer.init(url:)) }, label: {
26 | Toggle(page.base.retrieveTitle()!, isOn: .init(get: { page.isChecked }, set: { viewModel.update(for: page, isChecked: $0) }))
27 | .toggleStyle(CheckBoxToggleStyle())
28 | .frame(height: 48)
29 | })
30 | }
31 | .listStyle(PlainListStyle())
32 | Group {
33 | let targetPages = viewModel.targetPages
34 | Button(!targetPages.isEmpty ? "Translate \(targetPages.count) page" : "Check translate target pages") {
35 | print("TODO: Translate and extract currnet page")
36 | }
37 | .disabled(targetPages.isEmpty)
38 | .buttonStyle(PrimaryButtonStyle(width: .infinity))
39 | .padding(.horizontal, 20)
40 | }
41 | }
42 | .navigationTitle(Text("Notion Pages"))
43 | }
44 | .accentColor(.appPrimary)
45 | .sheet(item: $url, content: { url in
46 | NotionWebViewPage(url: url.url)
47 | })
48 | .alert(isPresented: .init(get: { viewModel.error != nil }, set: { _ in viewModel.error = nil })) {
49 | Alert(
50 | title: Text("Error"),
51 | message: Text(viewModel.error?.localizedDescription ?? ""),
52 | dismissButton: Alert.Button.cancel()
53 | )
54 | }
55 | .onAppear {
56 | viewModel.fetchPages()
57 | }
58 | }
59 | }
60 |
61 | extension NotionPagesView {
62 | final class ViewModel: ObservableObject {
63 | @Environment(\.notion) private var session
64 | @Published var topPages: [Page] = []
65 | @Published var error: Swift.Error?
66 | var cancellables: [AnyCancellable] = []
67 | var allPages: [Page] = []
68 | var targetPages: [Page] {
69 | allPages.filter(\.isChecked)
70 | }
71 |
72 | class Page: Identifiable {
73 | var id: String { base.id }
74 | let base: Object.Page
75 | var children: [Page]?
76 | var isChecked: Bool = false
77 | init(base: Object.Page) {
78 | self.base = base
79 | }
80 | }
81 |
82 | func update(for page: Page, isChecked: Bool) {
83 | page.isChecked = isChecked
84 | // Call Published
85 | topPages = topPages
86 | }
87 |
88 | func fetchPages() {
89 | session.send(V1.Search.Search(query: "")).sink { [weak self] result in
90 | switch result {
91 | case let .success(response):
92 | let notionPages: [Object.Page] = response.results.compactMap {
93 | if case let .page(page) = $0.object {
94 | return page
95 | } else {
96 | print("[INFO]", $0.object)
97 | return nil
98 | }
99 | }
100 |
101 | let allPages: [Page] = notionPages.map(Page.init(base:))
102 | for page in allPages {
103 | for child in allPages {
104 | if case let .pageId(parentID) = child.base.parent.type {
105 | if page.id == parentID {
106 | if page.children == nil {
107 | page.children = []
108 | }
109 | page.children?.append(child)
110 | }
111 | }
112 | }
113 | }
114 | let topPages = allPages.filter { page in
115 | switch page.base.parent.type {
116 | case .databaseId, .workspace:
117 | return true
118 | case .pageId:
119 | return false
120 | }
121 | }
122 | self?.allPages = allPages
123 | self?.topPages = topPages
124 | case let .failure(error):
125 | self?.error = error
126 | }
127 | }.store(in: &cancellables)
128 | }
129 |
130 | }
131 | }
132 |
133 | struct NotionPagesView_Previews: PreviewProvider {
134 | static var previews: some View {
135 | NotionPagesView()
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/TransNotion/Domain/NotionPage/NotionPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotionPageView.swift
3 | // TransNotion
4 | //
5 | // Created by Yudai.Hirose on 2021/05/17.
6 | //
7 |
8 | import SwiftUI
9 | import Combine
10 | import notion
11 |
12 | struct NotionPageView: View {
13 | @ObservedObject var viewModel: ViewModel
14 |
15 | var body: some View {
16 | List {
17 | ForEach(viewModel.blocks) { block in
18 | plainText(block: block)
19 | }
20 | }
21 | .navigationTitle(viewModel.page?.retrieveTitle() ?? "Loading")
22 | .navigationBarItems(trailing: Button(action: {
23 | viewModel.isPresentedMenuSheet = true
24 | }, label: {
25 | Image(systemName: "plus")
26 | }))
27 | .onAppear {
28 | viewModel.fetch()
29 | viewModel.fetchBlocks()
30 | }
31 | .alert(isPresented: .init(get: { viewModel.error != nil }, set: { _ in viewModel.error = nil })) {
32 | Alert(
33 | title: Text("Error"),
34 | message: Text(viewModel.error?.localizedDescription ?? ""),
35 | dismissButton: Alert.Button.cancel()
36 | )
37 | }
38 | .actionSheet(isPresented: $viewModel.isPresentedMenuSheet, content: {
39 | ActionSheet(title: Text("menu"), buttons: [
40 | .default(Text("Add Block"), action: {
41 | viewModel.createBlock()
42 | }),
43 | .default(Text("Update Property"), action: {
44 | viewModel.updateProperty()
45 | }),
46 | .cancel()
47 | ])
48 | })
49 | }
50 |
51 | @ViewBuilder
52 | func plainText(block: Block) -> some View {
53 | switch block.type {
54 | case let .paragraph(paragraph):
55 | Text(paragraph.text.first?.plainText ?? "")
56 | case let .heading1(heading1):
57 | Text(heading1.text.first?.plainText ?? "")
58 | case let .heading2(heading2):
59 | Text(heading2.text.first?.plainText ?? "")
60 | case let .heading3(heading3):
61 | Text(heading3.text.first?.plainText ?? "")
62 | case let .bulletedListItem(bulletedListItem):
63 | Text(bulletedListItem.text.first?.plainText ?? "")
64 | case let .numberedListItem(numberedListItem):
65 | Text(numberedListItem.text.first?.plainText ?? "")
66 | case let .toDo(toDo):
67 | Text(toDo.text.first?.plainText ?? "")
68 | case let .toggle(toggle):
69 | Text(toggle.text.first?.plainText ?? "")
70 | case let .childPage(childPage):
71 | Text(childPage.title)
72 | case .unsupported:
73 | Text("-")
74 | }
75 | }
76 | }
77 |
78 | extension NotionPageView {
79 | class ViewModel: ObservableObject {
80 | internal init(id: Page.ID) {
81 | self.id = id
82 | }
83 |
84 | @Environment(\.notion) private var session
85 | @Published var page: Object.Page?
86 | @Published var blocks: [Object.Block] = []
87 | @Published var error: Error? = nil
88 | var cancellables: [AnyCancellable] = []
89 | @Published var isPresentedMenuSheet: Bool = false
90 |
91 | let id: Page.ID
92 |
93 | func fetch() {
94 | session.send(V1.Pages.Page(id: id)).sink { result in
95 | switch result {
96 | case let .success(response):
97 | print(response.properties)
98 | self.page = response
99 | case let .failure(error):
100 | self.error = error
101 | }
102 | }.store(in: &cancellables)
103 | }
104 |
105 | func fetchBlocks() {
106 | session.send(V1.Blocks.Children(id: id)).sink { result in
107 | switch result {
108 | case let .success(response):
109 | self.blocks = response.results
110 | case let .failure(error):
111 | self.error = error
112 | }
113 | }.store(in: &cancellables)
114 | }
115 |
116 | func createBlock() {
117 | let block: Block = .init(type: .heading1(.init(text: [.init(type: .text(.init(content: "append line")))])))
118 | session.send(V1.Blocks.Append(id: id, children: [block])).sink { result in
119 | switch result {
120 | case let .success(response):
121 | self.blocks = []
122 | self.fetchBlocks()
123 | case let .failure(error):
124 | self.error = error
125 | }
126 | }.store(in: &cancellables)
127 | }
128 |
129 | func updateProperty() {
130 | session.send(V1.Pages.Update(id: id, properties: ["title" : .init(type: .title([.init(type: .text(.init(content: "Updated name")))]))])).sink { result in
131 | switch result {
132 | case let .success(response):
133 | self.page = nil
134 | self.fetch()
135 | break
136 | case let .failure(error):
137 | self.error = error
138 | }
139 | }.store(in: &cancellables)
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/TransNotion.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 20F7E1162681F65A00F0024A /* NotionWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E1152681F65A00F0024A /* NotionWebView.swift */; };
11 | 20F7E1182681FDF400F0024A /* Notion.Object.Page+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E1172681FDF400F0024A /* Notion.Object.Page+Extension.swift */; };
12 | 20F7E11A26820EA500F0024A /* NotionWebViewPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E11926820EA500F0024A /* NotionWebViewPage.swift */; };
13 | 20F7E11D2682145A00F0024A /* Placeholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E11C2682145A00F0024A /* Placeholder.swift */; };
14 | 20F7E1202682287400F0024A /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E11F2682287400F0024A /* Button.swift */; };
15 | 20F7E1222682CC5B00F0024A /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20F7E1212682CC5B00F0024A /* Toggle.swift */; };
16 | BA00718D26508564001DFFCB /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = BA00718926508564001DFFCB /* Debug.xcconfig */; };
17 | BA00718E26508564001DFFCB /* Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = BA00718A26508564001DFFCB /* Release.xcconfig */; };
18 | BA00718F26508564001DFFCB /* Debug-Secret.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = BA00718B26508564001DFFCB /* Debug-Secret.xcconfig */; };
19 | BA00719026508564001DFFCB /* Release-Secret.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = BA00718C26508564001DFFCB /* Release-Secret.xcconfig */; };
20 | BA00719F2650886C001DFFCB /* OAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA00719E2650886C001DFFCB /* OAuth.swift */; };
21 | BA0071A826509001001DFFCB /* Environment+Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0071A726509001001DFFCB /* Environment+Window.swift */; };
22 | BA0071E92650A401001DFFCB /* GoogleService-Info-dev.plist in Resources */ = {isa = PBXBuildFile; fileRef = BAD32C20264FC6E600DD7824 /* GoogleService-Info-dev.plist */; };
23 | BA0071F126511CFC001DFFCB /* LocalStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0071F026511CFC001DFFCB /* LocalStore.swift */; };
24 | BA0071FC26512C9C001DFFCB /* Credential.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0071FB26512C9C001DFFCB /* Credential.swift */; };
25 | BA00720226512D63001DFFCB /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA00720126512D63001DFFCB /* ErrorLogger.swift */; };
26 | BA00720B26512E89001DFFCB /* JSONCoder+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA00720A26512E89001DFFCB /* JSONCoder+Extension.swift */; };
27 | BA00721D2651C99C001DFFCB /* notion in Frameworks */ = {isa = PBXBuildFile; productRef = BA00721C2651C99C001DFFCB /* notion */; };
28 | BA00722C2651C9E6001DFFCB /* NotionPagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA00722B2651C9E6001DFFCB /* NotionPagesView.swift */; };
29 | BA0072342651CB05001DFFCB /* Environment+notion.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0072332651CB05001DFFCB /* Environment+notion.swift */; };
30 | BA0B34C4264FA4F100774AA0 /* TransNotionApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0B34C3264FA4F100774AA0 /* TransNotionApp.swift */; };
31 | BA0B34C6264FA4F100774AA0 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0B34C5264FA4F100774AA0 /* RootView.swift */; };
32 | BA0B34C8264FA4F800774AA0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA0B34C7264FA4F800774AA0 /* Assets.xcassets */; };
33 | BA0B34CB264FA4F800774AA0 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA0B34CA264FA4F800774AA0 /* Preview Assets.xcassets */; };
34 | BA0B34D6264FA4F800774AA0 /* TransNotionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0B34D5264FA4F800774AA0 /* TransNotionTests.swift */; };
35 | BA0B34E1264FA4F800774AA0 /* TransNotionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0B34E0264FA4F800774AA0 /* TransNotionUITests.swift */; };
36 | BA842EBF2651DF0400399BDB /* NotionPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA842EBE2651DF0400399BDB /* NotionPage.swift */; };
37 | BACEC6BD264FF4AC0070D31B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6BC264FF4AC0070D31B /* ContentView.swift */; };
38 | BACEC6C2264FF4B90070D31B /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6C1264FF4B90070D31B /* LoginView.swift */; };
39 | BACEC6CE264FF5030070D31B /* DatabasePathBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6C8264FF5020070D31B /* DatabasePathBuilder.swift */; };
40 | BACEC6CF264FF5030070D31B /* DatabaseEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6C9264FF5020070D31B /* DatabaseEntity.swift */; };
41 | BACEC6D0264FF5030070D31B /* DocumentReference+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6CA264FF5020070D31B /* DocumentReference+Combine.swift */; };
42 | BACEC6D1264FF5030070D31B /* CollectionReference+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6CB264FF5020070D31B /* CollectionReference+Combine.swift */; };
43 | BACEC6D2264FF5030070D31B /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6CC264FF5020070D31B /* Database.swift */; };
44 | BACEC6D3264FF5030070D31B /* Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6CD264FF5020070D31B /* Auth.swift */; };
45 | BACEC6DA264FF54B0070D31B /* Me.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6D8264FF54B0070D31B /* Me.swift */; };
46 | BACEC6DB264FF54B0070D31B /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6D9264FF54B0070D31B /* User.swift */; };
47 | BACEC6E1264FF7EB0070D31B /* Color+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BACEC6E0264FF7EB0070D31B /* Color+Extension.swift */; };
48 | BACEC6EF264FF9430070D31B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BACEC6F1264FF9430070D31B /* Localizable.strings */; };
49 | BAD32BE3264FC50B00DD7824 /* Secret.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAD32BE2264FC50B00DD7824 /* Secret.swift */; };
50 | BAD32C3F264FCE5C00DD7824 /* FirebaseFirestoreSwift-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = BAD32C3E264FCE5C00DD7824 /* FirebaseFirestoreSwift-Beta */; };
51 | BAD32C41264FCE5C00DD7824 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = BAD32C40264FCE5C00DD7824 /* FirebaseCrashlytics */; };
52 | BAD32C43264FCE5C00DD7824 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = BAD32C42264FCE5C00DD7824 /* FirebaseAuth */; };
53 | BAD32C45264FCE5C00DD7824 /* FirebaseAnalyticsSwift-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = BAD32C44264FCE5C00DD7824 /* FirebaseAnalyticsSwift-Beta */; };
54 | BAD32C47264FCE5C00DD7824 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = BAD32C46264FCE5C00DD7824 /* FirebaseFirestore */; };
55 | BAD32C4D264FDDAB00DD7824 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAD32C4C264FDDAB00DD7824 /* AppDelegate.swift */; };
56 | /* End PBXBuildFile section */
57 |
58 | /* Begin PBXContainerItemProxy section */
59 | BA0B34D2264FA4F800774AA0 /* PBXContainerItemProxy */ = {
60 | isa = PBXContainerItemProxy;
61 | containerPortal = BA0B34B8264FA4F100774AA0 /* Project object */;
62 | proxyType = 1;
63 | remoteGlobalIDString = BA0B34BF264FA4F100774AA0;
64 | remoteInfo = TransNotion;
65 | };
66 | BA0B34DD264FA4F800774AA0 /* PBXContainerItemProxy */ = {
67 | isa = PBXContainerItemProxy;
68 | containerPortal = BA0B34B8264FA4F100774AA0 /* Project object */;
69 | proxyType = 1;
70 | remoteGlobalIDString = BA0B34BF264FA4F100774AA0;
71 | remoteInfo = TransNotion;
72 | };
73 | /* End PBXContainerItemProxy section */
74 |
75 | /* Begin PBXFileReference section */
76 | 20F7E1152681F65A00F0024A /* NotionWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotionWebView.swift; sourceTree = ""; };
77 | 20F7E1172681FDF400F0024A /* Notion.Object.Page+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notion.Object.Page+Extension.swift"; sourceTree = ""; };
78 | 20F7E11926820EA500F0024A /* NotionWebViewPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotionWebViewPage.swift; sourceTree = ""; };
79 | 20F7E11C2682145A00F0024A /* Placeholder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Placeholder.swift; sourceTree = ""; };
80 | 20F7E11F2682287400F0024A /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; };
81 | 20F7E1212682CC5B00F0024A /* Toggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toggle.swift; sourceTree = ""; };
82 | BA00718926508564001DFFCB /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; };
83 | BA00718A26508564001DFFCB /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; };
84 | BA00718B26508564001DFFCB /* Debug-Secret.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Debug-Secret.xcconfig"; sourceTree = ""; };
85 | BA00718C26508564001DFFCB /* Release-Secret.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Release-Secret.xcconfig"; sourceTree = ""; };
86 | BA00719E2650886C001DFFCB /* OAuth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth.swift; sourceTree = ""; };
87 | BA0071A726509001001DFFCB /* Environment+Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Environment+Window.swift"; sourceTree = ""; };
88 | BA0071F026511CFC001DFFCB /* LocalStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalStore.swift; sourceTree = ""; };
89 | BA0071FB26512C9C001DFFCB /* Credential.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credential.swift; sourceTree = ""; };
90 | BA00720126512D63001DFFCB /* ErrorLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogger.swift; sourceTree = ""; };
91 | BA00720A26512E89001DFFCB /* JSONCoder+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONCoder+Extension.swift"; sourceTree = ""; };
92 | BA00722B2651C9E6001DFFCB /* NotionPagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotionPagesView.swift; sourceTree = ""; };
93 | BA0072332651CB05001DFFCB /* Environment+notion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Environment+notion.swift"; sourceTree = ""; };
94 | BA0B34C0264FA4F100774AA0 /* TransNotion.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TransNotion.app; sourceTree = BUILT_PRODUCTS_DIR; };
95 | BA0B34C3264FA4F100774AA0 /* TransNotionApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransNotionApp.swift; sourceTree = ""; };
96 | BA0B34C5264FA4F100774AA0 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; };
97 | BA0B34C7264FA4F800774AA0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
98 | BA0B34CA264FA4F800774AA0 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
99 | BA0B34CC264FA4F800774AA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
100 | BA0B34D1264FA4F800774AA0 /* TransNotionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TransNotionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
101 | BA0B34D5264FA4F800774AA0 /* TransNotionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransNotionTests.swift; sourceTree = ""; };
102 | BA0B34D7264FA4F800774AA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
103 | BA0B34DC264FA4F800774AA0 /* TransNotionUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TransNotionUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
104 | BA0B34E0264FA4F800774AA0 /* TransNotionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransNotionUITests.swift; sourceTree = ""; };
105 | BA0B34E2264FA4F800774AA0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
106 | BA842EBE2651DF0400399BDB /* NotionPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotionPage.swift; sourceTree = ""; };
107 | BACEC6BC264FF4AC0070D31B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
108 | BACEC6C1264FF4B90070D31B /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; };
109 | BACEC6C8264FF5020070D31B /* DatabasePathBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabasePathBuilder.swift; sourceTree = ""; };
110 | BACEC6C9264FF5020070D31B /* DatabaseEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatabaseEntity.swift; sourceTree = ""; };
111 | BACEC6CA264FF5020070D31B /* DocumentReference+Combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DocumentReference+Combine.swift"; sourceTree = ""; };
112 | BACEC6CB264FF5020070D31B /* CollectionReference+Combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CollectionReference+Combine.swift"; sourceTree = ""; };
113 | BACEC6CC264FF5020070D31B /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = ""; };
114 | BACEC6CD264FF5020070D31B /* Auth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Auth.swift; sourceTree = ""; };
115 | BACEC6D8264FF54B0070D31B /* Me.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Me.swift; sourceTree = ""; };
116 | BACEC6D9264FF54B0070D31B /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; };
117 | BACEC6E0264FF7EB0070D31B /* Color+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extension.swift"; sourceTree = ""; };
118 | BACEC6F0264FF9430070D31B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; };
119 | BACEC6F5264FF9690070D31B /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; };
120 | BAD32BE2264FC50B00DD7824 /* Secret.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Secret.swift; sourceTree = ""; };
121 | BAD32C20264FC6E600DD7824 /* GoogleService-Info-dev.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info-dev.plist"; sourceTree = ""; };
122 | BAD32C26264FC96000DD7824 /* Secret.swift.sample */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Secret.swift.sample; sourceTree = ""; };
123 | BAD32C4C264FDDAB00DD7824 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
124 | /* End PBXFileReference section */
125 |
126 | /* Begin PBXFrameworksBuildPhase section */
127 | BA0B34BD264FA4F100774AA0 /* Frameworks */ = {
128 | isa = PBXFrameworksBuildPhase;
129 | buildActionMask = 2147483647;
130 | files = (
131 | BAD32C3F264FCE5C00DD7824 /* FirebaseFirestoreSwift-Beta in Frameworks */,
132 | BAD32C43264FCE5C00DD7824 /* FirebaseAuth in Frameworks */,
133 | BAD32C45264FCE5C00DD7824 /* FirebaseAnalyticsSwift-Beta in Frameworks */,
134 | BAD32C47264FCE5C00DD7824 /* FirebaseFirestore in Frameworks */,
135 | BAD32C41264FCE5C00DD7824 /* FirebaseCrashlytics in Frameworks */,
136 | BA00721D2651C99C001DFFCB /* notion in Frameworks */,
137 | );
138 | runOnlyForDeploymentPostprocessing = 0;
139 | };
140 | BA0B34CE264FA4F800774AA0 /* Frameworks */ = {
141 | isa = PBXFrameworksBuildPhase;
142 | buildActionMask = 2147483647;
143 | files = (
144 | );
145 | runOnlyForDeploymentPostprocessing = 0;
146 | };
147 | BA0B34D9264FA4F800774AA0 /* Frameworks */ = {
148 | isa = PBXFrameworksBuildPhase;
149 | buildActionMask = 2147483647;
150 | files = (
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | /* End PBXFrameworksBuildPhase section */
155 |
156 | /* Begin PBXGroup section */
157 | 20F7E1142681F64C00F0024A /* NotionWebView */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 20F7E1152681F65A00F0024A /* NotionWebView.swift */,
161 | 20F7E11926820EA500F0024A /* NotionWebViewPage.swift */,
162 | );
163 | path = NotionWebView;
164 | sourceTree = "";
165 | };
166 | 20F7E11B2682145500F0024A /* Modifier */ = {
167 | isa = PBXGroup;
168 | children = (
169 | 20F7E11C2682145A00F0024A /* Placeholder.swift */,
170 | );
171 | path = Modifier;
172 | sourceTree = "";
173 | };
174 | BA00719D26508863001DFFCB /* Auth */ = {
175 | isa = PBXGroup;
176 | children = (
177 | BACEC6CD264FF5020070D31B /* Auth.swift */,
178 | BA00719E2650886C001DFFCB /* OAuth.swift */,
179 | );
180 | path = Auth;
181 | sourceTree = "";
182 | };
183 | BA0071A626508FFC001DFFCB /* Environment */ = {
184 | isa = PBXGroup;
185 | children = (
186 | BA0071A726509001001DFFCB /* Environment+Window.swift */,
187 | BA0072332651CB05001DFFCB /* Environment+notion.swift */,
188 | );
189 | path = Environment;
190 | sourceTree = "";
191 | };
192 | BA0071ED26511CDB001DFFCB /* Remote */ = {
193 | isa = PBXGroup;
194 | children = (
195 | BACEC6C8264FF5020070D31B /* DatabasePathBuilder.swift */,
196 | BACEC6C9264FF5020070D31B /* DatabaseEntity.swift */,
197 | BACEC6CA264FF5020070D31B /* DocumentReference+Combine.swift */,
198 | BACEC6CB264FF5020070D31B /* CollectionReference+Combine.swift */,
199 | BACEC6CC264FF5020070D31B /* Database.swift */,
200 | );
201 | path = Remote;
202 | sourceTree = "";
203 | };
204 | BA0071EE26511CED001DFFCB /* Local */ = {
205 | isa = PBXGroup;
206 | children = (
207 | BA0071F026511CFC001DFFCB /* LocalStore.swift */,
208 | );
209 | path = Local;
210 | sourceTree = "";
211 | };
212 | BA00720026512D5D001DFFCB /* Logger */ = {
213 | isa = PBXGroup;
214 | children = (
215 | BA00720126512D63001DFFCB /* ErrorLogger.swift */,
216 | );
217 | path = Logger;
218 | sourceTree = "";
219 | };
220 | BA00720926512E7E001DFFCB /* Extension */ = {
221 | isa = PBXGroup;
222 | children = (
223 | BA00720A26512E89001DFFCB /* JSONCoder+Extension.swift */,
224 | 20F7E1172681FDF400F0024A /* Notion.Object.Page+Extension.swift */,
225 | );
226 | path = Extension;
227 | sourceTree = "";
228 | };
229 | BA0072212651C9B1001DFFCB /* Domain */ = {
230 | isa = PBXGroup;
231 | children = (
232 | 20F7E1142681F64C00F0024A /* NotionWebView */,
233 | BA842EBD2651DEF800399BDB /* NotionPage */,
234 | BA0072292651C9C4001DFFCB /* NotionPages */,
235 | BA0072252651C9B4001DFFCB /* Login */,
236 | );
237 | path = Domain;
238 | sourceTree = "";
239 | };
240 | BA0072252651C9B4001DFFCB /* Login */ = {
241 | isa = PBXGroup;
242 | children = (
243 | BACEC6C1264FF4B90070D31B /* LoginView.swift */,
244 | );
245 | path = Login;
246 | sourceTree = "";
247 | };
248 | BA0072292651C9C4001DFFCB /* NotionPages */ = {
249 | isa = PBXGroup;
250 | children = (
251 | BA00722B2651C9E6001DFFCB /* NotionPagesView.swift */,
252 | );
253 | path = NotionPages;
254 | sourceTree = "";
255 | };
256 | BA0B34B7264FA4F100774AA0 = {
257 | isa = PBXGroup;
258 | children = (
259 | BA0B34C2264FA4F100774AA0 /* TransNotion */,
260 | BA0B34D4264FA4F800774AA0 /* TransNotionTests */,
261 | BA0B34DF264FA4F800774AA0 /* TransNotionUITests */,
262 | BA0B34C1264FA4F100774AA0 /* Products */,
263 | );
264 | sourceTree = "";
265 | };
266 | BA0B34C1264FA4F100774AA0 /* Products */ = {
267 | isa = PBXGroup;
268 | children = (
269 | BA0B34C0264FA4F100774AA0 /* TransNotion.app */,
270 | BA0B34D1264FA4F800774AA0 /* TransNotionTests.xctest */,
271 | BA0B34DC264FA4F800774AA0 /* TransNotionUITests.xctest */,
272 | );
273 | name = Products;
274 | sourceTree = "";
275 | };
276 | BA0B34C2264FA4F100774AA0 /* TransNotion */ = {
277 | isa = PBXGroup;
278 | children = (
279 | 20F7E11B2682145500F0024A /* Modifier */,
280 | BA00720926512E7E001DFFCB /* Extension */,
281 | BA0071A626508FFC001DFFCB /* Environment */,
282 | BACEC6DF264FF7E10070D31B /* Style */,
283 | BACEC6D7264FF53A0070D31B /* Entity */,
284 | BACEC6C6264FF4ED0070D31B /* Service */,
285 | BA0B34CC264FA4F800774AA0 /* Info.plist */,
286 | BAD32C20264FC6E600DD7824 /* GoogleService-Info-dev.plist */,
287 | BAD32BE2264FC50B00DD7824 /* Secret.swift */,
288 | BAD32C26264FC96000DD7824 /* Secret.swift.sample */,
289 | BA0B34C3264FA4F100774AA0 /* TransNotionApp.swift */,
290 | BAD32C4C264FDDAB00DD7824 /* AppDelegate.swift */,
291 | BA0B34C5264FA4F100774AA0 /* RootView.swift */,
292 | BACEC6BC264FF4AC0070D31B /* ContentView.swift */,
293 | BA0072212651C9B1001DFFCB /* Domain */,
294 | BA0B34C7264FA4F800774AA0 /* Assets.xcassets */,
295 | BA00718B26508564001DFFCB /* Debug-Secret.xcconfig */,
296 | BA00718926508564001DFFCB /* Debug.xcconfig */,
297 | BA00718C26508564001DFFCB /* Release-Secret.xcconfig */,
298 | BA00718A26508564001DFFCB /* Release.xcconfig */,
299 | BA0B34C9264FA4F800774AA0 /* Preview Content */,
300 | BACEC6F1264FF9430070D31B /* Localizable.strings */,
301 | );
302 | path = TransNotion;
303 | sourceTree = "";
304 | };
305 | BA0B34C9264FA4F800774AA0 /* Preview Content */ = {
306 | isa = PBXGroup;
307 | children = (
308 | BA0B34CA264FA4F800774AA0 /* Preview Assets.xcassets */,
309 | );
310 | path = "Preview Content";
311 | sourceTree = "";
312 | };
313 | BA0B34D4264FA4F800774AA0 /* TransNotionTests */ = {
314 | isa = PBXGroup;
315 | children = (
316 | BA0B34D5264FA4F800774AA0 /* TransNotionTests.swift */,
317 | BA0B34D7264FA4F800774AA0 /* Info.plist */,
318 | );
319 | path = TransNotionTests;
320 | sourceTree = "";
321 | };
322 | BA0B34DF264FA4F800774AA0 /* TransNotionUITests */ = {
323 | isa = PBXGroup;
324 | children = (
325 | BA0B34E0264FA4F800774AA0 /* TransNotionUITests.swift */,
326 | BA0B34E2264FA4F800774AA0 /* Info.plist */,
327 | );
328 | path = TransNotionUITests;
329 | sourceTree = "";
330 | };
331 | BA842EBD2651DEF800399BDB /* NotionPage */ = {
332 | isa = PBXGroup;
333 | children = (
334 | BA842EBE2651DF0400399BDB /* NotionPage.swift */,
335 | );
336 | path = NotionPage;
337 | sourceTree = "";
338 | };
339 | BACEC6C6264FF4ED0070D31B /* Service */ = {
340 | isa = PBXGroup;
341 | children = (
342 | BA00720026512D5D001DFFCB /* Logger */,
343 | BA00719D26508863001DFFCB /* Auth */,
344 | BACEC6C7264FF5020070D31B /* Database */,
345 | );
346 | path = Service;
347 | sourceTree = "";
348 | };
349 | BACEC6C7264FF5020070D31B /* Database */ = {
350 | isa = PBXGroup;
351 | children = (
352 | BA0071EE26511CED001DFFCB /* Local */,
353 | BA0071ED26511CDB001DFFCB /* Remote */,
354 | );
355 | path = Database;
356 | sourceTree = "";
357 | };
358 | BACEC6D7264FF53A0070D31B /* Entity */ = {
359 | isa = PBXGroup;
360 | children = (
361 | BACEC6D8264FF54B0070D31B /* Me.swift */,
362 | BACEC6D9264FF54B0070D31B /* User.swift */,
363 | BA0071FB26512C9C001DFFCB /* Credential.swift */,
364 | );
365 | path = Entity;
366 | sourceTree = "";
367 | };
368 | BACEC6DF264FF7E10070D31B /* Style */ = {
369 | isa = PBXGroup;
370 | children = (
371 | BACEC6E0264FF7EB0070D31B /* Color+Extension.swift */,
372 | 20F7E11F2682287400F0024A /* Button.swift */,
373 | 20F7E1212682CC5B00F0024A /* Toggle.swift */,
374 | );
375 | path = Style;
376 | sourceTree = "";
377 | };
378 | /* End PBXGroup section */
379 |
380 | /* Begin PBXNativeTarget section */
381 | BA0B34BF264FA4F100774AA0 /* TransNotion */ = {
382 | isa = PBXNativeTarget;
383 | buildConfigurationList = BA0B34E5264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotion" */;
384 | buildPhases = (
385 | BA0B34BC264FA4F100774AA0 /* Sources */,
386 | BA0B34BD264FA4F100774AA0 /* Frameworks */,
387 | BA0B34BE264FA4F100774AA0 /* Resources */,
388 | );
389 | buildRules = (
390 | );
391 | dependencies = (
392 | );
393 | name = TransNotion;
394 | packageProductDependencies = (
395 | BAD32C3E264FCE5C00DD7824 /* FirebaseFirestoreSwift-Beta */,
396 | BAD32C40264FCE5C00DD7824 /* FirebaseCrashlytics */,
397 | BAD32C42264FCE5C00DD7824 /* FirebaseAuth */,
398 | BAD32C44264FCE5C00DD7824 /* FirebaseAnalyticsSwift-Beta */,
399 | BAD32C46264FCE5C00DD7824 /* FirebaseFirestore */,
400 | BA00721C2651C99C001DFFCB /* notion */,
401 | );
402 | productName = TransNotion;
403 | productReference = BA0B34C0264FA4F100774AA0 /* TransNotion.app */;
404 | productType = "com.apple.product-type.application";
405 | };
406 | BA0B34D0264FA4F800774AA0 /* TransNotionTests */ = {
407 | isa = PBXNativeTarget;
408 | buildConfigurationList = BA0B34E8264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotionTests" */;
409 | buildPhases = (
410 | BA0B34CD264FA4F800774AA0 /* Sources */,
411 | BA0B34CE264FA4F800774AA0 /* Frameworks */,
412 | BA0B34CF264FA4F800774AA0 /* Resources */,
413 | );
414 | buildRules = (
415 | );
416 | dependencies = (
417 | BA0B34D3264FA4F800774AA0 /* PBXTargetDependency */,
418 | );
419 | name = TransNotionTests;
420 | productName = TransNotionTests;
421 | productReference = BA0B34D1264FA4F800774AA0 /* TransNotionTests.xctest */;
422 | productType = "com.apple.product-type.bundle.unit-test";
423 | };
424 | BA0B34DB264FA4F800774AA0 /* TransNotionUITests */ = {
425 | isa = PBXNativeTarget;
426 | buildConfigurationList = BA0B34EB264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotionUITests" */;
427 | buildPhases = (
428 | BA0B34D8264FA4F800774AA0 /* Sources */,
429 | BA0B34D9264FA4F800774AA0 /* Frameworks */,
430 | BA0B34DA264FA4F800774AA0 /* Resources */,
431 | );
432 | buildRules = (
433 | );
434 | dependencies = (
435 | BA0B34DE264FA4F800774AA0 /* PBXTargetDependency */,
436 | );
437 | name = TransNotionUITests;
438 | productName = TransNotionUITests;
439 | productReference = BA0B34DC264FA4F800774AA0 /* TransNotionUITests.xctest */;
440 | productType = "com.apple.product-type.bundle.ui-testing";
441 | };
442 | /* End PBXNativeTarget section */
443 |
444 | /* Begin PBXProject section */
445 | BA0B34B8264FA4F100774AA0 /* Project object */ = {
446 | isa = PBXProject;
447 | attributes = {
448 | LastSwiftUpdateCheck = 1240;
449 | LastUpgradeCheck = 1240;
450 | TargetAttributes = {
451 | BA0B34BF264FA4F100774AA0 = {
452 | CreatedOnToolsVersion = 12.4;
453 | };
454 | BA0B34D0264FA4F800774AA0 = {
455 | CreatedOnToolsVersion = 12.4;
456 | TestTargetID = BA0B34BF264FA4F100774AA0;
457 | };
458 | BA0B34DB264FA4F800774AA0 = {
459 | CreatedOnToolsVersion = 12.4;
460 | TestTargetID = BA0B34BF264FA4F100774AA0;
461 | };
462 | };
463 | };
464 | buildConfigurationList = BA0B34BB264FA4F100774AA0 /* Build configuration list for PBXProject "TransNotion" */;
465 | compatibilityVersion = "Xcode 9.3";
466 | developmentRegion = en;
467 | hasScannedForEncodings = 0;
468 | knownRegions = (
469 | en,
470 | Base,
471 | ja,
472 | );
473 | mainGroup = BA0B34B7264FA4F100774AA0;
474 | packageReferences = (
475 | BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
476 | BA00721B2651C99C001DFFCB /* XCRemoteSwiftPackageReference "notion" */,
477 | );
478 | productRefGroup = BA0B34C1264FA4F100774AA0 /* Products */;
479 | projectDirPath = "";
480 | projectRoot = "";
481 | targets = (
482 | BA0B34BF264FA4F100774AA0 /* TransNotion */,
483 | BA0B34D0264FA4F800774AA0 /* TransNotionTests */,
484 | BA0B34DB264FA4F800774AA0 /* TransNotionUITests */,
485 | );
486 | };
487 | /* End PBXProject section */
488 |
489 | /* Begin PBXResourcesBuildPhase section */
490 | BA0B34BE264FA4F100774AA0 /* Resources */ = {
491 | isa = PBXResourcesBuildPhase;
492 | buildActionMask = 2147483647;
493 | files = (
494 | BA00718D26508564001DFFCB /* Debug.xcconfig in Resources */,
495 | BA0071E92650A401001DFFCB /* GoogleService-Info-dev.plist in Resources */,
496 | BA0B34CB264FA4F800774AA0 /* Preview Assets.xcassets in Resources */,
497 | BACEC6EF264FF9430070D31B /* Localizable.strings in Resources */,
498 | BA0B34C8264FA4F800774AA0 /* Assets.xcassets in Resources */,
499 | BA00718F26508564001DFFCB /* Debug-Secret.xcconfig in Resources */,
500 | BA00719026508564001DFFCB /* Release-Secret.xcconfig in Resources */,
501 | BA00718E26508564001DFFCB /* Release.xcconfig in Resources */,
502 | );
503 | runOnlyForDeploymentPostprocessing = 0;
504 | };
505 | BA0B34CF264FA4F800774AA0 /* Resources */ = {
506 | isa = PBXResourcesBuildPhase;
507 | buildActionMask = 2147483647;
508 | files = (
509 | );
510 | runOnlyForDeploymentPostprocessing = 0;
511 | };
512 | BA0B34DA264FA4F800774AA0 /* Resources */ = {
513 | isa = PBXResourcesBuildPhase;
514 | buildActionMask = 2147483647;
515 | files = (
516 | );
517 | runOnlyForDeploymentPostprocessing = 0;
518 | };
519 | /* End PBXResourcesBuildPhase section */
520 |
521 | /* Begin PBXSourcesBuildPhase section */
522 | BA0B34BC264FA4F100774AA0 /* Sources */ = {
523 | isa = PBXSourcesBuildPhase;
524 | buildActionMask = 2147483647;
525 | files = (
526 | BA0071F126511CFC001DFFCB /* LocalStore.swift in Sources */,
527 | BA842EBF2651DF0400399BDB /* NotionPage.swift in Sources */,
528 | BACEC6C2264FF4B90070D31B /* LoginView.swift in Sources */,
529 | BACEC6E1264FF7EB0070D31B /* Color+Extension.swift in Sources */,
530 | 20F7E1202682287400F0024A /* Button.swift in Sources */,
531 | BACEC6D2264FF5030070D31B /* Database.swift in Sources */,
532 | BA00720B26512E89001DFFCB /* JSONCoder+Extension.swift in Sources */,
533 | BA0072342651CB05001DFFCB /* Environment+notion.swift in Sources */,
534 | 20F7E11D2682145A00F0024A /* Placeholder.swift in Sources */,
535 | BA0071A826509001001DFFCB /* Environment+Window.swift in Sources */,
536 | BACEC6CF264FF5030070D31B /* DatabaseEntity.swift in Sources */,
537 | BACEC6D0264FF5030070D31B /* DocumentReference+Combine.swift in Sources */,
538 | BAD32C4D264FDDAB00DD7824 /* AppDelegate.swift in Sources */,
539 | BACEC6BD264FF4AC0070D31B /* ContentView.swift in Sources */,
540 | BA00719F2650886C001DFFCB /* OAuth.swift in Sources */,
541 | BA00720226512D63001DFFCB /* ErrorLogger.swift in Sources */,
542 | BA0071FC26512C9C001DFFCB /* Credential.swift in Sources */,
543 | BACEC6DB264FF54B0070D31B /* User.swift in Sources */,
544 | BACEC6CE264FF5030070D31B /* DatabasePathBuilder.swift in Sources */,
545 | BA0B34C6264FA4F100774AA0 /* RootView.swift in Sources */,
546 | BACEC6D1264FF5030070D31B /* CollectionReference+Combine.swift in Sources */,
547 | 20F7E11A26820EA500F0024A /* NotionWebViewPage.swift in Sources */,
548 | BACEC6DA264FF54B0070D31B /* Me.swift in Sources */,
549 | 20F7E1182681FDF400F0024A /* Notion.Object.Page+Extension.swift in Sources */,
550 | BAD32BE3264FC50B00DD7824 /* Secret.swift in Sources */,
551 | 20F7E1162681F65A00F0024A /* NotionWebView.swift in Sources */,
552 | BA0B34C4264FA4F100774AA0 /* TransNotionApp.swift in Sources */,
553 | 20F7E1222682CC5B00F0024A /* Toggle.swift in Sources */,
554 | BACEC6D3264FF5030070D31B /* Auth.swift in Sources */,
555 | BA00722C2651C9E6001DFFCB /* NotionPagesView.swift in Sources */,
556 | );
557 | runOnlyForDeploymentPostprocessing = 0;
558 | };
559 | BA0B34CD264FA4F800774AA0 /* Sources */ = {
560 | isa = PBXSourcesBuildPhase;
561 | buildActionMask = 2147483647;
562 | files = (
563 | BA0B34D6264FA4F800774AA0 /* TransNotionTests.swift in Sources */,
564 | );
565 | runOnlyForDeploymentPostprocessing = 0;
566 | };
567 | BA0B34D8264FA4F800774AA0 /* Sources */ = {
568 | isa = PBXSourcesBuildPhase;
569 | buildActionMask = 2147483647;
570 | files = (
571 | BA0B34E1264FA4F800774AA0 /* TransNotionUITests.swift in Sources */,
572 | );
573 | runOnlyForDeploymentPostprocessing = 0;
574 | };
575 | /* End PBXSourcesBuildPhase section */
576 |
577 | /* Begin PBXTargetDependency section */
578 | BA0B34D3264FA4F800774AA0 /* PBXTargetDependency */ = {
579 | isa = PBXTargetDependency;
580 | target = BA0B34BF264FA4F100774AA0 /* TransNotion */;
581 | targetProxy = BA0B34D2264FA4F800774AA0 /* PBXContainerItemProxy */;
582 | };
583 | BA0B34DE264FA4F800774AA0 /* PBXTargetDependency */ = {
584 | isa = PBXTargetDependency;
585 | target = BA0B34BF264FA4F100774AA0 /* TransNotion */;
586 | targetProxy = BA0B34DD264FA4F800774AA0 /* PBXContainerItemProxy */;
587 | };
588 | /* End PBXTargetDependency section */
589 |
590 | /* Begin PBXVariantGroup section */
591 | BACEC6F1264FF9430070D31B /* Localizable.strings */ = {
592 | isa = PBXVariantGroup;
593 | children = (
594 | BACEC6F0264FF9430070D31B /* en */,
595 | BACEC6F5264FF9690070D31B /* ja */,
596 | );
597 | name = Localizable.strings;
598 | sourceTree = "";
599 | };
600 | /* End PBXVariantGroup section */
601 |
602 | /* Begin XCBuildConfiguration section */
603 | BA0B34E3264FA4F800774AA0 /* Debug */ = {
604 | isa = XCBuildConfiguration;
605 | baseConfigurationReference = BA00718926508564001DFFCB /* Debug.xcconfig */;
606 | buildSettings = {
607 | ALWAYS_SEARCH_USER_PATHS = NO;
608 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
609 | CLANG_ANALYZER_NONNULL = YES;
610 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
611 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
612 | CLANG_CXX_LIBRARY = "libc++";
613 | CLANG_ENABLE_MODULES = YES;
614 | CLANG_ENABLE_OBJC_ARC = YES;
615 | CLANG_ENABLE_OBJC_WEAK = YES;
616 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
617 | CLANG_WARN_BOOL_CONVERSION = YES;
618 | CLANG_WARN_COMMA = YES;
619 | CLANG_WARN_CONSTANT_CONVERSION = YES;
620 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
621 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
622 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
623 | CLANG_WARN_EMPTY_BODY = YES;
624 | CLANG_WARN_ENUM_CONVERSION = YES;
625 | CLANG_WARN_INFINITE_RECURSION = YES;
626 | CLANG_WARN_INT_CONVERSION = YES;
627 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
628 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
629 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
630 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
631 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
632 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
633 | CLANG_WARN_STRICT_PROTOTYPES = YES;
634 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
635 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
636 | CLANG_WARN_UNREACHABLE_CODE = YES;
637 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
638 | COPY_PHASE_STRIP = NO;
639 | DEBUG_INFORMATION_FORMAT = dwarf;
640 | ENABLE_STRICT_OBJC_MSGSEND = YES;
641 | ENABLE_TESTABILITY = YES;
642 | GCC_C_LANGUAGE_STANDARD = gnu11;
643 | GCC_DYNAMIC_NO_PIC = NO;
644 | GCC_NO_COMMON_BLOCKS = YES;
645 | GCC_OPTIMIZATION_LEVEL = 0;
646 | GCC_PREPROCESSOR_DEFINITIONS = (
647 | "DEBUG=1",
648 | "$(inherited)",
649 | );
650 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
651 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
652 | GCC_WARN_UNDECLARED_SELECTOR = YES;
653 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
654 | GCC_WARN_UNUSED_FUNCTION = YES;
655 | GCC_WARN_UNUSED_VARIABLE = YES;
656 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
657 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
658 | MTL_FAST_MATH = YES;
659 | ONLY_ACTIVE_ARCH = YES;
660 | SDKROOT = iphoneos;
661 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
662 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
663 | };
664 | name = Debug;
665 | };
666 | BA0B34E4264FA4F800774AA0 /* Release */ = {
667 | isa = XCBuildConfiguration;
668 | baseConfigurationReference = BA00718A26508564001DFFCB /* Release.xcconfig */;
669 | buildSettings = {
670 | ALWAYS_SEARCH_USER_PATHS = NO;
671 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
672 | CLANG_ANALYZER_NONNULL = YES;
673 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
674 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
675 | CLANG_CXX_LIBRARY = "libc++";
676 | CLANG_ENABLE_MODULES = YES;
677 | CLANG_ENABLE_OBJC_ARC = YES;
678 | CLANG_ENABLE_OBJC_WEAK = YES;
679 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
680 | CLANG_WARN_BOOL_CONVERSION = YES;
681 | CLANG_WARN_COMMA = YES;
682 | CLANG_WARN_CONSTANT_CONVERSION = YES;
683 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
684 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
685 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
686 | CLANG_WARN_EMPTY_BODY = YES;
687 | CLANG_WARN_ENUM_CONVERSION = YES;
688 | CLANG_WARN_INFINITE_RECURSION = YES;
689 | CLANG_WARN_INT_CONVERSION = YES;
690 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
691 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
692 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
693 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
694 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
695 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
696 | CLANG_WARN_STRICT_PROTOTYPES = YES;
697 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
698 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
699 | CLANG_WARN_UNREACHABLE_CODE = YES;
700 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
701 | COPY_PHASE_STRIP = NO;
702 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
703 | ENABLE_NS_ASSERTIONS = NO;
704 | ENABLE_STRICT_OBJC_MSGSEND = YES;
705 | GCC_C_LANGUAGE_STANDARD = gnu11;
706 | GCC_NO_COMMON_BLOCKS = YES;
707 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
708 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
709 | GCC_WARN_UNDECLARED_SELECTOR = YES;
710 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
711 | GCC_WARN_UNUSED_FUNCTION = YES;
712 | GCC_WARN_UNUSED_VARIABLE = YES;
713 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
714 | MTL_ENABLE_DEBUG_INFO = NO;
715 | MTL_FAST_MATH = YES;
716 | SDKROOT = iphoneos;
717 | SWIFT_COMPILATION_MODE = wholemodule;
718 | SWIFT_OPTIMIZATION_LEVEL = "-O";
719 | VALIDATE_PRODUCT = YES;
720 | };
721 | name = Release;
722 | };
723 | BA0B34E6264FA4F800774AA0 /* Debug */ = {
724 | isa = XCBuildConfiguration;
725 | buildSettings = {
726 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
727 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
728 | CODE_SIGN_STYLE = Automatic;
729 | DEVELOPMENT_ASSET_PATHS = "\"TransNotion/Preview Content\"";
730 | DEVELOPMENT_TEAM = TQPN82UBBY;
731 | ENABLE_PREVIEWS = YES;
732 | INFOPLIST_FILE = TransNotion/Info.plist;
733 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
734 | LD_RUNPATH_SEARCH_PATHS = (
735 | "$(inherited)",
736 | "@executable_path/Frameworks",
737 | );
738 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion;
739 | PRODUCT_NAME = "$(TARGET_NAME)";
740 | SWIFT_VERSION = 5.0;
741 | TARGETED_DEVICE_FAMILY = "1,2";
742 | };
743 | name = Debug;
744 | };
745 | BA0B34E7264FA4F800774AA0 /* Release */ = {
746 | isa = XCBuildConfiguration;
747 | buildSettings = {
748 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
749 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
750 | CODE_SIGN_STYLE = Automatic;
751 | DEVELOPMENT_ASSET_PATHS = "\"TransNotion/Preview Content\"";
752 | DEVELOPMENT_TEAM = TQPN82UBBY;
753 | ENABLE_PREVIEWS = YES;
754 | INFOPLIST_FILE = TransNotion/Info.plist;
755 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
756 | LD_RUNPATH_SEARCH_PATHS = (
757 | "$(inherited)",
758 | "@executable_path/Frameworks",
759 | );
760 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion;
761 | PRODUCT_NAME = "$(TARGET_NAME)";
762 | SWIFT_VERSION = 5.0;
763 | TARGETED_DEVICE_FAMILY = "1,2";
764 | };
765 | name = Release;
766 | };
767 | BA0B34E9264FA4F800774AA0 /* Debug */ = {
768 | isa = XCBuildConfiguration;
769 | buildSettings = {
770 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
771 | BUNDLE_LOADER = "$(TEST_HOST)";
772 | CODE_SIGN_STYLE = Automatic;
773 | DEVELOPMENT_TEAM = TQPN82UBBY;
774 | INFOPLIST_FILE = TransNotionTests/Info.plist;
775 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
776 | LD_RUNPATH_SEARCH_PATHS = (
777 | "$(inherited)",
778 | "@executable_path/Frameworks",
779 | "@loader_path/Frameworks",
780 | );
781 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion.TransNotionTests;
782 | PRODUCT_NAME = "$(TARGET_NAME)";
783 | SWIFT_VERSION = 5.0;
784 | TARGETED_DEVICE_FAMILY = "1,2";
785 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TransNotion.app/TransNotion";
786 | };
787 | name = Debug;
788 | };
789 | BA0B34EA264FA4F800774AA0 /* Release */ = {
790 | isa = XCBuildConfiguration;
791 | buildSettings = {
792 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
793 | BUNDLE_LOADER = "$(TEST_HOST)";
794 | CODE_SIGN_STYLE = Automatic;
795 | DEVELOPMENT_TEAM = TQPN82UBBY;
796 | INFOPLIST_FILE = TransNotionTests/Info.plist;
797 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
798 | LD_RUNPATH_SEARCH_PATHS = (
799 | "$(inherited)",
800 | "@executable_path/Frameworks",
801 | "@loader_path/Frameworks",
802 | );
803 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion.TransNotionTests;
804 | PRODUCT_NAME = "$(TARGET_NAME)";
805 | SWIFT_VERSION = 5.0;
806 | TARGETED_DEVICE_FAMILY = "1,2";
807 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TransNotion.app/TransNotion";
808 | };
809 | name = Release;
810 | };
811 | BA0B34EC264FA4F800774AA0 /* Debug */ = {
812 | isa = XCBuildConfiguration;
813 | buildSettings = {
814 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
815 | CODE_SIGN_STYLE = Automatic;
816 | DEVELOPMENT_TEAM = TQPN82UBBY;
817 | INFOPLIST_FILE = TransNotionUITests/Info.plist;
818 | LD_RUNPATH_SEARCH_PATHS = (
819 | "$(inherited)",
820 | "@executable_path/Frameworks",
821 | "@loader_path/Frameworks",
822 | );
823 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion.TransNotionUITests;
824 | PRODUCT_NAME = "$(TARGET_NAME)";
825 | SWIFT_VERSION = 5.0;
826 | TARGETED_DEVICE_FAMILY = "1,2";
827 | TEST_TARGET_NAME = TransNotion;
828 | };
829 | name = Debug;
830 | };
831 | BA0B34ED264FA4F800774AA0 /* Release */ = {
832 | isa = XCBuildConfiguration;
833 | buildSettings = {
834 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
835 | CODE_SIGN_STYLE = Automatic;
836 | DEVELOPMENT_TEAM = TQPN82UBBY;
837 | INFOPLIST_FILE = TransNotionUITests/Info.plist;
838 | LD_RUNPATH_SEARCH_PATHS = (
839 | "$(inherited)",
840 | "@executable_path/Frameworks",
841 | "@loader_path/Frameworks",
842 | );
843 | PRODUCT_BUNDLE_IDENTIFIER = com.bannzai.transnotion.TransNotionUITests;
844 | PRODUCT_NAME = "$(TARGET_NAME)";
845 | SWIFT_VERSION = 5.0;
846 | TARGETED_DEVICE_FAMILY = "1,2";
847 | TEST_TARGET_NAME = TransNotion;
848 | };
849 | name = Release;
850 | };
851 | /* End XCBuildConfiguration section */
852 |
853 | /* Begin XCConfigurationList section */
854 | BA0B34BB264FA4F100774AA0 /* Build configuration list for PBXProject "TransNotion" */ = {
855 | isa = XCConfigurationList;
856 | buildConfigurations = (
857 | BA0B34E3264FA4F800774AA0 /* Debug */,
858 | BA0B34E4264FA4F800774AA0 /* Release */,
859 | );
860 | defaultConfigurationIsVisible = 0;
861 | defaultConfigurationName = Release;
862 | };
863 | BA0B34E5264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotion" */ = {
864 | isa = XCConfigurationList;
865 | buildConfigurations = (
866 | BA0B34E6264FA4F800774AA0 /* Debug */,
867 | BA0B34E7264FA4F800774AA0 /* Release */,
868 | );
869 | defaultConfigurationIsVisible = 0;
870 | defaultConfigurationName = Release;
871 | };
872 | BA0B34E8264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotionTests" */ = {
873 | isa = XCConfigurationList;
874 | buildConfigurations = (
875 | BA0B34E9264FA4F800774AA0 /* Debug */,
876 | BA0B34EA264FA4F800774AA0 /* Release */,
877 | );
878 | defaultConfigurationIsVisible = 0;
879 | defaultConfigurationName = Release;
880 | };
881 | BA0B34EB264FA4F800774AA0 /* Build configuration list for PBXNativeTarget "TransNotionUITests" */ = {
882 | isa = XCConfigurationList;
883 | buildConfigurations = (
884 | BA0B34EC264FA4F800774AA0 /* Debug */,
885 | BA0B34ED264FA4F800774AA0 /* Release */,
886 | );
887 | defaultConfigurationIsVisible = 0;
888 | defaultConfigurationName = Release;
889 | };
890 | /* End XCConfigurationList section */
891 |
892 | /* Begin XCRemoteSwiftPackageReference section */
893 | BA00721B2651C99C001DFFCB /* XCRemoteSwiftPackageReference "notion" */ = {
894 | isa = XCRemoteSwiftPackageReference;
895 | repositoryURL = "git@github.com:noppefoxwolf/notion.git";
896 | requirement = {
897 | kind = upToNextMajorVersion;
898 | minimumVersion = 0.1.1;
899 | };
900 | };
901 | BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
902 | isa = XCRemoteSwiftPackageReference;
903 | repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
904 | requirement = {
905 | kind = upToNextMajorVersion;
906 | minimumVersion = 8.0.0;
907 | };
908 | };
909 | /* End XCRemoteSwiftPackageReference section */
910 |
911 | /* Begin XCSwiftPackageProductDependency section */
912 | BA00721C2651C99C001DFFCB /* notion */ = {
913 | isa = XCSwiftPackageProductDependency;
914 | package = BA00721B2651C99C001DFFCB /* XCRemoteSwiftPackageReference "notion" */;
915 | productName = notion;
916 | };
917 | BAD32C3E264FCE5C00DD7824 /* FirebaseFirestoreSwift-Beta */ = {
918 | isa = XCSwiftPackageProductDependency;
919 | package = BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
920 | productName = "FirebaseFirestoreSwift-Beta";
921 | };
922 | BAD32C40264FCE5C00DD7824 /* FirebaseCrashlytics */ = {
923 | isa = XCSwiftPackageProductDependency;
924 | package = BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
925 | productName = FirebaseCrashlytics;
926 | };
927 | BAD32C42264FCE5C00DD7824 /* FirebaseAuth */ = {
928 | isa = XCSwiftPackageProductDependency;
929 | package = BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
930 | productName = FirebaseAuth;
931 | };
932 | BAD32C44264FCE5C00DD7824 /* FirebaseAnalyticsSwift-Beta */ = {
933 | isa = XCSwiftPackageProductDependency;
934 | package = BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
935 | productName = "FirebaseAnalyticsSwift-Beta";
936 | };
937 | BAD32C46264FCE5C00DD7824 /* FirebaseFirestore */ = {
938 | isa = XCSwiftPackageProductDependency;
939 | package = BAD32C3D264FCE5C00DD7824 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
940 | productName = FirebaseFirestore;
941 | };
942 | /* End XCSwiftPackageProductDependency section */
943 | };
944 | rootObject = BA0B34B8264FA4F100774AA0 /* Project object */;
945 | }
946 |
--------------------------------------------------------------------------------