mirror of
https://github.com/writeas/writefreely-swiftui-multiplatform.git
synced 2024-11-15 01:11:02 +00:00
Fix merge conflict in Shared/PostList/PostListView
This commit is contained in:
commit
5557566657
23
Shared/Assets.xcassets/does.not.exist.imageset/Contents.json
vendored
Normal file
23
Shared/Assets.xcassets/does.not.exist.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "does.not.exist.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "does.not.exist@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "does.not.exist@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist.png
vendored
Normal file
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 501 B |
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist@2x.png
vendored
Normal file
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 501 B |
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist@3x.png
vendored
Normal file
BIN
Shared/Assets.xcassets/does.not.exist.imageset/does.not.exist@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 502 B |
@ -29,6 +29,7 @@ class WriteFreelyModel: ObservableObject {
|
||||
// swiftlint:disable line_length
|
||||
let helpURL = URL(string: "https://discuss.write.as/c/help/5")!
|
||||
let howToURL = URL(string: "https://discuss.write.as/t/using-the-writefreely-ios-app/1946")!
|
||||
let reviewURL = URL(string: "https://apps.apple.com/app/id1531530896?action=write-review")!
|
||||
let licensesURL = URL(string: "https://github.com/writeas/writefreely-swiftui-multiplatform/tree/main/Shared/Resources/Licenses")!
|
||||
// swiftlint:enable line_length
|
||||
|
||||
|
@ -20,6 +20,8 @@ struct PostEditorStatusToolbarView: View {
|
||||
}, label: {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
})
|
||||
.accessibilityLabel(Text("Update post"))
|
||||
.accessibilityHint(Text("Replace this post with the server version"))
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.background(Color.primary.opacity(0.1))
|
||||
@ -45,6 +47,8 @@ struct PostEditorStatusToolbarView: View {
|
||||
}, label: {
|
||||
Image(systemName: "trash")
|
||||
})
|
||||
.accessibilityLabel(Text("Delete"))
|
||||
.accessibilityHint(Text("Delete this post from your Mac"))
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.background(Color.primary.opacity(0.1))
|
||||
|
@ -29,33 +29,51 @@ struct PostListView: View {
|
||||
)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(action: {
|
||||
let managedPost = WFAPost(context: self.managedObjectContext)
|
||||
managedPost.createdDate = Date()
|
||||
managedPost.title = ""
|
||||
managedPost.body = ""
|
||||
managedPost.status = PostStatus.local.rawValue
|
||||
managedPost.collectionAlias = nil
|
||||
switch model.preferences.font {
|
||||
case 1:
|
||||
managedPost.appearance = "sans"
|
||||
case 2:
|
||||
managedPost.appearance = "wrap"
|
||||
default:
|
||||
managedPost.appearance = "serif"
|
||||
}
|
||||
if let languageCode = Locale.current.languageCode {
|
||||
managedPost.language = languageCode
|
||||
managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft
|
||||
}
|
||||
withAnimation {
|
||||
self.selectedCollection = nil
|
||||
self.showAllPosts = false
|
||||
self.model.selectedPost = managedPost
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "square.and.pencil")
|
||||
})
|
||||
// We have to add a Spacer as a sibling view to the Button in some kind of Stack, so that any
|
||||
// a11y modifiers are applied as expected: bug report filed as FB8956392.
|
||||
ZStack {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
let managedPost = WFAPost(context: self.managedObjectContext)
|
||||
managedPost.createdDate = Date()
|
||||
managedPost.title = ""
|
||||
managedPost.body = ""
|
||||
managedPost.status = PostStatus.local.rawValue
|
||||
managedPost.collectionAlias = nil
|
||||
switch model.preferences.font {
|
||||
case 1:
|
||||
managedPost.appearance = "sans"
|
||||
case 2:
|
||||
managedPost.appearance = "wrap"
|
||||
default:
|
||||
managedPost.appearance = "serif"
|
||||
}
|
||||
if let languageCode = Locale.current.languageCode {
|
||||
managedPost.language = languageCode
|
||||
//swiftlint:disable:next line_length
|
||||
managedPost.rtl = Locale.characterDirection(forLanguage: languageCode) == .rightToLeft
|
||||
}
|
||||
withAnimation {
|
||||
self.selectedCollection = nil
|
||||
self.showAllPosts = false
|
||||
self.model.selectedPost = managedPost
|
||||
}
|
||||
}, label: {
|
||||
ZStack {
|
||||
Image("does.not.exist")
|
||||
.accessibilityHidden(true)
|
||||
Image(systemName: "square.and.pencil")
|
||||
.accessibilityHidden(true)
|
||||
.imageScale(.large) // These modifiers compensate for the resizing
|
||||
.padding(.vertical, 12) // done to the Image (and the button tap target)
|
||||
.padding(.leading, 12) // by the SwiftUI layout system from adding a
|
||||
.padding(.trailing, 8) // Spacer in this ZStack (FB8956392).
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
})
|
||||
.accessibilityLabel(Text("Compose"))
|
||||
.accessibilityHint(Text("Compose a new local draft"))
|
||||
}
|
||||
}
|
||||
}
|
||||
VStack {
|
||||
@ -65,6 +83,8 @@ struct PostListView: View {
|
||||
}, label: {
|
||||
Image(systemName: "gear")
|
||||
})
|
||||
.accessibilityLabel(Text("Settings"))
|
||||
.accessibilityHint(Text("Open the Settings sheet"))
|
||||
Spacer()
|
||||
Text(postCount == 1 ? "\(postCount) post" : "\(postCount) posts")
|
||||
.foregroundColor(.secondary)
|
||||
@ -80,6 +100,8 @@ struct PostListView: View {
|
||||
}, label: {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
})
|
||||
.accessibilityLabel(Text("Refresh Posts"))
|
||||
.accessibilityHint(Text("Fetch changes from the server"))
|
||||
.disabled(!model.account.isLoggedIn)
|
||||
}
|
||||
}
|
||||
|
61
Shared/Resources/Licenses/Sparkle-License.txt
Normal file
61
Shared/Resources/Licenses/Sparkle-License.txt
Normal file
@ -0,0 +1,61 @@
|
||||
Copyright (c) 2006-2013 Andy Matuschak.
|
||||
Copyright (c) 2009-2013 Elgato Systems GmbH.
|
||||
Copyright (c) 2011-2014 Kornel Lesiński.
|
||||
Copyright (c) 2015-2017 Mayur Pawashe.
|
||||
Copyright (c) 2014 C.W. Betts.
|
||||
Copyright (c) 2014 Petroules Corporation.
|
||||
Copyright (c) 2014 Big Nerd Ranch.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
=================
|
||||
EXTERNAL LICENSES
|
||||
=================
|
||||
|
||||
bspatch.c and bsdiff.c, from bsdiff 4.3 <http://www.daemonology.net/bsdiff/>:
|
||||
Copyright (c) 2003-2005 Colin Percival.
|
||||
|
||||
sais.c and sais.c, from sais-lite (2010/08/07) <https://sites.google.com/site/yuta256/sais>:
|
||||
Copyright (c) 2008-2010 Yuta Mori.
|
||||
|
||||
SUDSAVerifier.m:
|
||||
Copyright (c) 2011 Mark Hamlin.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted providing that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
@ -1,5 +1,9 @@
|
||||
import SwiftUI
|
||||
|
||||
#if os(macOS)
|
||||
import Sparkle
|
||||
#endif
|
||||
|
||||
@main
|
||||
struct CheckForDebugModifier {
|
||||
static func main() {
|
||||
@ -20,6 +24,8 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
@StateObject private var model = WriteFreelyModel()
|
||||
|
||||
#if os(macOS)
|
||||
// swiftlint:disable:next weak_delegate
|
||||
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
|
||||
@State private var selectedTab = 0
|
||||
#endif
|
||||
|
||||
@ -38,6 +44,13 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
|
||||
}
|
||||
.commands {
|
||||
#if os(macOS)
|
||||
CommandGroup(after: .appInfo, addition: {
|
||||
Button("Check For Updates") {
|
||||
SUUpdater.shared()?.checkForUpdates(self)
|
||||
}
|
||||
})
|
||||
#endif
|
||||
CommandGroup(replacing: .newItem, addition: {
|
||||
Button("New Post") {
|
||||
createNewLocalPost()
|
||||
@ -85,8 +98,14 @@ struct WriteFreely_MultiPlatformApp: App {
|
||||
Text("Preferences")
|
||||
}
|
||||
.tag(1)
|
||||
MacUpdatesView()
|
||||
.tabItem {
|
||||
Image(systemName: "arrow.down.circle")
|
||||
Text("Updates")
|
||||
}
|
||||
.tag(2)
|
||||
}
|
||||
.frame(minWidth: 300, maxWidth: 300, minHeight: 200, maxHeight: 200)
|
||||
.frame(minWidth: 500, maxWidth: 500, minHeight: 200)
|
||||
.padding()
|
||||
// .preferredColorScheme(preferences.selectedColorScheme) // See PreferencesModel for info.
|
||||
}
|
||||
|
66
Technotes/MacSoftwareUpdater.md
Normal file
66
Technotes/MacSoftwareUpdater.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Mac Software Updater
|
||||
|
||||
To make updating the Mac app easy, we're using the [Sparkle framework][1].
|
||||
|
||||
This is added to the project via the Swift Package Manager (SPM), but at the time of writing, tagged versions of Sparkle do not yet support
|
||||
SPM — the dependency can only be added from a branch or commit. To avoid any surprises arising from updates to the project's `master`
|
||||
branch, we're using [WriteFreely's fork of Sparkle][2]. Updates to the forked repository from upstream should be considered dangerous and
|
||||
tested thoroughly before merging into `main`.
|
||||
|
||||
WriteFreely for Mac uses the v1.x branch of Sparkle, and is therefore not a sandboxed app.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### If Xcode throws an error when you try to build the project
|
||||
|
||||
You may need to reset the package caches:
|
||||
|
||||
1. From the **File** menu in Xcode, choose **Swift Packages** → **Reset Package Caches**
|
||||
2. Again from the **File** menu, choose **Swift Packages** → **Update to Latest Package Versions**
|
||||
|
||||
You should then be able to build and run the Mac target.
|
||||
|
||||
### If you can't run `generate_keys` because "Apple cannot check it for malicious software"
|
||||
|
||||
There may be a code signing issue with Sparkle. Right-click on `generate_keys` in the Finder and choose Open ([reference][3]).
|
||||
|
||||
## Deploying Updates
|
||||
|
||||
To [publish an update to the app][5], you'll need the **Sparkle-for-Swift-Package-Manager.zip** [archive][4] — specifically, you'll need the
|
||||
`generate_appcast` tool. Download and de-compress the archive.
|
||||
|
||||
You will need some credentials and signing certificates to proceed with this process; speak to the project maintainer if you're responsible for
|
||||
creating the update, and confirm you have:
|
||||
|
||||
- the app's Developer ID Application certificate (check your Mac's system Keychain)
|
||||
- the Sparkle EdDSA signing key (again, check your Mac's system Keychain)
|
||||
|
||||
Sign and notarize the app archive, then click on **Export Notarized App** in Xcode's Organizer window. Open the Terminal and navigate to
|
||||
where you de-compressed the Sparkle-for-Swift-Package-Manager archive, then create a zip file that preserves symlinks:
|
||||
|
||||
```bash
|
||||
% ditto -c -k --sequesterRsrc --keepParent <source_path_to_app> <zip_destination>
|
||||
```
|
||||
|
||||
For example, if you export the notarized app to the desktop, all prior updates are located in `~/Developer/WriteFreely/Updates`, and
|
||||
the final archive should be called `WFMac.zip`, you would run:
|
||||
|
||||
```bash
|
||||
% ditto -c -k --sequesterRsrc --keepParent ~/Desktop/WriteFreely\ for\ Mac.app ~/Developer/WriteFreely/Updates/WFMac.zip
|
||||
```
|
||||
|
||||
Then, generate an appcast file:
|
||||
|
||||
```bash
|
||||
% ./bin/generate_appcast ~/Developer/WriteFreely/Updates
|
||||
```
|
||||
|
||||
Once that's done, upload the appcast.xml and WFMac.zip files to the update distribution server (`files.writefreely.org/apps/mac`)
|
||||
and they'll be made available to users.
|
||||
|
||||
<!--references-->
|
||||
[1]: https://sparkle-project.org
|
||||
[2]: https://github.com/writefreely/Sparkle
|
||||
[3]: https://github.com/sparkle-project/Sparkle/issues/1701#issuecomment-752249920
|
||||
[4]: https://github.com/sparkle-project/Sparkle/releases/tag/1.24.0
|
||||
[5]: https://sparkle-project.org/documentation/publishing/
|
@ -20,6 +20,7 @@
|
||||
17120DB224E1E19C002B9F6C /* SettingsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */; };
|
||||
171BFDFA24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; };
|
||||
171BFDFB24D4AF8300888236 /* CollectionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171BFDF924D4AF8300888236 /* CollectionListView.swift */; };
|
||||
172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172C492D2593981900E20ADF /* MacUpdatesView.swift */; };
|
||||
173E19D1254318F600440F0F /* RemoteChangePromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19D0254318F600440F0F /* RemoteChangePromptView.swift */; };
|
||||
173E19E3254329CC00440F0F /* PostTextEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173E19E2254329CC00440F0F /* PostTextEditingView.swift */; };
|
||||
17466626256C0D0600629997 /* MacEditorTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17466625256C0D0600629997 /* MacEditorTextView.swift */; };
|
||||
@ -51,6 +52,8 @@
|
||||
1765F62B24E18EA200C9EBF0 /* SidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1765F62924E18EA200C9EBF0 /* SidebarView.swift */; };
|
||||
17681E412519410E00D394AE /* UINavigationController+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17681E402519410E00D394AE /* UINavigationController+Appearance.swift */; };
|
||||
1780F6EF25895EDB00FE45FF /* PostCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1780F6EE25895EDB00FE45FF /* PostCommands.swift */; };
|
||||
17A4FEDA25924AF70037E96B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 17A4FED925924AF70037E96B /* Sparkle */; };
|
||||
17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A4FEEC25927E730037E96B /* AppDelegate.swift */; };
|
||||
17A5388824DDA31F00DEFF9A /* MacAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388724DDA31F00DEFF9A /* MacAccountView.swift */; };
|
||||
17A5388C24DDC83F00DEFF9A /* AccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388B24DDC83F00DEFF9A /* AccountModel.swift */; };
|
||||
17A5388F24DDEC7400DEFF9A /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A5388D24DDEC7400DEFF9A /* AccountView.swift */; };
|
||||
@ -125,6 +128,7 @@
|
||||
17120DAB24E1B99F002B9F6C /* AccountLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginView.swift; sourceTree = "<group>"; };
|
||||
17120DB124E1E19C002B9F6C /* SettingsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeaderView.swift; sourceTree = "<group>"; };
|
||||
171BFDF924D4AF8300888236 /* CollectionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionListView.swift; sourceTree = "<group>"; };
|
||||
172C492D2593981900E20ADF /* MacUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacUpdatesView.swift; sourceTree = "<group>"; };
|
||||
173E19D0254318F600440F0F /* RemoteChangePromptView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteChangePromptView.swift; sourceTree = "<group>"; };
|
||||
173E19E2254329CC00440F0F /* PostTextEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostTextEditingView.swift; sourceTree = "<group>"; };
|
||||
17466625256C0D0600629997 /* MacEditorTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacEditorTextView.swift; sourceTree = "<group>"; };
|
||||
@ -145,6 +149,8 @@
|
||||
1765F62924E18EA200C9EBF0 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = "<group>"; };
|
||||
17681E402519410E00D394AE /* UINavigationController+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Appearance.swift"; sourceTree = "<group>"; };
|
||||
1780F6EE25895EDB00FE45FF /* PostCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCommands.swift; sourceTree = "<group>"; };
|
||||
17A4FEDF25924E810037E96B /* MacSoftwareUpdater.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = MacSoftwareUpdater.md; sourceTree = "<group>"; };
|
||||
17A4FEEC25927E730037E96B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
17A5388724DDA31F00DEFF9A /* MacAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacAccountView.swift; sourceTree = "<group>"; };
|
||||
17A5388B24DDC83F00DEFF9A /* AccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountModel.swift; sourceTree = "<group>"; };
|
||||
17A5388D24DDEC7400DEFF9A /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
|
||||
@ -154,6 +160,7 @@
|
||||
17AD0A6325489E900057D763 /* PostBodyTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostBodyTextView.swift; sourceTree = "<group>"; };
|
||||
17B3E964250FAA9000EE9748 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
17B5103A2515448D00E9631F /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
|
||||
17B68D4F25A4FED2005ED37C /* Sparkle-License.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Sparkle-License.txt"; sourceTree = "<group>"; };
|
||||
17B996D62502D23E0017B536 /* WFAPost+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataClass.swift"; sourceTree = SOURCE_ROOT; };
|
||||
17B996D72502D23E0017B536 /* WFAPost+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WFAPost+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
|
||||
17BC617825715068003363CA /* ActivePostToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivePostToolbarView.swift; sourceTree = "<group>"; };
|
||||
@ -204,6 +211,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17DF32C324C87D8D00BCE2E3 /* WriteFreely in Frameworks */,
|
||||
17A4FEDA25924AF70037E96B /* Sparkle in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -228,6 +236,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1709ADDF251B9A110053AF79 /* EditorLaunchingPolicy.md */,
|
||||
17A4FEDF25924E810037E96B /* MacSoftwareUpdater.md */,
|
||||
);
|
||||
path = Technotes;
|
||||
sourceTree = "<group>";
|
||||
@ -296,6 +305,7 @@
|
||||
children = (
|
||||
17A5388724DDA31F00DEFF9A /* MacAccountView.swift */,
|
||||
1753F6AB24E431CC00309365 /* MacPreferencesView.swift */,
|
||||
172C492D2593981900E20ADF /* MacUpdatesView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@ -409,6 +419,7 @@
|
||||
children = (
|
||||
17DF329224C87D3500BCE2E3 /* Info.plist */,
|
||||
17DF329324C87D3500BCE2E3 /* macOS.entitlements */,
|
||||
17A4FEEC25927E730037E96B /* AppDelegate.swift */,
|
||||
17BC617725715042003363CA /* Navigation */,
|
||||
17A67CAC251A5D8D002F163D /* PostEditor */,
|
||||
17A5388924DDA50500DEFF9A /* Settings */,
|
||||
@ -485,6 +496,7 @@
|
||||
17DFDE83251D309400A25F31 /* Licenses */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17B68D4F25A4FED2005ED37C /* Sparkle-License.txt */,
|
||||
17DFDE84251D309400A25F31 /* Hack-License.txt */,
|
||||
17DFDE85251D309400A25F31 /* Lora-Cyrillic-OFL.txt */,
|
||||
17DFDE86251D309400A25F31 /* OpenSans-License.txt */,
|
||||
@ -532,6 +544,7 @@
|
||||
name = "WriteFreely-MultiPlatform (macOS)";
|
||||
packageProductDependencies = (
|
||||
17DF32C224C87D8D00BCE2E3 /* WriteFreely */,
|
||||
17A4FED925924AF70037E96B /* Sparkle */,
|
||||
);
|
||||
productName = "WriteFreely-MultiPlatform (macOS)";
|
||||
productReference = 17DF329024C87D3500BCE2E3 /* WriteFreely for Mac.app */;
|
||||
@ -609,6 +622,7 @@
|
||||
mainGroup = 17DF327B24C87D3300BCE2E3;
|
||||
packageReferences = (
|
||||
17DF32BE24C87D7B00BCE2E3 /* XCRemoteSwiftPackageReference "writefreely-swift" */,
|
||||
17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */,
|
||||
);
|
||||
productRefGroup = 17DF328924C87D3500BCE2E3 /* Products */;
|
||||
projectDirPath = "";
|
||||
@ -757,10 +771,12 @@
|
||||
17DF32AD24C87D3500BCE2E3 /* ContentView.swift in Sources */,
|
||||
1765F62B24E18EA200C9EBF0 /* SidebarView.swift in Sources */,
|
||||
1756DBBB24FED45500207AB8 /* LocalStorageManager.swift in Sources */,
|
||||
17A4FEED25927E730037E96B /* AppDelegate.swift in Sources */,
|
||||
174D313324EC2831006CA9EE /* WriteFreelyModel.swift in Sources */,
|
||||
17D435E924E3128F0036B539 /* PreferencesModel.swift in Sources */,
|
||||
17120DAA24E1B2F5002B9F6C /* AccountLogoutView.swift in Sources */,
|
||||
17DF32D624C8CA3400BCE2E3 /* PostStatusBadgeView.swift in Sources */,
|
||||
172C492E2593981900E20ADF /* MacUpdatesView.swift in Sources */,
|
||||
17479F152583D8E40072B7FB /* PostEditorSharingPicker.swift in Sources */,
|
||||
17480CA6251272EE00EB7765 /* Bundle+AppVersion.swift in Sources */,
|
||||
17C42E662509237800072984 /* PostListFilteredView.swift in Sources */,
|
||||
@ -992,7 +1008,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 514;
|
||||
CURRENT_PROJECT_VERSION = 532;
|
||||
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@ -1002,7 +1018,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.0b1;
|
||||
MARKETING_VERSION = 0.1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
||||
PRODUCT_NAME = "WriteFreely for Mac";
|
||||
SDKROOT = macosx;
|
||||
@ -1018,7 +1034,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 514;
|
||||
CURRENT_PROJECT_VERSION = 532;
|
||||
DEVELOPMENT_TEAM = TPPAB4YBA6;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@ -1028,7 +1044,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 1.0b1;
|
||||
MARKETING_VERSION = 0.1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abunchtell.WriteFreely-MultiPlatform";
|
||||
PRODUCT_NAME = "WriteFreely for Mac";
|
||||
SDKROOT = macosx;
|
||||
@ -1176,6 +1192,14 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/writefreely/Sparkle";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
17DF32BE24C87D7B00BCE2E3 /* XCRemoteSwiftPackageReference "writefreely-swift" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "git@github.com:writeas/writefreely-swift.git";
|
||||
@ -1187,6 +1211,11 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
17A4FED925924AF70037E96B /* Sparkle */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 17A4FED825924AF70037E96B /* XCRemoteSwiftPackageReference "Sparkle" */;
|
||||
productName = Sparkle;
|
||||
};
|
||||
17DF32BF24C87D7B00BCE2E3 /* WriteFreely */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 17DF32BE24C87D7B00BCE2E3 /* XCRemoteSwiftPackageReference "writefreely-swift" */;
|
||||
|
@ -7,12 +7,12 @@
|
||||
<key>WriteFreely-MultiPlatform (iOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>WriteFreely-MultiPlatform (macOS).xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
@ -80,6 +80,8 @@ struct PostEditorView: View {
|
||||
}, label: {
|
||||
Label("Publish…", systemImage: "paperplane")
|
||||
})
|
||||
.accessibilityHint(Text("Choose the blog you want to publish this post to"))
|
||||
.disabled(post.body.count == 0)
|
||||
} else {
|
||||
Button(action: {
|
||||
if model.account.isLoggedIn {
|
||||
@ -97,6 +99,7 @@ struct PostEditorView: View {
|
||||
}, label: {
|
||||
Label("Share", systemImage: "square.and.arrow.up")
|
||||
})
|
||||
.accessibilityHint(Text("Open the system share sheet to share a link to this post"))
|
||||
.disabled(post.postId == nil)
|
||||
// Button(action: {
|
||||
// print("Tapped 'Delete...' button")
|
||||
@ -117,8 +120,20 @@ struct PostEditorView: View {
|
||||
}
|
||||
}
|
||||
}, label: {
|
||||
Image(systemName: "ellipsis.circle")
|
||||
ZStack {
|
||||
Image("does.not.exist")
|
||||
.accessibilityHidden(true)
|
||||
Image(systemName: "ellipsis.circle")
|
||||
.imageScale(.large)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
})
|
||||
.accessibilityLabel(Text("Menu"))
|
||||
.accessibilityHint(Text("Opens a context menu to publish, share, or move the post"))
|
||||
.onTapGesture {
|
||||
hideKeyboard()
|
||||
}
|
||||
.disabled(post.body.count == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ struct PostTextEditingView: View {
|
||||
.foregroundColor(Color(UIColor.placeholderText))
|
||||
.padding(.horizontal, 4)
|
||||
.padding(.vertical, 8)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
PostTitleTextView(
|
||||
text: $post.title,
|
||||
@ -49,6 +50,8 @@ struct PostTextEditingView: View {
|
||||
isFirstResponder: $titleIsFirstResponder,
|
||||
lineSpacing: horizontalSizeClass == .compact ? lineSpacingMultiplier / 2 : lineSpacingMultiplier
|
||||
)
|
||||
.accessibilityLabel(Text("Title (optional)"))
|
||||
.accessibilityHint(Text("Add or edit the title for your post; use the Return key to skip to the body"))
|
||||
.frame(height: titleFieldHeight)
|
||||
.onChange(of: post.title) { _ in
|
||||
if post.status == PostStatus.published.rawValue && !updatingTitleFromServer {
|
||||
@ -66,6 +69,7 @@ struct PostTextEditingView: View {
|
||||
.foregroundColor(Color(UIColor.placeholderText))
|
||||
.padding(.horizontal, 4)
|
||||
.padding(.vertical, 8)
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
PostBodyTextView(
|
||||
text: $post.body,
|
||||
@ -73,6 +77,8 @@ struct PostTextEditingView: View {
|
||||
isFirstResponder: $bodyIsFirstResponder,
|
||||
lineSpacing: horizontalSizeClass == .compact ? lineSpacingMultiplier / 2 : lineSpacingMultiplier
|
||||
)
|
||||
.accessibilityLabel(Text("Body"))
|
||||
.accessibilityHint(Text("Add or edit the body of your post"))
|
||||
.onChange(of: post.body) { _ in
|
||||
if post.status == PostStatus.published.rawValue && !updatingBodyFromServer {
|
||||
post.status = PostStatus.edited.rawValue
|
||||
|
@ -9,6 +9,8 @@ struct RemoteChangePromptView: View {
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
@State private var promptText: String = "This is placeholder prompt text. Replace it?"
|
||||
@State private var promptIcon: Image = Image(systemName: "questionmark.square.dashed")
|
||||
@State private var accessibilityLabel: String = "Replace"
|
||||
@State private var accessibilityHint: String = "Replace this text with an accessibility hint"
|
||||
@State var remoteChangeType: RemotePostChangeType
|
||||
@State var buttonHandler: () -> Void
|
||||
|
||||
@ -18,6 +20,8 @@ struct RemoteChangePromptView: View {
|
||||
.font(horizontalSizeClass == .compact ? .caption : .body)
|
||||
.foregroundColor(.secondary)
|
||||
Button(action: buttonHandler, label: { promptIcon })
|
||||
.accessibilityLabel(Text(accessibilityLabel))
|
||||
.accessibilityHint(Text(accessibilityHint))
|
||||
}
|
||||
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
|
||||
.background(Color(UIColor.secondarySystemBackground))
|
||||
@ -28,9 +32,13 @@ struct RemoteChangePromptView: View {
|
||||
case .remoteCopyUpdated:
|
||||
promptText = "Newer copy on server. Replace local copy?"
|
||||
promptIcon = Image(systemName: "square.and.arrow.down")
|
||||
accessibilityLabel = "Update post"
|
||||
accessibilityHint = "Replace this post with the server version"
|
||||
case .remoteCopyDeleted:
|
||||
promptText = "Post deleted from server. Delete local copy?"
|
||||
promptIcon = Image(systemName: "trash")
|
||||
accessibilityLabel = "Delete"
|
||||
accessibilityHint = "Delete this post from your device"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ struct SettingsHeaderView: View {
|
||||
}, label: {
|
||||
Image(systemName: "xmark.circle")
|
||||
})
|
||||
.accessibilityLabel(Text("Close"))
|
||||
.accessibilityHint(Text("Dismiss the Settings sheet"))
|
||||
}
|
||||
Text("WriteFreely v\(Bundle.main.appMarketingVersion) (build \(Bundle.main.appBuildVersion))")
|
||||
.font(.caption)
|
||||
|
@ -13,7 +13,7 @@ struct SettingsView: View {
|
||||
Section(header: Text("Appearance")) {
|
||||
PreferencesView(preferences: model.preferences)
|
||||
}
|
||||
Section(header: Text("Support Links")) {
|
||||
Section(header: Text("External Links")) {
|
||||
HStack {
|
||||
Spacer()
|
||||
Link("View the Guide", destination: model.howToURL)
|
||||
@ -24,6 +24,11 @@ struct SettingsView: View {
|
||||
Link("Visit the Help Forum", destination: model.helpURL)
|
||||
Spacer()
|
||||
}
|
||||
HStack {
|
||||
Spacer()
|
||||
Link("Write a Review on the App Store", destination: model.reviewURL)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
Section(header: Text("Acknowledgements")) {
|
||||
VStack {
|
||||
|
24
macOS/AppDelegate.swift
Normal file
24
macOS/AppDelegate.swift
Normal file
@ -0,0 +1,24 @@
|
||||
import Cocoa
|
||||
import Sparkle
|
||||
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
func applicationWillFinishLaunching(_ notification: Notification) {
|
||||
// Check UserDefaults for values; if the key doesn't exist (e.g., if MacUpdatesView hasn't ever been shown),
|
||||
// bool(forKey:) returns false, so set SUUpdater.shared() appropriately.
|
||||
let automaticallyChecksForUpdates = UserDefaults.standard.bool(forKey: "automaticallyChecksForUpdates")
|
||||
let subscribeToBetaUpdates = UserDefaults.standard.bool(forKey: "subscribeToBetaUpdates")
|
||||
|
||||
// Set Sparkle properties.
|
||||
SUUpdater.shared()?.automaticallyChecksForUpdates = automaticallyChecksForUpdates
|
||||
if subscribeToBetaUpdates {
|
||||
SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.beta.rawValue)
|
||||
} else {
|
||||
SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.release.rawValue)
|
||||
}
|
||||
|
||||
// If enabled, check for updates.
|
||||
if automaticallyChecksForUpdates {
|
||||
SUUpdater.shared()?.checkForUpdates(self)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,24 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2578
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 SFProDisplay-Regular;}
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 SFProDisplay-Bold;\f1\fnil\fcharset0 SFProDisplay-Regular;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;}
|
||||
{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}}
|
||||
{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}}
|
||||
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
|
||||
|
||||
\f0\fs26 \cf0 This application makes use of the following open-source projects:\
|
||||
\f0\b\fs26 \cf0 \
|
||||
PRE-RELEASE SOFTWARE
|
||||
\f1\b0 \
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
|
||||
\cf0 \
|
||||
WriteFreely for Mac makes use of the following open-source projects:\
|
||||
\
|
||||
\pard\tx220\tx720\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li720\fi-720\pardirnatural\partightenfactor0
|
||||
\ls1\ilvl0\cf0 {\listtext \uc0\u8226 }Lora typeface\
|
||||
{\listtext \uc0\u8226 }Open Sans typeface\
|
||||
{\listtext \uc0\u8226 }Hack typeface\
|
||||
\ls1\ilvl0\cf0 {\listtext \uc0\u8226 }Lora ({\field{\*\fldinst{HYPERLINK "https://github.com/cyrealtype/Lora-Cyrillic"}}{\fldrslt typeface}})\
|
||||
{\listtext \uc0\u8226 }Open Sans ({\field{\*\fldinst{HYPERLINK "https://fonts.google.com/specimen/Open+Sans"}}{\fldrslt typeface}})\
|
||||
{\listtext \uc0\u8226 }Hack ({\field{\*\fldinst{HYPERLINK "https://sourcefoundry.org/hack/"}}{\fldrslt typeface}})\
|
||||
{\listtext \uc0\u8226 }Sparkle ({\field{\*\fldinst{HYPERLINK "https://sparkle-project.org"}}{\fldrslt framework}})\
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
|
||||
\cf0 \
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
|
||||
|
@ -28,5 +28,9 @@
|
||||
<string>public.app-category.social-networking</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://writefreely-files.s3.amazonaws.com/apps/mac/appcast.xml</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>xLenuurDaQb2/dj2ScylLmJx0gSnBmacUsOAgUjErUc=</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -5,9 +5,7 @@ struct MacAccountView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Login Details")) {
|
||||
AccountView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
93
macOS/Settings/MacUpdatesView.swift
Normal file
93
macOS/Settings/MacUpdatesView.swift
Normal file
@ -0,0 +1,93 @@
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
|
||||
enum AppcastFeedUrl: String {
|
||||
case release = "https://writefreely-files.s3.amazonaws.com/apps/mac/appcast.xml"
|
||||
case beta = "https://writefreely-files.s3.amazonaws.com/apps/mac/appcast-beta.xml"
|
||||
}
|
||||
|
||||
struct MacUpdatesView: View {
|
||||
@AppStorage("automaticallyChecksForUpdates") var automaticallyChecksForUpdates: Bool = false
|
||||
@AppStorage("subscribeToBetaUpdates") var subscribeToBetaUpdates: Bool = false
|
||||
@State private var lastUpdateCheck: Date?
|
||||
|
||||
private let betaWarningString = """
|
||||
To get brand new features before each official release, choose "Test versions." Note that test versions may have bugs \
|
||||
that can cause crashes and data loss.
|
||||
"""
|
||||
|
||||
static let lastUpdateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .short
|
||||
formatter.timeStyle = .short
|
||||
formatter.doesRelativeDateFormatting = true
|
||||
return formatter
|
||||
}()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 24) {
|
||||
Toggle(isOn: $automaticallyChecksForUpdates, label: {
|
||||
Text("Check for updates automatically")
|
||||
})
|
||||
|
||||
VStack {
|
||||
Button(action: {
|
||||
SUUpdater.shared()?.checkForUpdates(self)
|
||||
DispatchQueue.main.async {
|
||||
lastUpdateCheck = SUUpdater.shared()?.lastUpdateCheckDate
|
||||
}
|
||||
}, label: {
|
||||
Text("Check For Updates")
|
||||
})
|
||||
|
||||
HStack {
|
||||
Text("Last checked:")
|
||||
.font(.caption)
|
||||
if let lastUpdateCheck = lastUpdateCheck {
|
||||
Text(lastUpdateCheck, formatter: Self.lastUpdateFormatter)
|
||||
.font(.caption)
|
||||
} else {
|
||||
Text("Never")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VStack(spacing: 16) {
|
||||
HStack(alignment: .top) {
|
||||
Text("Download:")
|
||||
Picker(selection: $subscribeToBetaUpdates, label: Text("Download:"), content: {
|
||||
Text("Release versions").tag(false)
|
||||
Text("Test versions").tag(true)
|
||||
})
|
||||
.pickerStyle(RadioGroupPickerStyle())
|
||||
.labelsHidden()
|
||||
}
|
||||
|
||||
Text(betaWarningString)
|
||||
.frame(width: 350)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.onAppear {
|
||||
lastUpdateCheck = SUUpdater.shared()?.lastUpdateCheckDate
|
||||
}
|
||||
.onChange(of: automaticallyChecksForUpdates) { value in
|
||||
SUUpdater.shared()?.automaticallyChecksForUpdates = value
|
||||
}
|
||||
.onChange(of: subscribeToBetaUpdates) { value in
|
||||
if value {
|
||||
SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.beta.rawValue)
|
||||
} else {
|
||||
SUUpdater.shared()?.feedURL = URL(string: AppcastFeedUrl.release.rawValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MacUpdatesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MacUpdatesView()
|
||||
}
|
||||
}
|
@ -1,14 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict/>
|
||||
</plist>
|
||||
|
Loading…
Reference in New Issue
Block a user