Skip to content
Open
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
32 changes: 16 additions & 16 deletions CBNote.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
Expand All @@ -531,7 +531,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.WidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand All @@ -555,7 +555,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = WidgetExtension/Info.plist;
Expand All @@ -567,7 +567,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.WidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -720,7 +720,7 @@
CODE_SIGN_ENTITLEMENTS = CBNote/CBNote.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
ENABLE_APP_SANDBOX = YES;
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
Expand Down Expand Up @@ -752,7 +752,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -780,7 +780,7 @@
CODE_SIGN_ENTITLEMENTS = CBNote/CBNote.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
ENABLE_APP_SANDBOX = YES;
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
Expand Down Expand Up @@ -812,7 +812,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand All @@ -835,7 +835,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = CaptureExtension/Info.plist;
Expand All @@ -848,7 +848,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
OTHER_SWIFT_FLAGS = "-D EXTENSION";
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.CaptureExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -870,7 +870,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = CaptureExtension/Info.plist;
Expand All @@ -883,7 +883,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
OTHER_SWIFT_FLAGS = "-D EXTENSION";
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.CaptureExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -907,7 +907,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -918,7 +918,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand All @@ -940,7 +940,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 54;
CURRENT_PROJECT_VERSION = 55;
DEVELOPMENT_TEAM = Z8R89S24YT;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -951,7 +951,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.6;
MARKETING_VERSION = 2.7;
PRODUCT_BUNDLE_IDENTIFIER = net.cizzuk.cbnote.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
Expand Down
6 changes: 5 additions & 1 deletion CBNote/AppIcons/AppIcon.icon/icon.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"features" : [
"specular-location"
],
"fill" : {
"solid" : "srgb:0.00000,0.00000,0.00000,1.00000"
},
Expand Down Expand Up @@ -42,7 +45,7 @@
"kind" : "neutral",
"opacity" : 0.5
},
"specular" : true,
"specular" : "inside",
"translucency" : {
"enabled" : true,
"value" : 0.2
Expand Down Expand Up @@ -71,6 +74,7 @@
"kind" : "neutral",
"opacity" : 0.5
},
"specular" : "inside",
"translucency" : {
"enabled" : true,
"value" : 0.25
Expand Down
5 changes: 4 additions & 1 deletion CBNote/AppIcons/Pride.icon/icon.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"features" : [
"specular-location"
],
"fill" : {
"solid" : "srgb:0.00000,0.00000,0.00000,1.00000"
},
Expand Down Expand Up @@ -26,7 +29,7 @@
"kind" : "neutral",
"opacity" : 0.5
},
"specular" : true,
"specular" : "inside",
"translucency" : {
"enabled" : true,
"value" : 0.25
Expand Down
5 changes: 4 additions & 1 deletion CBNote/AppIcons/Unity.icon/icon.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"features" : [
"specular-location"
],
"fill" : {
"solid" : "srgb:0.00000,0.00000,0.00000,1.00000"
},
Expand Down Expand Up @@ -26,7 +29,7 @@
"kind" : "neutral",
"opacity" : 0.5
},
"specular" : true,
"specular" : "inside",
"translucency" : {
"enabled" : true,
"value" : 0.25
Expand Down
Binary file modified CBNote/Assets.xcassets/AppIcon-pre.imageset/AppIcon-pre.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified CBNote/Assets.xcassets/Pride-pre.imageset/Pride-pre.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified CBNote/Assets.xcassets/Unity-pre.imageset/Unity-pre.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions CBNote/CBNoteApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct CBNoteApp: App {
// MARK: - Window Group
WindowGroup {
MainView()
.scrollDismissesKeyboard(.interactively)
#if targetEnvironment(macCatalyst)
.onAppear {
(UIApplication.shared.connectedScenes.first as? UIWindowScene)?
Expand Down
4 changes: 0 additions & 4 deletions CBNote/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>x-web-search</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand Down
20 changes: 13 additions & 7 deletions CBNote/Models/Helpers/TrueDevice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,19 @@ struct TrueDevice {
}

static let defaultSearchEngine: String = {
let defaultEngine: String
if let url = URL(string: "x-web-search://?test"),
UIApplication.shared.canOpenURL(url) {
defaultEngine = "x-web-search://?%s"
} else {
defaultEngine = "https://www.google.com/search?q=%s"
#if targetEnvironment(macCatalyst)
return false

#else
switch userInterfaceIdiom {
case .phone:
return "x-web-search://?%s"
case .pad:
return "x-web-search://?%s"
default:
return "https://duckduckgo.com/?q=%s"
}
return defaultEngine

#endif
}()
}
6 changes: 3 additions & 3 deletions CBNote/Models/Services/NoteService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ class NoteService: ObservableObject {
}
}

func saveCapturedImage(data: Data) -> URL? {
guard let fileURL = self.createFileURL(fileExtension: "jpeg") else { return nil }
func saveImage(data: Data, fileExtension: String = "jpeg") -> URL? {
guard let fileURL = self.createFileURL(fileExtension: fileExtension) else { return nil }
do {
try data.write(to: fileURL)
self.loadFiles()
Expand Down Expand Up @@ -258,7 +258,7 @@ class NoteService: ObservableObject {

for fileURL in fileURLs {
if let data = try? Data(contentsOf: fileURL) {
_ = self.saveCapturedImage(data: data)
_ = self.saveImage(data: data)
}
}

Expand Down
39 changes: 32 additions & 7 deletions CBNote/ViewModels/MainViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Combine
import LockedCameraCapture
import Photos
import PhotosUI
import SwiftUI
import Translation
import UniformTypeIdentifiers
Expand Down Expand Up @@ -277,12 +278,11 @@ class MainViewModel: ObservableObject {
func openInBrowser(at url: URL) {
guard let content = try? String(contentsOf: url, encoding: .utf8) else { return }

// If content is a valid URL, open directly
let trimmedContent = content.trimmingCharacters(in: .whitespacesAndNewlines)
// Check only one line
if !trimmedContent.contains("\n") {
// Check valid URL
if let linkURL = URL(string: trimmedContent), UIApplication.shared.canOpenURL(linkURL) {
// If content is a valid URL and has allowed scheme, open it directly
if let linkURL = URL(string: content.trimmingCharacters(in: .whitespacesAndNewlines)),
let scheme = linkURL.scheme?.lowercased() {
let allowedSchemes = ["http", "https", "x-web-search", "mailto", "tel", "sms"]
if allowedSchemes.contains(scheme) {
UIApplication.shared.open(linkURL)
return
}
Expand Down Expand Up @@ -328,7 +328,7 @@ class MainViewModel: ObservableObject {
// Handler for camera capture
func saveCapturedImage(data: Data, suppress: Bool = false) {
// Save as new note
guard let newImageURL = noteManager.saveCapturedImage(data: data) else {
guard let newImageURL = noteManager.saveImage(data: data) else {
if !suppress {
UINotificationFeedbackGenerator().notificationOccurred(.error)
}
Expand Down Expand Up @@ -381,6 +381,31 @@ class MainViewModel: ObservableObject {
}
}

// Hande PhotoPicker selection
func handlePhotoPickerSelection(_ item: PhotosPickerItem) {
item.loadTransferable(type: Data.self) { [weak self] result in
switch result {
case .success(let data):
let fileExtension = item.supportedContentTypes.first?.preferredFilenameExtension ?? ""
guard let imageData = data,
let newImageURL = self?.noteManager.saveImage(data: imageData, fileExtension: fileExtension)
else {
UINotificationFeedbackGenerator().notificationOccurred(.error)
return
}

UINotificationFeedbackGenerator().notificationOccurred(.success)
DispatchQueue.main.async {
self?.newFileURLToScroll = newImageURL
}

case .failure(let error):
print("PhotoPicker load error: ", error)
UINotificationFeedbackGenerator().notificationOccurred(.error)
}
}
}

// Handler for keyboard shortcuts
func handleKeyboardShortcut(shortcut: CustomKeyboardShortcut) {
switch shortcut {
Expand Down
1 change: 0 additions & 1 deletion CBNote/Views/MainView/MainView+FileList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ extension MainView {
// To reduce View jitter
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
.scrollDismissesKeyboard(.interactively)
.onChange(of: vm.unpinnedFiles) {
guard let scrollPos = vm.newFileURLToScroll else { return }
DispatchQueue.main.async {
Expand Down
5 changes: 5 additions & 0 deletions CBNote/Views/MainView/MainView+Toolbar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Cizzuk on 2026/02/11.
//

import PhotosUI
import SwiftUI

extension MainView {
Expand Down Expand Up @@ -44,6 +45,10 @@ extension MainView {
Button(action: { showFileImporter = true }) {
Label("Import from Files", systemImage: "document")
}

PhotosPicker(selection: $selectedPhoto) {
Label("Import from Photos", systemImage: "photo")
}
}

// MARK: - Top Left
Expand Down
8 changes: 8 additions & 0 deletions CBNote/Views/MainView/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import QuickLook
import PhotosUI
import SwiftUI
import Translation
import TemporaryScreenCurtain
Expand All @@ -19,6 +20,7 @@ struct MainView: View {
@State var previewURL: URL?
@State var isExpandPinnedSection = true
@State var showFileImporter = false
@State var selectedPhoto: PhotosPickerItem? = nil

var imagePreviewMode: ImagePreviewMode { userSettings.imagePreviewMode }
var enableNoteListAnimations: Bool { userSettings.enableNoteListAnimations }
Expand Down Expand Up @@ -75,6 +77,12 @@ struct MainView: View {
// MARK: - Events
.onAppear { vm.onAppear() }
.onChange(of: scenePhase) { vm.onChange(scenePhase: scenePhase) }
.onChange(of: selectedPhoto) {
if let selectedPhoto {
vm.handlePhotoPickerSelection(selectedPhoto)
}
selectedPhoto = nil
}
// Opening from Camera Control
.onReceive(NotificationCenter.default.publisher(for: .cameraControlDidActivate)) { _ in
vm.handleCameraControlAction()
Expand Down
Loading