Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ jobs:
bundler-cache: true
- run: bundle exec rubocop

test:
name: Test
runs-on: macos-26
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install XcodeGen
run: brew install xcodegen
- run: bundle exec fastlane ios test

build-ios-debug:
name: Build iOS/iPadOS Debug
runs-on: macos-26
Expand Down
1 change: 1 addition & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ README.md
*.jpg
Jottre.xcodeproj
Resources
Tests/Resources
hooks
fastlane
Gemfile
Expand Down
5 changes: 5 additions & 0 deletions Sources/CloudMigrationPage/CloudMigrationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@

import UIKit

@MainActor
protocol CloudMigrationCoordinatorProtocol: Coordinator {

func shouldStart() -> Bool

func showInfoAlert(title: String, message: String)

func dismiss()
}

final class CloudMigrationCoordinator: CloudMigrationCoordinatorProtocol {
Expand Down
4 changes: 2 additions & 2 deletions Sources/CloudMigrationPage/CloudMigrationViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class CloudMigrationViewModel: PageViewModel, Sendable {
private let itemsContinuation: AsyncStream<[PageCellItem]>.Continuation

private let repository: CloudMigrationRepositoryProtocol
private weak var coordinator: CloudMigrationCoordinator?
private weak var coordinator: CloudMigrationCoordinatorProtocol?

private(set) lazy var actions = [
PageCallToActionView.ActionConfiguration(
Expand All @@ -41,7 +41,7 @@ final class CloudMigrationViewModel: PageViewModel, Sendable {

init(
repository: CloudMigrationRepositoryProtocol,
coordinator: CloudMigrationCoordinator
coordinator: CloudMigrationCoordinatorProtocol
) {
self.repository = repository
self.coordinator = coordinator
Expand Down
23 changes: 22 additions & 1 deletion Sources/EditJotPage/EditJotCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,28 @@

import UIKit

final class EditJotCoordinator: NavigationCoordinator {
protocol EditJotCoordinatorProtocol: NavigationCoordinator {

func showShareJot(
jotFileInfo: JotFile.Info,
format: ShareFormat,
configurePopoverAnchor: PopoverAnchor?
)
func showRenameAlert(jotFileInfo: JotFile.Info)
func openDeleteJot(jotFileInfo: JotFile.Info)
func openJot(jotFileInfo: JotFile.Info)
func showInFiles(jotFileInfo: JotFile.Info)
func showJotConflictPage(
jotFileInfo: JotFile.Info,
jotFileVersions: [JotFileVersion],
onResult: @Sendable @escaping (_ result: JotConflictResult) -> Void
)
func canGoBack() -> Bool
func goBack()
func showInfoAlert(title: String, message: String)
}

final class EditJotCoordinator: NavigationCoordinator, EditJotCoordinatorProtocol {

private var retainedInfoAlertCoordinator: Coordinator?

Expand Down
4 changes: 2 additions & 2 deletions Sources/EditJotPage/EditJotViewControllerFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protocol EditJotViewControllerFactoryProtocol: Sendable {

func make(
jotFileInfo: JotFile.Info,
coordinator: EditJotCoordinator
coordinator: EditJotCoordinatorProtocol
) -> UIViewController
}

Expand All @@ -35,7 +35,7 @@ struct EditJotViewControllerFactory: EditJotViewControllerFactoryProtocol {

func make(
jotFileInfo: JotFile.Info,
coordinator: EditJotCoordinator,
coordinator: EditJotCoordinatorProtocol,
) -> UIViewController {
EditJotViewController(
viewModel: EditJotViewModel(
Expand Down
4 changes: 2 additions & 2 deletions Sources/EditJotPage/EditJotViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ final class EditJotViewModel: Sendable {

private let jotFileInfo: JotFile.Info
private let repository: EditJotRepositoryProtocol
private weak var coordinator: EditJotCoordinator?
private weak var coordinator: EditJotCoordinatorProtocol?
private let menuConfigurationFactory: JotMenuConfigurationFactory

init(
jotFileInfo: JotFile.Info,
repository: EditJotRepositoryProtocol,
coordinator: EditJotCoordinator,
coordinator: EditJotCoordinatorProtocol,
menuConfigurationFactory: JotMenuConfigurationFactory
) {
self.jotFileInfo = jotFileInfo
Expand Down
8 changes: 7 additions & 1 deletion Sources/EnableCloudPage/EnableCloudCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@

import UIKit

final class EnableCloudCoordinator: Coordinator {
protocol EnableCloudCoordinatorProtocol: Coordinator {

func openLearnHowToEnable()
func dismiss()
}

final class EnableCloudCoordinator: Coordinator, EnableCloudCoordinatorProtocol {

var onEnd: (() -> Void)?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ import UIKit
@MainActor
protocol EnableCloudViewControllerFactoryProtocol: Sendable {

func make(coordinator: EnableCloudCoordinator) -> UIViewController
func make(coordinator: EnableCloudCoordinatorProtocol) -> UIViewController
}

struct EnableCloudViewControllerFactory: EnableCloudViewControllerFactoryProtocol {

let textBarButtonItemFactory: TextBarButtonItemFactory
let symbolBarButtonItemFactory: SymbolBarButtonItemFactory

func make(coordinator: EnableCloudCoordinator) -> UIViewController {
func make(coordinator: EnableCloudCoordinatorProtocol) -> UIViewController {
PageViewController(
viewModel: EnableCloudViewModel(
coordinator: coordinator
Expand Down
4 changes: 2 additions & 2 deletions Sources/EnableCloudPage/EnableCloudViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ final class EnableCloudViewModel: PageViewModel, Sendable {
let items: AsyncStream<[PageCellItem]>
private let itemsContinuation: AsyncStream<[PageCellItem]>.Continuation

private weak var coordinator: EnableCloudCoordinator?
private weak var coordinator: EnableCloudCoordinatorProtocol?

private(set) lazy var actions = [
PageCallToActionView.ActionConfiguration(
Expand All @@ -39,7 +39,7 @@ final class EnableCloudViewModel: PageViewModel, Sendable {
}
]

init(coordinator: EnableCloudCoordinator) {
init(coordinator: EnableCloudCoordinatorProtocol) {
self.coordinator = coordinator

(items, itemsContinuation) = AsyncStream.makeStream(
Expand Down
8 changes: 7 additions & 1 deletion Sources/JotConflictPage/JotConflictCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@

import UIKit

final class JotConflictCoordinator: Coordinator {
protocol JotConflictCoordinatorProtocol: Coordinator {

func showInfoAlert(title: String, message: String)
func dismiss(completion: @Sendable @escaping () -> Void)
}

final class JotConflictCoordinator: Coordinator, JotConflictCoordinatorProtocol {

private var retainedInfoAlertCoordinator: Coordinator?

Expand Down
4 changes: 2 additions & 2 deletions Sources/JotConflictPage/JotConflictViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ final class JotConflictViewModel: PageViewModel, Sendable {
private let jotFileInfo: JotFile.Info
private let jotFileVersions: [JotFileVersion]
private let repository: JotConflictRepositoryProtocol
private weak var coordinator: JotConflictCoordinator?
private weak var coordinator: JotConflictCoordinatorProtocol?
private let onResult: @Sendable (_ result: JotConflictResult) -> Void

init(
jotFileInfo: JotFile.Info,
jotFileVersions: [JotFileVersion],
repository: JotConflictRepositoryProtocol,
coordinator: JotConflictCoordinator,
coordinator: JotConflictCoordinatorProtocol,
onResult: @Sendable @escaping (_ result: JotConflictResult) -> Void
) {
assert(jotFileVersions.count >= 1, "Resolving a version conflict between less than two files is not logical.")
Expand Down
39 changes: 28 additions & 11 deletions Sources/JotsPage/JotsCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,25 @@

import UIKit

protocol JotsCoordinatorProtocol: NavigationCoordinator {

func openSettings()
func openCreateJot()
func openJot(jotFileInfo: JotFile.Info, prefersNewWindow: Bool)
func openEnableCloudPage()
func showShareJot(
jotFileInfo: JotFile.Info,
format: ShareFormat,
configurePopoverAnchor: PopoverAnchor?
)
func showRenameAlert(jotFileInfo: JotFile.Info)
func openDeleteJot(jotFileInfo: JotFile.Info)
func showInfoAlert(title: String, message: String)
func showInFiles(jotFileInfo: JotFile.Info)
}

@MainActor
final class JotsCoordinator: NavigationCoordinator {
final class JotsCoordinator: NavigationCoordinator, JotsCoordinatorProtocol {

private var cloudMigrationTask: Task<Void, Never>?

Expand All @@ -40,11 +57,11 @@ final class JotsCoordinator: NavigationCoordinator {
]

private let navigation: Navigation
private let jotsViewControllerFactory: JotsViewControllerFactory
private let settingsCoordinatorFactory: SettingsCoordinatorFactory
private let enableCloudCoordinatorFactory: EnableCloudCoordinatorFactory
private let editJotCoordinatorFactory: EditJotCoordinatorFactory
private let cloudMigrationCoordinatorFactory: CloudMigrationCoordinatorFactory
private let jotsViewControllerFactory: JotsViewControllerFactoryProtocol
private let settingsCoordinatorFactory: SettingsCoordinatorFactoryProtocol
private let enableCloudCoordinatorFactory: EnableCloudCoordinatorFactoryProtocol
private let editJotCoordinatorFactory: EditJotCoordinatorFactoryProtocol
private let cloudMigrationCoordinatorFactory: CloudMigrationCoordinatorFactoryProtocol
private let createJotCoordinatorFactory: CreateJotCoordinatorFactoryProtocol
private let deleteJotCoordinatorFactory: DeleteJotCoordinatorFactoryProtocol
private let renameJotCoordinatorFactory: RenameJotCoordinatorFactoryProtocol
Expand All @@ -53,11 +70,11 @@ final class JotsCoordinator: NavigationCoordinator {

init(
navigation: Navigation,
jotsViewControllerFactory: JotsViewControllerFactory,
settingsCoordinatorFactory: SettingsCoordinatorFactory,
enableCloudCoordinatorFactory: EnableCloudCoordinatorFactory,
editJotCoordinatorFactory: EditJotCoordinatorFactory,
cloudMigrationCoordinatorFactory: CloudMigrationCoordinatorFactory,
jotsViewControllerFactory: JotsViewControllerFactoryProtocol,
settingsCoordinatorFactory: SettingsCoordinatorFactoryProtocol,
enableCloudCoordinatorFactory: EnableCloudCoordinatorFactoryProtocol,
editJotCoordinatorFactory: EditJotCoordinatorFactoryProtocol,
cloudMigrationCoordinatorFactory: CloudMigrationCoordinatorFactoryProtocol,
createJotCoordinatorFactory: CreateJotCoordinatorFactoryProtocol,
deleteJotCoordinatorFactory: DeleteJotCoordinatorFactoryProtocol,
renameJotCoordinatorFactory: RenameJotCoordinatorFactoryProtocol,
Expand Down
4 changes: 2 additions & 2 deletions Sources/JotsPage/JotsViewControllerFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import UIKit
@MainActor
protocol JotsViewControllerFactoryProtocol: Sendable {

func make(coordinator: JotsCoordinator) -> UIViewController
func make(coordinator: JotsCoordinatorProtocol) -> UIViewController
}

struct JotsViewControllerFactory: JotsViewControllerFactoryProtocol {
Expand All @@ -31,7 +31,7 @@ struct JotsViewControllerFactory: JotsViewControllerFactoryProtocol {
let textBarButtonItemFactory: TextBarButtonItemFactory
let symbolBarButtonItemFactory: SymbolBarButtonItemFactory

func make(coordinator: JotsCoordinator) -> UIViewController {
func make(coordinator: JotsCoordinatorProtocol) -> UIViewController {
let viewController = PageViewController(
viewModel: JotsViewModel(
coordinator: coordinator,
Expand Down
4 changes: 2 additions & 2 deletions Sources/JotsPage/JotsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ final class JotsViewModel: PageViewModel {

private var jotsTask: Task<Void, Never>?

private weak var coordinator: JotsCoordinator?
private weak var coordinator: JotsCoordinatorProtocol?

private let repository: JotsRepositoryProtocol
private let menuConfigurationFactory: JotMenuConfigurationFactory

init(
coordinator: JotsCoordinator,
coordinator: JotsCoordinatorProtocol,
repository: JotsRepositoryProtocol,
menuConfigurationFactory: JotMenuConfigurationFactory
) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Navigation/NavigationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import UIKit

@MainActor
protocol NavigationCoordinator: Sendable {
protocol NavigationCoordinator: Sendable, AnyObject {

/// Whether this coordinator is capable of navigating to the given ``URL``.
func shouldHandle(url: URL) -> Bool
Expand Down
8 changes: 7 additions & 1 deletion Sources/SettingsPage/SettingsCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@

import UIKit

final class SettingsCoordinator: Coordinator {
protocol SettingsCoordinatorProtocol: Coordinator {

func openExternalLink(url: URL)
func dismiss()
}

final class SettingsCoordinator: Coordinator, SettingsCoordinatorProtocol {

var onEnd: (() -> Void)?

Expand Down
4 changes: 2 additions & 2 deletions Sources/SettingsPage/SettingsViewControllerFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import UIKit
@MainActor
protocol SettingsViewControllerFactoryProtocol: Sendable {

func make(coordinator: SettingsCoordinator) -> UIViewController
func make(coordinator: SettingsCoordinatorProtocol) -> UIViewController
}

struct SettingsViewControllerFactory: SettingsViewControllerFactoryProtocol {
Expand All @@ -30,7 +30,7 @@ struct SettingsViewControllerFactory: SettingsViewControllerFactoryProtocol {
let textBarButtonItemFactory: TextBarButtonItemFactory
let symbolBarButtonItemFactory: SymbolBarButtonItemFactory

func make(coordinator: SettingsCoordinator) -> UIViewController {
func make(coordinator: SettingsCoordinatorProtocol) -> UIViewController {
let viewController = PageViewController(
viewModel: SettingsViewModel(
repository: repository,
Expand Down
4 changes: 2 additions & 2 deletions Sources/SettingsPage/SettingsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ final class SettingsViewModel: PageViewModel {
private let itemsContinuation: AsyncStream<[PageCellItem]>.Continuation

private let repository: SettingsRepositoryProtocol
private weak var coordinator: SettingsCoordinator?
private weak var coordinator: SettingsCoordinatorProtocol?

private var loadingTask: Task<Void, Never>?

init(
repository: SettingsRepositoryProtocol,
coordinator: SettingsCoordinator
coordinator: SettingsCoordinatorProtocol
) {
self.repository = repository
self.coordinator = coordinator
Expand Down
36 changes: 36 additions & 0 deletions Tests/CloudMigrationPage/CloudImageCellViewModelTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Jottre: Minimalistic jotting for iPhone, iPad and Mac.
Copyright (C) 2021-2026 Anton Lorani

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import XCTest

@testable import Jottre

@MainActor
final class CloudImageCellViewModelTests: XCTestCase {

func test_handleAction_givenTap_doesNothing() {
// Given
let viewModel = CloudImageCellViewModel()

// When
viewModel.handle(action: .tap)

// Then
XCTAssertNotNil(viewModel)
}
}
Loading
Loading