ObservedObjext

This commit is contained in:
Gerrit Linnemann 2020-10-04 14:19:53 +02:00
parent 226dd0593b
commit bead05837b
11 changed files with 209 additions and 49 deletions

View File

@ -15,6 +15,8 @@
EC13306F24DD687F008063CF /* YapsFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC13306E24DD687F008063CF /* YapsFile.swift */; };
EC13307124DDB3F4008063CF /* FinderHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC13307024DDB3F4008063CF /* FinderHelper.swift */; };
EC13307424DF2B2D008063CF /* YapsFileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC13307324DF2B2D008063CF /* YapsFileCell.swift */; };
EC62160025160F7100F285FC /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6215FF25160F7100F285FC /* Toolbar.swift */; };
EC6216062517CB8000F285FC /* ObservableArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6216052517CB8000F285FC /* ObservableArray.swift */; };
ECF5A75824E070710010A11D /* RawFileExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF5A75724E070710010A11D /* RawFileExtensions.swift */; };
ECF5A76024E41AAC0010A11D /* Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF5A75F24E41AAC0010A11D /* Shared.swift */; };
ECF5A76224E93C080010A11D /* MiscHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF5A76124E93C080010A11D /* MiscHelper.swift */; };
@ -32,6 +34,8 @@
EC13306E24DD687F008063CF /* YapsFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YapsFile.swift; sourceTree = "<group>"; };
EC13307024DDB3F4008063CF /* FinderHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinderHelper.swift; sourceTree = "<group>"; };
EC13307324DF2B2D008063CF /* YapsFileCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YapsFileCell.swift; sourceTree = "<group>"; };
EC6215FF25160F7100F285FC /* Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = "<group>"; };
EC6216052517CB8000F285FC /* ObservableArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableArray.swift; sourceTree = "<group>"; };
ECF5A75724E070710010A11D /* RawFileExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawFileExtensions.swift; sourceTree = "<group>"; };
ECF5A75F24E41AAC0010A11D /* Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shared.swift; sourceTree = "<group>"; };
ECF5A76124E93C080010A11D /* MiscHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiscHelper.swift; sourceTree = "<group>"; };
@ -79,6 +83,7 @@
EC13307024DDB3F4008063CF /* FinderHelper.swift */,
ECF5A75F24E41AAC0010A11D /* Shared.swift */,
ECF5A76124E93C080010A11D /* MiscHelper.swift */,
EC6215FF25160F7100F285FC /* Toolbar.swift */,
);
path = YAPS;
sourceTree = "<group>";
@ -95,6 +100,7 @@
isa = PBXGroup;
children = (
EC13306E24DD687F008063CF /* YapsFile.swift */,
EC6216052517CB8000F285FC /* ObservableArray.swift */,
);
path = Model;
sourceTree = "<group>";
@ -179,6 +185,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EC62160025160F7100F285FC /* Toolbar.swift in Sources */,
ECF5A76024E41AAC0010A11D /* Shared.swift in Sources */,
EC13305D24DAE92D008063CF /* ContentView.swift in Sources */,
EC13307124DDB3F4008063CF /* FinderHelper.swift in Sources */,
@ -186,6 +193,7 @@
EC13306F24DD687F008063CF /* YapsFile.swift in Sources */,
EC13307424DF2B2D008063CF /* YapsFileCell.swift in Sources */,
EC13305B24DAE92D008063CF /* AppDelegate.swift in Sources */,
EC6216062517CB8000F285FC /* ObservableArray.swift in Sources */,
ECF5A76224E93C080010A11D /* MiscHelper.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -12,6 +12,7 @@ import SwiftUI
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@ObservedObject var observedFileList: ObservableArray<YapsFile> = Shared.shared.fileList
var window: NSWindow!
@ -19,11 +20,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Toolbar **needs** a delegate
NSToolbar.yapsToolbar.delegate = self
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.toolbar = .yapsToolbar
window.center()
window.setFrameAutosaveName("YAPS Main Window")
window.contentView = NSHostingView(rootView: contentView)
@ -49,11 +54,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
*/
@IBAction func openFolder(_ sender: Any) {
if !Shared.shared.destinationDefined {
Shared.shared.destination = FinderHelper.shared.selectFolder(modalTitle: "Choose destination folder.")
Shared.shared.destinationDefined = true
}
FinderHelper.shared.iLikeThisImage(yapsFile: Shared.shared.currentFile, destination: Shared.shared.destination)
self.observedFileList.array.removeAll()
self.observedFileList.array.append(contentsOf: FinderHelper.shared.askForFolderAndGetFiles())
}
@IBAction func getIt(_ sender: Any) {
@ -76,3 +78,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
//scrollView.magnify(toFit: imageView.frame)
}
}
struct AppDelegate_Previews: PreviewProvider {
static var previews: some View {
/*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Image.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -9,12 +9,13 @@
import SwiftUI
struct ContentView: View {
@State var fileList = [YapsFile]()
@ObservedObject var observedFileList: ObservableArray<YapsFile> = Shared.shared.fileList
@State var previewImg = Image("placeholder-image")
var body: some View {
HStack {
VStack(alignment: .leading) {
/*
HStack {
Image.init("folder")
@ -31,9 +32,10 @@ struct ContentView: View {
Text("􀈕 Select Folder")
}
}
*/
List {
ForEach(self.fileList, id: \.self) { yapsFile in
List() {
ForEach(self.observedFileList.array, id: \.self) { yapsFile in
YapsFileCell(focused: self.checkCurrentFile(yapsFile: yapsFile), yapsFile: yapsFile)
.onTapGesture(perform: {
print("pressed \(yapsFile.name)")
@ -46,10 +48,12 @@ struct ContentView: View {
.focusable()
.onMoveCommand { (direction) in
var newIndex = Shared.shared.currentFile.index
print("\(direction)")
switch direction {
case MoveCommandDirection.down:
let max = self.fileList.count
let max = self.observedFileList.array.count
if (newIndex + 1) < max {
newIndex += 1
}
@ -61,7 +65,7 @@ struct ContentView: View {
newIndex += 0
}
self.setCurrentFile(newCurrent: self.fileList[newIndex], at: newIndex)
self.setCurrentFile(newCurrent: self.observedFileList.array[newIndex], at: newIndex)
}
}
.frame(width: 260.0)
@ -85,14 +89,14 @@ struct ContentView: View {
func setCurrentFile(newCurrent: YapsFile, at: Int) {
let currentFile = self.fileList[at]
let currentFile = self.observedFileList.array[at]
Shared.shared.currentFile = currentFile
self.resetCurrentFile()
self.fileList[at].current = true
self.observedFileList.array[at].isCurrent = true
self.previewImg = FinderHelper.shared.getImageByURL(source: self.fileList[at].file)
self.previewImg = FinderHelper.shared.getImageByURL(source: self.observedFileList.array[at].file)
}
func checkCurrentFile(yapsFile: YapsFile) -> Bool {
@ -104,8 +108,8 @@ struct ContentView: View {
}
func resetCurrentFile() {
for yapsFile in self.fileList {
self.fileList[yapsFile.index].current = false
for yapsFile in self.observedFileList.array {
self.observedFileList.array[yapsFile.index].isCurrent = false
}
}
}

View File

@ -53,7 +53,7 @@ class FinderHelper {
var index = 0
for item in items {
let yapsFile: YapsFile = YapsFile(index: -1, name: item.lastPathComponent, file: item, current: false)
let yapsFile: YapsFile = YapsFile(index: -1, name: item.lastPathComponent, file: item, isCurrent: false)
fileList.append(yapsFile)
index += 1
}
@ -61,6 +61,8 @@ class FinderHelper {
// failed to read directory bad permissions, perhaps?
}
print("Found \(fileList.count) file\(fileList.count != 1 ? "s" : "") to show")
return indexify(list: fileList.sorted {
let f01: YapsFile = $0
let f02: YapsFile = $1
@ -77,7 +79,7 @@ class FinderHelper {
var index = 0
for item in list {
let yapsFile: YapsFile = YapsFile(index: index, name: item.file.lastPathComponent, file: item.file, current: false)
let yapsFile: YapsFile = YapsFile(index: index, name: item.file.lastPathComponent, file: item.file, isCurrent: false)
indexifiedFileList.append(yapsFile)
index += 1
}

View File

@ -0,0 +1,33 @@
//
// ObservableArray.swift
// YAPS
//
// Created by Gerrit Linnemann on 20.09.20.
// Copyright © 2020 Adawim UG (haftungsbeschränkt). All rights reserved.
//
import Foundation
import Combine
import SwiftUI
class ObservableArray<T>: ObservableObject {
@Published var array:[T] = []
var cancellables = [AnyCancellable]()
init(array: [T]) {
self.array = array
}
func observeChildrenChanges<T: ObservableObject>() -> ObservableArray<T> {
let array2 = array as! [T]
array2.forEach({
let c = $0.objectWillChange.sink(receiveValue: { _ in self.objectWillChange.send() })
// Important: You have to keep the returned value allocated,
// otherwise the sink subscription gets cancelled
self.cancellables.append(c)
})
return self as! ObservableArray<T>
}
}

View File

@ -9,10 +9,18 @@
import Foundation
struct YapsFile: Identifiable, Hashable {
let id = UUID()
var index: Int
var name: String
var file: URL
var current: Bool
var isCurrent: Bool
init(index: Int, name: String, file: URL, isCurrent: Bool) {
self.index = index
self.name = name
self.file = file
self.isCurrent = isCurrent
}
}

View File

@ -12,11 +12,15 @@ import SwiftUI
class Shared: ObservableObject {
static let shared = Shared()
@Published var fileList = [YapsFile]()
@Published var currentFile: YapsFile = YapsFile(index: -1, name: "EMPTY", file: .init(fileURLWithPath: "Y"), current: false)
var fileList: ObservableArray<YapsFile>
var currentFile: YapsFile
var destination: URL
var destinationDefined: Bool
var destination: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
var destinationDefined: Bool = false
private init() { }
init() {
self.fileList = ObservableArray(array: [])
self.currentFile = YapsFile(index: -1, name: "EMPTY", file: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0], isCurrent: false)
self.destination = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
self.destinationDefined = false
}
}

View File

@ -11,8 +11,7 @@ import SwiftUI
struct YapsFileCell: View {
@State var focused: Bool
var yapsFile : YapsFile
@State var yapsFile : YapsFile
var body: some View {
Group {
@ -42,26 +41,3 @@ struct YapsFileCell: View {
}
}
}
struct YapsFileCell_Previews: PreviewProvider {
static var previews: some View {
Group {
VStack(alignment: .leading) {
// Dateiname
Text("dateiname.xyz")
.foregroundColor(.primary)
.multilineTextAlignment(.leading)
.lineLimit(1)
.aspectRatio(contentMode: .fill)
// Details
Text("xyz")
.font(.footnote)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
.lineLimit(1)
.aspectRatio(contentMode: .fill)
}
}
}
}

96
YAPS/YAPS/Toolbar.swift Normal file
View File

@ -0,0 +1,96 @@
//
// Toolbar.swift
// SUIToolbarPlay
//
// Created by Bill So on 4/23/20.
// Copyright © 2020 Bill So. All rights reserved.
//
import AppKit
extension NSImage.Name {
static let folder = "toolbar_folder"
}
extension NSToolbarItem.Identifier {
static let calendar = NSToolbarItem.Identifier(rawValue: "ShowCalendar")
static let today = NSToolbarItem.Identifier(rawValue: "GoToToday")
}
extension NSToolbar {
static let yapsToolbar: NSToolbar = {
let toolbar = NSToolbar(identifier: "YapsToolbar")
toolbar.displayMode = .iconOnly
return toolbar
}()
}
extension AppDelegate: NSToolbarDelegate {
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
[.today, .calendar]
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
[.today, .calendar]
}
@objc
func toolbarOpenSourceAction() {
self.observedFileList.array.removeAll()
self.observedFileList.array.append(contentsOf: FinderHelper.shared.askForFolderAndGetFiles())
}
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
switch itemIdentifier {
case NSToolbarItem.Identifier.calendar:
let button = NSButton(image: NSImage(named: .folder)!, target: nil, action: #selector(toolbarOpenSourceAction))
button.bezelStyle = .texturedRounded
return customToolbarItem(itemIdentifier: .calendar, label: "Open", paletteLabel: "Open", toolTip: "Open source folder", itemContent: button)
default:
return nil
}
}
/**
Mostly base on Apple sample code: https://developer.apple.com/documentation/appkit/touch_bar/integrating_a_toolbar_and_touch_bar_into_your_app
*/
func customToolbarItem(
itemIdentifier: NSToolbarItem.Identifier,
label: String,
paletteLabel: String,
toolTip: String,
itemContent: NSButton) -> NSToolbarItem? {
let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
toolbarItem.label = label
toolbarItem.paletteLabel = paletteLabel
toolbarItem.toolTip = toolTip
/**
You don't need to set a `target` if you know what you are doing.
In this example, AppDelegate is also the toolbar delegate.
Since AppDelegate is not a responder, implementing an IBAction in the AppDelegate class has no effect. Try using a subclass of NSWindow or NSWindowController to implement your action methods and use them as the toolbar delegate instead.
Ref: https://developer.apple.com/documentation/appkit/nstoolbaritem/1525982-target
From doc:
If target is nil, the toolbar will call action and attempt to invoke the action on the first responder and, failing that, pass the action up the responder chain.
*/
//toolbarItem.target = itemContent.target
//toolbarItem.action = itemContent.action
toolbarItem.view = itemContent
// We actually need an NSMenuItem here, so we construct one.
let menuItem: NSMenuItem = NSMenuItem()
menuItem.submenu = nil
menuItem.title = label
toolbarItem.menuFormRepresentation = menuItem
return toolbarItem
}
}