feed

2024年11月07日, 編集履歴

Murasaki ver. 2.5.1をリリース

macOS用EPUBリーダアプリ「Murasaki」のver. 2.5.1が出ました。

ver. 2.5.1での変更点は、

Quick Look Thumbnail拡張機能の実装によって、macOS 15 Sequoia環境でEPUBのカバー画像をサムネイルとしてFinder等で表示できるようになりました。

Quick Look Preview拡張機能の修正について。EPUBの仕様的に必須となっている項目が抜けていたとき等、読み込みエラーになってプレビューできないようになっていました。あまつさえ、実装ミスにより、そのときにクラッシュしていました。クラッシュする不具合は修正し、メタデータが不備でもプレビューはできるように変更しました。

また、プレビューの読み込みデータサイズ制限のディフォルト値を5MBから10MBに拡張しました。

どうぞよろしく。

2024年10月24日, 編集履歴

Keyknockr ver. 2.0.1をリリース

macOS用ランチャアプリケーション「Keyknockr」の新しいヴァージョン2.0.1が出ました。

ver. 2.0.1の変更点は、

です。

また、このヴァージョンからは、macOS 15 Sequoia以降のみをサポートとします。どうぞよろしく。

2024年09月30日, 編集履歴

Murasaki ver. 2.5をリリース

macOS用EPUBリーダアプリ「Murasaki」のver. 2.5が出ました。

ver. 2.5での変更点は、

です。

新しいQuick Look拡張機能に関して、macOS 15 Sequoia以降は従来のQuick Lookプラグイン形式(.qlgenerator)がサポートされなくなったので、Sequoia以降で動作する機能拡張形式(.appex)で実装し直しました。

それに伴い、Quick Lookの動作設定を変更できるようにもなりました。

それぞれを、Murasaki本体の設定ウィンドウから変更できるようになっています。

読み込みデータサイズ制限は、Quick LookがEPUBデータを展開、プレヴューを構成していくなかで、全データを読み込むのではなく、設定したデータサイズで読み込みを打ち切ります。大きなデータサイズのEPUBの場合、プレヴュー構成に時間が掛かることがあるための制限となります(これまでは固定値でした)。

デフォルトのコンテントサイズは、Quick Lookプレヴューの初期ウィンドウサイズを設定できます。

また、新しい拡張機能形式はシステム設定から拡張機能の有効・無効を設定することができます。

どうぞよろしくお願いします。

2024年03月03日, 編集履歴

Keyknockr(旧CLCL)v2.0をリリース

macOS用ランチャアプリケーション「CLCL」を全面的に作り直し、名称を「Keyknockr」へと変更しました(バージョン番号は継続)。

Keyknockr(旧CLCL)はCommandキーやShiftキーなどの修飾キーを連打することで、設定したアプリケーションやURLを開くことができるランチャアプリケーションです。

今回のバージョンアップにともない、従来のLite版・有料版販売モデルから、フリーミアムモデル(基本無料+サブスクリプションによる機能解放)へと移行し、配信場所はMac App Storeへ統一されました。

v2.0ではイチからSwift/SwiftUIを用いて再構築され、新しい特殊アクションとして、

が追加されました。

「実行中のアプリケーション」アクションは現在実行中の(Dockに表示される)アプリケーションの一覧メニューがポップアップされ、そこから当該アプリケーションをアクティブ化できます。

「ポップアップメニュー」アクションは事前に設定したアプリケーションやローカルファイル、URLの一覧メニューがポップアップされ、そこから起動、アクティブ化、開く操作が実行できます。

また、「ログイン時に起動」設定を追加したので、Keyknockrの設定画面からかんたんに起動設定を変更できるようになりました。

どうぞよろしく。

以前にCLCLをGumroadで購入されていた方へはKeyknockr v2.0機能解放版を提供しています。Gumroadのシステムを通してメールを送信しているので、ご確認ください。

2024年02月20日, 編集履歴

SwiftUIのmacOSアプリでTableにコンテキストメニューをつける

Tableの基本的な使い方は「SwiftUI Tableの使い方」を参照。

macOSアプリにSwiftUIのTableを組み込み、副ボタンクリック(右クリック)によるコンテキストメニューをつけた時、テーブル行として表現されているオブジェクトに対して何らかの操作を行うような場合を考える。たとえばリスト表示にしたFinderで、ファイルやフォルダを右クリックしたときにでるコンテキストメニューをイメージしてもらうと良い。

このときTableColumn配下の要素やTableRow.contextMenu(menuItems:)モディファイアをつけてしまいがちだが、macOSアプリのテーブルに対するコンテキストメニューの自然な挙動を実現するには、Table自体に.contextMenu(forSelectionType:menu:primaryAction:)モディファイアをつけなければならない。

テーブルの選択状態と操作対象

テーブル行をふつうにクリックした場合、行選択の状態となり、行全体にハイライトがつく。行を右クリックした場合、行の縁だけハイライトがつき、コンテキストメニューの起点、操作対象の状態になる。このふたつは別の状態である。選択範囲とコンテキストメニューの操作対象は重なる場合もあれば、異なる場合もある。

コンテキストメニューの操作対象は以下のようになる:

上図のコンテキストメニューの内容から操作対象が変わっていることが解る。

実装

以下のような実装が良いと思う。

import SwiftUI
import UniformTypeIdentifiers

struct Bookmark: Identifiable {

  var id = UUID()
  var title: String
  var url: URL
}

struct ContentView: View {

  @State private var sampleData: [Bookmark] = [
    .init(title: "Genji App", url: URL(string: "https://genjiapp.com")!),
    .init(title: "Apple", url: URL(string: "https://www.apple.com")!),
    .init(title: "Google", url: URL(string: "https://www.google.com")!)
  ]
  @State private var selectedIDs = Set<Bookmark.ID>()

  var body: some View {
    Table(of: Bookmark.self, selection: $selectedIDs) {
      TableColumn("Title") { bookmark in
        Text(bookmark.title)
//          .contextMenu {
//            Button("ここじゃない") {
//              print(bookmark)
//              print(selectedIDs)
//            }
//          }
      }
      TableColumn("URL") { bookmark in
        Text(bookmark.url.absoluteString)
      }
    } rows: {
      ForEach(sampleData) { bookmark in
        TableRow(bookmark)
//          .contextMenu {
//            Button("ここでもない") {
//              print(bookmark)
//              print(selectedIDs)
//            }
//          }
      }
    }
    .tableStyle(.bordered)
    // ここ!
    .contextMenu(forSelectionType: Bookmark.ID.self) { clickedRowIDs in
      addButton
      Button("Delete Bookmark") {
        sampleData.removeAll { clickedRowIDs.contains($0.id) }
      }
    }
    // ここはテーブル内余白を右クリックしたとき
    .contextMenu {
      addButton
    }
    .padding()
  }

  var addButton: some View {
    Button("Add Bookmark") {
      sampleData.append(.init(title: "Microsoft", url: URL(string: "https://www.microsoft.com")!))
    }
  }

}

TableColumn配下の要素に.contextMenu(menuItems:)モディファイアをつける場合、複数の列があるときはすべてにモディファイアをつけなければならないし、右クリックに反応するのは行の中の文字がある部分だけになる。

TableRow.contextMenu(menuItems:)モディファイアをつける場合、選択行とコンテキストメニューの操作対象両方を取得できるが、両者が別の型になるし、両者の重なり具合を調べて操作対象を自分で計算する必要がある。

Table自体に.contextMenu(forSelectionType:menu:primaryAction:)モディファイアをつける場合、第2引数menuクロージャの引数として、標準的な操作対象となるオブジェクトのidSetで取得できるので、その後の処理がストレートに記述できる。

第1引数forSelectionTypeには、テーブル行を表現するオブジェクトを特定するための型を指定する。オブジェクトはIdentifiableプロトコルに適合させているはずなので、idプロパティの型となる。第3引数primaryActionは、行をダブルクリックした時に実行される。

また、ドキュメントには.contextMenu(forSelectionType:menu:primaryAction:)の第2引数menuクロージャの引数が空のSetの場合はテーブルの余白部分を右クリックしたことになるとあるが、macOS 14.3.1とXcode Version 15.2 (15C500b)の環境ではコンテキストメニューが出ない。上のコード例ではTable自体にもうひとつ別の.contextMenu(menuItems:)をつけることで、余白部分を右クリックした場合をカバーしている。