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
1 change: 0 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ strict: true

file_header:
required_pattern: |
\/\/ SPDX-FileCopyrightText: Nextcloud GmbH
\/\/ SPDX-FileCopyrightText: 2025 .*?
\/\/ SPDX-License-Identifier: GPL-3.0-or-later
severity: error
Expand Down
11 changes: 7 additions & 4 deletions Networking/NoteSessionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,13 @@ class NoteSessionManager {
}
}

func update(note: NoteProtocol, completion: SyncCompletionBlock? = nil) {
func update(note: NoteProtocol, updateModified: Bool = true, completion: SyncCompletionBlock? = nil) {
logger.notice("Updating note...")

var incoming = note
incoming.updateNeeded = true
if NoteSessionManager.isOnline {
updateOnServer(incoming) { [weak self] result in
updateOnServer(incoming, updateModified: updateModified) { [weak self] result in
switch result {
case .success( _):
completion?()
Expand All @@ -538,11 +538,14 @@ class NoteSessionManager {
}
}

fileprivate func updateOnServer(_ note: NoteProtocol, handler: @escaping SyncHandler) {
fileprivate func updateOnServer(_ note: NoteProtocol, updateModified: Bool = true, handler: @escaping SyncHandler) {
// Metadata-only changes (e.g. toggling favorite) keep the existing modification date so the note does
// not jump to the top of a date-sorted list and the row is not re-sorted a second time after the sync.
let modified = updateModified ? Date().timeIntervalSince1970 : note.modified
let parameters: Parameters = ["title": note.title as Any,
"content": note.content as Any,
"category": note.category as Any,
"modified": Date().timeIntervalSince1970 as Any,
"modified": modified as Any,
"favorite": note.favorite]
let router = Router.updateNote(id: Int(note.id), paramters: parameters)
session
Expand Down
51 changes: 27 additions & 24 deletions Source/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,18 @@ import SwiftUI
class AppDelegate: UIResponder, UIApplicationDelegate {
var store = Store.shared

var notesTableViewController: NotesTableViewController?

///
/// Updated by being the `NextcloudKitDelegate`.
///
var networkReachability: NKCommon.TypeReachability?
var networkReachability: NKTypeReachability?

static var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}

private let operationQueue = OperationQueue()
private var updateFrcDelegateNeeded = true
private var pendingNoteToOpen: Note?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
NextcloudKit.shared.setup(delegate: self)

Expand All @@ -40,7 +38,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
userId: account.userId,
password: account.password,
userAgent: userAgent,
nextcloudVersion: account.serverVersion.major,
groupIdentifier: NCBrandOptions.shared.capabilitiesGroup
)
}
Expand Down Expand Up @@ -71,7 +68,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
UITableViewCell.appearance().backgroundColor = .ph_cellBackgroundColor

let scrollViewArray = [
NotesTableViewController.self,
CategoryTableViewController.self,
EditorViewController.self,
PreviewViewController.self,
Expand All @@ -95,8 +91,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
/// Scene lifecycle is adopted via ``SceneDelegate``; these handlers hold the shared behaviour it forwards.
///
func handleDidEnterBackground() {
notesTableViewController?.disableFetchedResultsController()
updateFrcDelegateNeeded = true
scheduleAppSync()
}

Expand All @@ -112,19 +106,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func handleDidBecomeActive() {
store.synchronize()
updateFrcDelegateIfNeeded()
}

private func updateFrcDelegateIfNeeded() {
guard updateFrcDelegateNeeded else {
return
DispatchQueue.main.async {
self.openPendingNoteIfNeeded()
}

updateFrcDelegateNeeded = false
notesTableViewController?.configureFetchedResultsController(performFetch: KeychainHelper.didSyncInBackground)
KeychainHelper.didSyncInBackground = false
}

func scheduleAppSync() {
BGTaskScheduler.shared.cancelAllTaskRequests()
let request = BGAppRefreshTaskRequest(identifier: "com.peterandlinda.iOCNotes.Sync")
Expand Down Expand Up @@ -167,9 +153,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let queryItems = urlComponents?.queryItems,
let item = queryItems.first(where: { $0.name == "note" }),
let content = item.value {
// Make sure we connect the delegate up, as this is called before the app is active
updateFrcDelegateIfNeeded()
self.notesTableViewController?.addNote(content: content)
NoteSessionManager.shared.add(content: content, category: "") { note in
guard let note = note else { return }
DispatchQueue.main.async {
self.openEditorWhenReady(for: note)
}
}
}
} else if url.isFileURL {
do {
Expand All @@ -184,6 +173,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
return true
}

private func openEditorWhenReady(for note: Note) {
guard NotesPresenter.openEditor(for: note, isNewNote: true) else {
pendingNoteToOpen = note
return
}

pendingNoteToOpen = nil
}

private func openPendingNoteIfNeeded() {
guard let pendingNoteToOpen else { return }
openEditorWhenReady(for: pendingNoteToOpen)
}
}

// MARK: - NextcloudKitDelegate
Expand All @@ -199,7 +202,7 @@ extension AppDelegate: NextcloudKitDelegate {
}
}

public func networkReachabilityObserver(_ typeReachability: NKCommon.TypeReachability) {
public func networkReachabilityObserver(_ typeReachability: NKTypeReachability) {
self.networkReachability = typeReachability
}
}
152 changes: 14 additions & 138 deletions Source/Base.lproj/Main_iPhone.storyboard
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Hnc-wc-q9I">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="R1o-2G-Lxf">
<device id="ipad11_0rounded" orientation="landscape" layout="fullscreen" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
Expand All @@ -8,99 +8,25 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Notes-->
<scene sceneID="rtV-CN-b4x">
<!--Navigation Controller-->
<scene sceneID="1o0-w2-ASY">
<objects>
<tableViewController storyboardIdentifier="Notes" id="DXe-Iw-CcD" customClass="NotesTableViewController" customModule="iOCNotes" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="K35-HQ-LQQ">
<rect key="frame" x="0.0" y="0.0" width="420" height="834"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
<color key="separatorColor" name="PHWhiteReadText"/>
<view key="tableFooterView" contentMode="scaleToFill" id="PUY-jA-gLM">
<rect key="frame" x="0.0" y="117.5" width="420" height="1"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="NoteCell" textLabel="1Q3-he-nuB" detailTextLabel="x61-QN-GPh" style="IBUITableViewCellStyleSubtitle" id="kka-p9-Iaq" customClass="NoteTableViewCell" customModule="iOCNotes" customModuleProvider="target">
<rect key="frame" x="0.0" y="55.5" width="420" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="kka-p9-Iaq" id="bx6-5a-S9d">
<rect key="frame" x="100" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="1Q3-he-nuB">
<rect key="frame" x="16" y="4" width="35" height="21.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" name="PHWhiteText"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="x61-QN-GPh">
<rect key="frame" x="16" y="25.5" width="44" height="14.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="R1o-2G-Lxf" kind="showDetail" identifier="showDetail" id="RCf-VZ-GG6"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="DXe-Iw-CcD" id="6Yr-UO-Tnt"/>
<outlet property="delegate" destination="DXe-Iw-CcD" id="lTT-Wj-gfA"/>
</connections>
</tableView>
<navigationController storyboardIdentifier="Editor" automaticallyAdjustsScrollViewInsets="NO" modalPresentationStyle="fullScreen" id="R1o-2G-Lxf" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" title="Notes" id="qfr-a2-foZ">
<rightBarButtonItems>
<barButtonItem systemItem="add" id="MOs-yv-oce">
<color key="tintColor" name="PHWhiteIcon"/>
<connections>
<action selector="onAddWithSender:" destination="DXe-Iw-CcD" id="8El-Gc-220"/>
</connections>
</barButtonItem>
<barButtonItem systemItem="refresh" id="Vq9-nq-q23">
<color key="tintColor" name="PHWhiteIcon"/>
<connections>
<action selector="onRefreshWithSender:" destination="DXe-Iw-CcD" id="2sU-BA-2fZ"/>
</connections>
</barButtonItem>
</rightBarButtonItems>
</navigationItem>
<refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="KYs-2X-3jY">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<navigationItem key="navigationItem" id="fUW-Ps-K5E"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Kus-pY-rHi">
<rect key="frame" x="0.0" y="0.0" width="1210" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<connections>
<action selector="onPullToRefresh:" destination="DXe-Iw-CcD" eventType="valueChanged" id="jv8-Ub-JzR"/>
</connections>
</refreshControl>
<connections>
<outlet property="addBarButton" destination="MOs-yv-oce" id="KfS-dy-ASJ"/>
<outlet property="refreshBarButton" destination="Vq9-nq-q23" id="MIf-rO-5SM"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2nj-I5-PGU" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1487" y="-1235"/>
</scene>
<!--Split View Controller-->
<scene sceneID="T5b-rp-L4S">
<objects>
<splitViewController allowDoubleColumnStyle="YES" id="Hnc-wc-q9I" customClass="PBHSplitViewController" customModule="iOCNotes" customModuleProvider="target" sceneMemberID="viewController">
<color key="tintColor" red="0.1176470588" green="0.1764705882" blue="0.26274509800000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="RQg-o0-i6F" kind="relationship" relationship="masterViewController" id="kQb-cu-1IE"/>
<segue destination="R1o-2G-Lxf" kind="relationship" relationship="detailViewController" id="2gj-xK-JEy"/>
<segue destination="vXZ-lx-hvc" kind="relationship" relationship="rootViewController" id="WOe-49-Vig"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Omp-bX-sKi" userLabel="First Responder" sceneMemberID="firstResponder"/>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bF7-Sg-WkW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-62" y="-978"/>
<point key="canvasLocation" x="703" y="-485"/>
</scene>
<!--Editor View Controller-->
<scene sceneID="ufC-wZ-h7g">
Expand Down Expand Up @@ -195,57 +121,7 @@
</objects>
<point key="canvasLocation" x="2154" y="-485"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="fMS-Gw-CfY">
<objects>
<navigationController id="RQg-o0-i6F" sceneMemberID="viewController">
<extendedEdge key="edgesForExtendedLayout"/>
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="fRT-Hm-h30">
<rect key="frame" x="0.0" y="24" width="420" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" name="PHWhiteIcon"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<toolbar key="toolbar" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="p4w-cm-yXR">
<rect key="frame" x="100" y="0.0" width="0.0" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</toolbar>
<connections>
<segue destination="DXe-Iw-CcD" kind="relationship" relationship="rootViewController" id="N2U-Wk-XGw"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="NPZ-9D-o3J" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="733" y="-1235"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="1o0-w2-ASY">
<objects>
<navigationController storyboardIdentifier="Editor" automaticallyAdjustsScrollViewInsets="NO" modalPresentationStyle="fullScreen" id="R1o-2G-Lxf" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" id="fUW-Ps-K5E"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Kus-pY-rHi">
<rect key="frame" x="0.0" y="0.0" width="1210" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.1176470588" green="0.1764705882" blue="0.26274509800000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="vXZ-lx-hvc" kind="relationship" relationship="rootViewController" id="WOe-49-Vig"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bF7-Sg-WkW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="703" y="-485"/>
</scene>
</scenes>
<inferredMetricsTieBreakers>
<segue reference="RCf-VZ-GG6"/>
</inferredMetricsTieBreakers>
<resources>
<image name="arrow.uturn.backward.circle" catalog="system" width="128" height="123"/>
<image name="arrow.uturn.forward.circle" catalog="system" width="128" height="123"/>
Expand Down
Loading
Loading