95 lines
2.5 KiB
Elixir
95 lines
2.5 KiB
Elixir
defmodule BDS.Desktop.FilePicker do
|
|
@moduledoc false
|
|
|
|
def choose_file(prompt) when is_binary(prompt) do
|
|
if System.get_env("BDS_DESKTOP_AUTOMATION") == "1" do
|
|
:cancel
|
|
else
|
|
case :os.type() do
|
|
{:unix, :darwin} -> choose_file_macos(prompt)
|
|
_other -> {:error, %{message: "File selection is only supported on macOS desktop"}}
|
|
end
|
|
end
|
|
end
|
|
|
|
def choose_files(prompt, opts \\ []) when is_binary(prompt) do
|
|
if System.get_env("BDS_DESKTOP_AUTOMATION") == "1" do
|
|
:cancel
|
|
else
|
|
case :os.type() do
|
|
{:unix, :darwin} -> choose_files_macos(prompt, opts)
|
|
_other -> {:error, %{message: "File selection is only supported on macOS desktop"}}
|
|
end
|
|
end
|
|
end
|
|
|
|
defp choose_file_macos(prompt) do
|
|
script = "POSIX path of (choose file with prompt \"#{escape_applescript(prompt)}\")"
|
|
|
|
case System.cmd("osascript", ["-e", script], stderr_to_stdout: true) do
|
|
{output, 0} -> {:ok, String.trim(output)}
|
|
{output, _status} -> normalize_picker_failure(output)
|
|
end
|
|
end
|
|
|
|
defp choose_files_macos(prompt, opts) do
|
|
multiple = Keyword.get(opts, :multiple, false)
|
|
image_only = Keyword.get(opts, :image_only, false)
|
|
|
|
script_parts = ["POSIX path of (choose file with prompt \"#{escape_applescript(prompt)}\""]
|
|
|
|
script_parts =
|
|
if image_only do
|
|
script_parts ++ [" of type {\"public.image\"}"]
|
|
else
|
|
script_parts
|
|
end
|
|
|
|
script_parts =
|
|
if multiple do
|
|
script_parts ++ [" with multiple selections allowed"]
|
|
else
|
|
script_parts
|
|
end
|
|
|
|
script = Enum.join(script_parts, "") <> ")"
|
|
|
|
case System.cmd("osascript", ["-e", script], stderr_to_stdout: true) do
|
|
{output, 0} -> parse_choose_files_result(String.trim(output), multiple)
|
|
{output, _status} -> normalize_picker_failure(output)
|
|
end
|
|
end
|
|
|
|
@doc false
|
|
def parse_choose_files_result(output, true = _multiple) do
|
|
paths =
|
|
output
|
|
|> String.split("\n")
|
|
|> Enum.map(&String.trim/1)
|
|
|> Enum.reject(&(&1 == ""))
|
|
|
|
{:ok, paths}
|
|
end
|
|
|
|
@doc false
|
|
def parse_choose_files_result(output, false = _multiple) do
|
|
{:ok, output}
|
|
end
|
|
|
|
defp normalize_picker_failure(output) do
|
|
message = String.trim(output)
|
|
|
|
if message == "" or String.contains?(String.downcase(message), "canceled") do
|
|
:cancel
|
|
else
|
|
{:error, %{message: message}}
|
|
end
|
|
end
|
|
|
|
defp escape_applescript(value) do
|
|
value
|
|
|> String.replace("\\", "\\\\")
|
|
|> String.replace("\"", "\\\"")
|
|
end
|
|
end
|