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
3 changes: 3 additions & 0 deletions README-macOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,5 +198,8 @@ versions of FastSM:
secondary action, keeping the media player in the background, and moving extra
reply mentions to the end.
- Advanced — how many pages of posts to fetch per load.
- Updates — choose Stable version releases or every new build from main, and
whether to check automatically at startup. Use Application > Check for Updates
to download the selected Mac disk image.
- Confirmation — ask before boosting, unboosting, liking, unliking, clearing a
timeline, blocking, unblocking, or deleting a post.
10 changes: 4 additions & 6 deletions apple/shared/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,10 @@ final class AppState {
}
func deleteList(id: String) { client.send("delete_list", ["id": id]) }

// Updates. Mac checks the version-tagged "stable" channel (the commit-based
// "latest" channel needs an embedded build commit, which the Mac build lacks
// — same rationale as Android).
func checkForUpdate(silent: Bool) {
client.send("check_for_update", ["silent": silent, "branch": "stable"])
}
// The core uses the saved channel; iOS does not invoke this update flow.
func checkForUpdate(silent: Bool) {
client.send("check_for_update", ["silent": silent])
}

func getClientFilter() { client.send("get_client_filter") }
func setClientFilter(_ filter: [String: Any]) { client.send("set_client_filter", ["filter": filter]) }
Expand Down
10 changes: 4 additions & 6 deletions apple/shared/CoreEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -494,28 +494,26 @@ struct AccountSettings: Decodable {
}
}

/// Result of a check_for_update. Mac uses the `dmg_url` (a .dmg release asset);
/// falls back to opening `download_url` if none.
/// Result of a check_for_update. Mac downloads the `dmg_url` asset.
struct UpdateStatus: Decodable {
var silent = false
var available = false
var branch = "stable"
var version = ""
var notes = ""
var downloadUrl = ""
var dmgUrl = ""
var error = ""
enum CodingKeys: String, CodingKey {
case silent, available, version, notes, error
case downloadUrl = "download_url"
case silent, available, branch, version, notes, error
case dmgUrl = "dmg_url"
}
init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
silent = try c.decodeIfPresent(Bool.self, forKey: .silent) ?? false
available = try c.decodeIfPresent(Bool.self, forKey: .available) ?? false
branch = try c.decodeIfPresent(String.self, forKey: .branch) ?? "stable"
version = try c.decodeIfPresent(String.self, forKey: .version) ?? ""
notes = try c.decodeIfPresent(String.self, forKey: .notes) ?? ""
downloadUrl = try c.decodeIfPresent(String.self, forKey: .downloadUrl) ?? ""
dmgUrl = try c.decodeIfPresent(String.self, forKey: .dmgUrl) ?? ""
error = try c.decodeIfPresent(String.self, forKey: .error) ?? ""
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/version.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "fastsm/fastsm.hpp"

#if defined(__APPLE__) && __has_include("fastsm_build_commit.h")
#include "fastsm_build_commit.h"
#endif

namespace fastsm {

const char* version() {
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FastSMRW changelog
0.6.0
-----

- New: on the Mac, choose Stable version releases or every new build from main in Settings, Updates, and choose whether to check at startup.
- Fixed: on iPhone, posts with multiple lines now display with their original line breaks.
- New: on iPhone, choose whether the VoiceOver magic tap uses your secondary action, opens compose, or leaves the gesture to iOS; a magic tap set to View Media opens compose when a post has no playable media.
- Fixed: on Mastodon, posting no longer fails with an error sound when you have many timelines open; background refreshing now slows down before it uses up your server's request limit.
Expand Down
4 changes: 4 additions & 0 deletions macos/build-core.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ CORE=core/src
CXXFLAGS=(-std=c++20 -fexceptions -frtti -O2 -g
-I core/include -I deps -I deps/stb_vorbis
-Wall -Wno-deprecated-declarations)
COMMIT=$(git rev-parse --short HEAD 2>/dev/null || true)
if [ -n "$COMMIT" ]; then
CXXFLAGS+=("-DFASTSM_BUILD_COMMIT=\"$COMMIT\"")
fi

# Portable core sources (mirrors android/app/src/main/cpp/CMakeLists.txt), plus
# the C-ABI factory. Windows-only winhttp_client is excluded; the Darwin
Expand Down
14 changes: 14 additions & 0 deletions macos/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ targets:
fastsm_core:
type: library.static
platform: macOS
preBuildScripts:
- name: Embed build commit
basedOnDependencyAnalysis: false
script: |
COMMIT=$(/usr/bin/git -C "$SRCROOT/.." rev-parse --short HEAD 2>/dev/null || true)
HEADER="$DERIVED_FILE_DIR/fastsm_build_commit.h"
mkdir -p "$DERIVED_FILE_DIR"
printf '#define FASTSM_BUILD_COMMIT "%s"\n' "$COMMIT" > "$HEADER.tmp"
if ! cmp -s "$HEADER.tmp" "$HEADER"; then
mv "$HEADER.tmp" "$HEADER"
else
rm "$HEADER.tmp"
fi
sources:
# The whole portable core, minus the Windows-only WinHTTP transport. This
# is capi/fastsm_core.cpp + net/darwin_http_client.mm + everything the
Expand All @@ -38,6 +51,7 @@ targets:
- ../core/include
- ../deps
- ../deps/stb_vorbis
- $(DERIVED_FILE_DIR)
# stb_vorbis.c is noisy; don't let its warnings clutter the build.
GCC_WARN_UNUSED_FUNCTION: NO
GCC_WARN_UNUSED_VARIABLE: NO
Expand Down
26 changes: 18 additions & 8 deletions macos/src/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,25 +108,35 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
if !status.silent {
let alert = NSAlert()
alert.messageText = "You’re up to date."
alert.informativeText = "FastSMRW \(CoreClient.version) is the latest version."
alert.informativeText = status.branch == "latest"
? "You’re running the latest build of FastSMRW."
: "FastSMRW \(CoreClient.version) is the latest version."
alert.addButton(withTitle: "OK")
present(alert, on: window) { _ in }
}
return
}
guard !status.dmgUrl.isEmpty else {
if !status.silent {
ErrorAlert.present("Mac update isn't available yet.",
detail: "The selected release has no Mac download yet. Check again later.",
in: window)
}
return
}
let alert = NSAlert()
alert.messageText = "Update available: \(status.version)"
alert.informativeText = status.notes.isEmpty ? "A new version of FastSMRW is available."
alert.messageText = status.branch == "latest"
? "New build available: \(status.version)"
: "Update available: \(status.version)"
alert.informativeText = status.notes.isEmpty
? (status.branch == "latest" ? "A new build of FastSMRW is available."
: "A new version of FastSMRW is available.")
: status.notes
alert.addButton(withTitle: "Download")
alert.addButton(withTitle: "Later")
present(alert, on: window) { [weak self] response in
guard response == .alertFirstButtonReturn else { return }
if !status.dmgUrl.isEmpty {
self?.downloadAndOpenDMG(status.dmgUrl)
} else if let url = URL(string: status.downloadUrl) {
NSWorkspace.shared.open(url) // no Mac disk image; open the release page
}
self?.downloadAndOpenDMG(status.dmgUrl)
}
}

Expand Down
19 changes: 18 additions & 1 deletion macos/src/SettingsWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// The preferences window: a toolbar-style tab view mirroring the Windows
// settings pages (General, Timelines, Audio, Speech, Behavior, Advanced,
// Confirmation). Each control reads from the core's settings and writes back
// Updates, Confirmation). Each control reads from the core's settings and writes back
// through update_settings, which the core applies live.
//
// Deferred: the per-category reorderable "Speech Details" field lists — those
Expand Down Expand Up @@ -153,6 +153,17 @@ final class SettingsWindowController: NSWindowController {
p.intRow("API pages per fetch:", key: "fetch_pages", default: 3, min: 1, max: 10)
}

tab("Updates", "arrow.down.circle") { p in
let channels = [("Stable (version updates)", "stable"),
("Latest (every build)", "latest")]
p.popup("Update channel:", options: channels,
key: "update_branch", default: "stable")
p.checkbox("Check for updates automatically at startup",
key: "check_updates_on_startup", default: true)
p.label("Stable offers versioned releases. Latest follows new builds from main.")
p.label("Use Application > Check for Updates to check now.")
}

tab("Confirmation", "checkmark.shield") { p in
p.checkbox("Confirm boost", key: "confirm_boost", default: false)
p.checkbox("Confirm un-boost", key: "confirm_unboost", default: false)
Expand Down Expand Up @@ -342,6 +353,12 @@ final class SettingsPane: NSViewController {
stack.addArrangedSubview(button)
}

func label(_ text: String) {
let label = NSTextField(wrappingLabelWithString: text)
label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
stack.addArrangedSubview(label)
}

// MARK: Helpers

private func currentValue<Value>(key: String, default def: Value) -> Value {
Expand Down
Loading