app.progress - Progress Dialog API

Display and control progress dialogs. Provides both a simple API (per-plugin isolation) and an advanced API (multiple instances).

The simple API allows only one progress dialog per plugin at a time, suitable for most scenarios.

app.progress.show(title, config?)

Displays a progress dialog. If the current plugin already has a progress dialog, it will be closed first.

Parameters:

  • title (string) - Dialog title
  • config (table, optional):
    • message (string) - Detail message
    • indeterminate (boolean) - Whether the progress is indeterminate (default true)
    • cancellable (boolean) - Whether the dialog can be cancelled (default false)
    • onCancel (function) - Cancel callback

Returns: boolean - Whether the dialog was displayed successfully

-- Simple usage
app.progress.show("Processing")

-- With configuration
app.progress.show("Processing", {
    message = "Please wait...",
    indeterminate = false,
    cancellable = true,
    onCancel = function()
        app.log.info("User cancelled the operation")
    end
})

-- You can also pass a config table directly
app.progress.show({
    title = "Processing",
    message = "Please wait...",
    indeterminate = false
})

app.progress.update(value, message?)

Updates the progress value and message.

Parameters:

  • value (number) - Current progress value (0-100)
  • message (string, optional) - Updated message
for i = 1, 100 do
    app.progress.update(i, "Processing item " .. i)
    -- Perform operation...
end

app.progress.setMessage(message)

Updates only the message text without changing the progress value.

Parameters:

  • message (string) - New message
app.progress.setMessage("Executing step 2...")

app.progress.isCancelled()

Checks whether the user has cancelled the current progress dialog. Must be used with cancellable = true.

Returns: boolean - Whether cancelled

app.progress.show("Processing", {
    indeterminate = false,
    cancellable = true
})

for i = 1, 100 do
    if app.progress.isCancelled() then
        break
    end
    app.progress.update(i, "Step " .. i)
end

app.progress.hide()

app.progress.hide()

Closes the progress dialog.

app.progress.hide()

Advanced API (Multiple Instances)

Use the advanced API when you need to display multiple progress dialogs simultaneously.

app.progress.create(config)

Creates and displays a new progress dialog instance.

Parameters:

  • config (table):
    • title (string, required) - Dialog title
    • message (string) - Detail message
    • indeterminate (boolean) - Whether the progress is indeterminate (default true)
    • cancellable (boolean) - Whether the dialog can be cancelled (default false)
    • onCancel (function) - Cancel callback

Returns: progressHandle - Progress handle object

local progress = app.progress.create({
    title = "Downloading File",
    message = "Preparing...",
    indeterminate = false,
    cancellable = true,
    onCancel = function()
        app.log.info("Download cancelled")
    end
})

progressHandle:update(value, message?)

Updates the progress value and message of the handle.

Parameters:

  • value (number) - Current progress value (0-100)
  • message (string, optional) - Updated message
progress:update(50, "50% complete")

progressHandle:setMessage(message)

Updates the message text of the progress handle.

Parameters:

  • message (string) - New message
progress:setMessage("Processing...")

progressHandle:isCancelled()

Checks whether the user has cancelled this progress dialog.

Returns: boolean - Whether cancelled

if progress:isCancelled() then
    progress:close()
    return
end

progressHandle:close()

Closes the dialog associated with this progress handle.

progress:close()

Complete Examples

Basic Usage

function MyPlugin:handleBatchProcess(context)
    local files = context.selectedFiles
    local total = #files

    -- Show a cancellable progress dialog
    app.progress.show("Batch Processing", {
        message = "Preparing...",
        indeterminate = false,
        cancellable = true
    })

    local processed = 0
    for i, file in ipairs(files) do
        -- Check if the user cancelled
        if app.progress.isCancelled() then
            break
        end

        -- Update progress
        app.progress.update(i * 100 / total, "Processing: " .. app.path.basename(file))

        -- Perform processing
        self:processFile(file)
        processed = processed + 1
    end

    app.progress.hide()
    app.notification.show("Done", "Processed " .. processed .. " files")
end

Indeterminate Progress Mode

function MyPlugin:handleSearch(context)
    -- Show a spinning indicator without a specific progress value
    app.progress.show("Searching", {
        message = "Searching for files...",
        indeterminate = true
    })

    -- Perform an operation of unknown duration
    local results = self:searchFiles()

    app.progress.hide()
    app.notification.show("Done", "Found " .. #results .. " files")
end

Multiple Instance Progress

function MyPlugin:handleParallelDownload(context)
    local urls = {"url1", "url2", "url3"}
    local progresses = {}

    -- Create multiple progress dialogs
    for i, url in ipairs(urls) do
        progresses[i] = app.progress.create({
            title = "Download " .. i,
            message = "Preparing...",
            indeterminate = false
        })
    end

    -- Simulate parallel downloads (in practice, use app.thread)
    for i = 1, 100 do
        for j, progress in ipairs(progresses) do
            progress:update(i, "Downloading... " .. i .. "%")
        end
    end

    -- Close all progress dialogs
    for _, progress in ipairs(progresses) do
        progress:close()
    end
end

With Cancel Callback

Note: You can also use app.progress.isCancelled() polling instead of setting a flag variable in the onCancel callback. See the “Basic Usage” example.

function MyPlugin:handleCancellableTask(context)
    local cancelled = false

    app.progress.show("Long Operation", {
        message = "Processing...",
        indeterminate = false,
        cancellable = true,
        onCancel = function()
            cancelled = true
            app.log.info("User cancelled the operation")
        end
    })

    for i = 1, 100 do
        if cancelled then
            break
        end

        app.progress.update(i, "Step " .. i .. "/100")
        -- Simulate a time-consuming operation
    end

    app.progress.hide()

    if cancelled then
        app.notification.show("Cancelled", "Operation was cancelled by user")
    else
        app.notification.show("Done", "Operation complete")
    end
end
Developer Documentation
User Guide
Getting Started Script Menus FAQ
Script Development
Development Guide
Plugin Development
Quick Start Development Guide Example Plugins
API Reference
Overview API Query Plugin Info Logging Finder Context Plugin Settings Internationalization
UI & Interaction
Dialog Progress Notification Chooser WebView Status Bar Dock
Files & Paths
File Operations Path Utilities Finder Actions Trash Extended Attributes Metadata File Watcher
Data Formats
JSON Plist CSV XML PDF Image
Text & Encoding
String Regex Date & Time Color Crypto
System
Shell Commands Process Application System Info AppleScript Shortcuts
System Info
Network Power/Battery Screen/Appearance Audio Bluetooth Location
Network
HTTP WebSocket URL
Input & Clipboard
Keyboard Mouse Hotkey Clipboard Window
Storage
SQLite Keychain UserDefaults
Media
OCR QR Code
Utilities
Archive UTI Share Timer Wake Lock Thread