🌐 feat(i18n): add translations for media controls
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
@girs/
|
@types/
|
||||||
build/
|
build/
|
||||||
|
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
|||||||
+1
-8
@@ -40,10 +40,6 @@ else
|
|||||||
mkdir -p $output
|
mkdir -p $output
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# link node_modules to src, so ags(esbuild) knows there are modules to bundle
|
|
||||||
echo "[info] linking modules"
|
|
||||||
ln -s node_modules src/node_modules
|
|
||||||
|
|
||||||
echo "[info] compiling gresource"
|
echo "[info] compiling gresource"
|
||||||
gres_target=`[[ "$keep_gresource" ]] && echo -n "$output/resources.gresource" || \
|
gres_target=`[[ "$keep_gresource" ]] && echo -n "$output/resources.gresource" || \
|
||||||
echo -n "${gresources_target:-$output/resources.gresource}"`
|
echo -n "${gresources_target:-$output/resources.gresource}"`
|
||||||
@@ -53,12 +49,9 @@ glib-compile-resources resources.gresource.xml \
|
|||||||
--target "$gres_target"
|
--target "$gres_target"
|
||||||
|
|
||||||
echo "[info] bundling project"
|
echo "[info] bundling project"
|
||||||
ags bundle src/app.ts $output/colorshell \
|
ags --gtk 4 bundle src/app.ts $output/colorshell \
|
||||||
-r ./src \
|
-r ./src \
|
||||||
-d "DEVEL=`[[ $is_devel ]] && echo -n true || echo -n false`" \
|
-d "DEVEL=`[[ $is_devel ]] && echo -n true || echo -n false`" \
|
||||||
-d "COLORSHELL_VERSION='`cat package.json | jq -r .version`'" \
|
-d "COLORSHELL_VERSION='`cat package.json | jq -r .version`'" \
|
||||||
-d "GRESOURCES_FILE='${gresources_target:-$output/resources.gresource}'" \
|
-d "GRESOURCES_FILE='${gresources_target:-$output/resources.gresource}'" \
|
||||||
|| rm -rf src/node_modules
|
|| rm -rf src/node_modules
|
||||||
|
|
||||||
echo "[info] cleaning"
|
|
||||||
rm -rf src/node_modules
|
|
||||||
|
|||||||
+1
-1
@@ -5,4 +5,4 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
echo "Building types, this can take long..."
|
echo "Building types, this can take long..."
|
||||||
pnpx @ts-for-gir/cli generate --ignoreVersionConflicts -o ./@girs
|
pnpx @ts-for-gir/cli generate --ignoreVersionConflicts
|
||||||
|
|||||||
+1
-5
@@ -1,7 +1,3 @@
|
|||||||
// fix ags needing --gtk 4
|
|
||||||
// import app from "ags/gtk4/app";
|
|
||||||
|
|
||||||
// fix can't convert non-null pointer to JS value (thanks Aylur!)
|
|
||||||
import "ags/overrides";
|
import "ags/overrides";
|
||||||
import "./config";
|
import "./config";
|
||||||
import {
|
import {
|
||||||
@@ -29,13 +25,13 @@ import { setConsoleLogDomain } from "console";
|
|||||||
import { initPlayer } from "./modules/media";
|
import { initPlayer } from "./modules/media";
|
||||||
import { createSubscription, encoder, secureBaseBinding } from "./modules/utils";
|
import { createSubscription, encoder, secureBaseBinding } from "./modules/utils";
|
||||||
import { exec } from "ags/process";
|
import { exec } from "ags/process";
|
||||||
|
import { NightLight } from "./modules/nightlight";
|
||||||
import { Backlights } from "./modules/backlight";
|
import { Backlights } from "./modules/backlight";
|
||||||
import GObject, { register } from "ags/gobject";
|
import GObject, { register } from "ags/gobject";
|
||||||
|
|
||||||
import GLib from "gi://GLib?version=2.0";
|
import GLib from "gi://GLib?version=2.0";
|
||||||
import Gio from "gi://Gio?version=2.0";
|
import Gio from "gi://Gio?version=2.0";
|
||||||
import Adw from "gi://Adw?version=1";
|
import Adw from "gi://Adw?version=1";
|
||||||
import { NightLight } from "./modules/nightlight";
|
|
||||||
|
|
||||||
|
|
||||||
const runnerPlugins: Array<Runner.Plugin> = [
|
const runnerPlugins: Array<Runner.Plugin> = [
|
||||||
|
|||||||
+4
-3
@@ -48,11 +48,11 @@ const generalConfigDefaults = {
|
|||||||
|
|
||||||
const userDataDefaults = {
|
const userDataDefaults = {
|
||||||
/** last default adapter */
|
/** last default adapter */
|
||||||
bluetooth_default_adapter: undefined,
|
bluetooth_default_adapter: undefined as unknown as string,
|
||||||
|
|
||||||
control_center: {
|
control_center: {
|
||||||
/** last default backlight */
|
/** last default backlight */
|
||||||
default_backlight: undefined
|
default_backlight: undefined as unknown as string
|
||||||
},
|
},
|
||||||
|
|
||||||
night_light: {
|
night_light: {
|
||||||
@@ -75,5 +75,6 @@ export const userData = new Config<
|
|||||||
|
|
||||||
export const generalConfig = new Config<keyof typeof generalConfigDefaults,
|
export const generalConfig = new Config<keyof typeof generalConfigDefaults,
|
||||||
typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>(
|
typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>(
|
||||||
`${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults
|
`${GLib.get_user_config_dir()}/colorshell/config.json`,
|
||||||
|
generalConfigDefaults
|
||||||
);
|
);
|
||||||
|
|||||||
+15
-1
@@ -20,7 +20,21 @@ export default {
|
|||||||
|
|
||||||
connect: "Connect",
|
connect: "Connect",
|
||||||
disconnect: "Disconnect",
|
disconnect: "Disconnect",
|
||||||
|
copy_to_clipboard: "Copy to clipboard",
|
||||||
|
|
||||||
|
media: {
|
||||||
|
play: "Play",
|
||||||
|
pause: "Pause",
|
||||||
|
next: "Next",
|
||||||
|
previous: "Previous",
|
||||||
|
loop: "Loop",
|
||||||
|
no_loop: "No loop",
|
||||||
|
song_loop: "Loop song",
|
||||||
|
shuffle_order: "Shuffle",
|
||||||
|
follow_order: "Follow order",
|
||||||
|
no_artist: "No artist",
|
||||||
|
no_title: "No title"
|
||||||
|
},
|
||||||
control_center: {
|
control_center: {
|
||||||
tiles: {
|
tiles: {
|
||||||
enabled: "Enabled",
|
enabled: "Enabled",
|
||||||
@@ -88,4 +102,4 @@ export default {
|
|||||||
ask_popup: {
|
ask_popup: {
|
||||||
title: "Question"
|
title: "Question"
|
||||||
}
|
}
|
||||||
} as i18nStruct;
|
} satisfies i18nStruct;
|
||||||
|
|||||||
+15
-1
@@ -20,7 +20,21 @@ export default {
|
|||||||
|
|
||||||
apps: "Aplicativos",
|
apps: "Aplicativos",
|
||||||
clear: "Limpar",
|
clear: "Limpar",
|
||||||
|
copy_to_clipboard: "Copiar para a Área de Transferência",
|
||||||
|
|
||||||
|
media: {
|
||||||
|
next: "Próxima faixa",
|
||||||
|
pause: "Pausar",
|
||||||
|
play: "Tocar",
|
||||||
|
previous: "Faixa anterior",
|
||||||
|
loop: "Repetir",
|
||||||
|
no_loop: "Não repetir",
|
||||||
|
song_loop: "Repetir faixa",
|
||||||
|
follow_order: "Seguir ordem",
|
||||||
|
shuffle_order: "Ordem aleatória",
|
||||||
|
no_title: "Sem título",
|
||||||
|
no_artist: "Sem artista"
|
||||||
|
},
|
||||||
control_center: {
|
control_center: {
|
||||||
tiles: {
|
tiles: {
|
||||||
enabled: "Ligado",
|
enabled: "Ligado",
|
||||||
@@ -88,4 +102,4 @@ export default {
|
|||||||
ask_popup: {
|
ask_popup: {
|
||||||
title: "Pergunta"
|
title: "Pergunta"
|
||||||
}
|
}
|
||||||
} as i18nStruct;
|
} satisfies i18nStruct;
|
||||||
|
|||||||
+16
-2
@@ -17,9 +17,23 @@ export type i18nStruct = {
|
|||||||
disconnect: string,
|
disconnect: string,
|
||||||
connect: string,
|
connect: string,
|
||||||
|
|
||||||
apps: string;
|
apps: string,
|
||||||
clear: string;
|
clear: string,
|
||||||
|
copy_to_clipboard: string,
|
||||||
|
|
||||||
|
media: {
|
||||||
|
loop: string,
|
||||||
|
song_loop: string,
|
||||||
|
no_loop: string,
|
||||||
|
shuffle_order: string,
|
||||||
|
follow_order: string,
|
||||||
|
pause: string,
|
||||||
|
play: string,
|
||||||
|
next: string,
|
||||||
|
previous: string,
|
||||||
|
no_artist: string,
|
||||||
|
no_title: string
|
||||||
|
},
|
||||||
control_center: {
|
control_center: {
|
||||||
tiles: {
|
tiles: {
|
||||||
enabled: string,
|
enabled: string,
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ import AstalBluetooth from "gi://AstalBluetooth";
|
|||||||
/** AstalBluetooth helper (implements the default adapter feature) */
|
/** AstalBluetooth helper (implements the default adapter feature) */
|
||||||
@register({ GTypeName: "Bluetooth" })
|
@register({ GTypeName: "Bluetooth" })
|
||||||
export class Bluetooth extends GObject.Object {
|
export class Bluetooth extends GObject.Object {
|
||||||
|
declare $signals: {
|
||||||
|
"notify": () => void;
|
||||||
|
"notify::adapter": (adapter: AstalBluetooth.Adapter|null) => void;
|
||||||
|
"notify::is-available": (available: boolean) => void;
|
||||||
|
"notify::save-default-adapter": (save: boolean) => void;
|
||||||
|
"notify::last-device": (device: AstalBluetooth.Device|null) => void;
|
||||||
|
};
|
||||||
|
|
||||||
private static instance: Bluetooth;
|
private static instance: Bluetooth;
|
||||||
private astalBl = AstalBluetooth.get_default();
|
private astalBl = AstalBluetooth.get_default();
|
||||||
|
|
||||||
@@ -16,12 +24,18 @@ export class Bluetooth extends GObject.Object {
|
|||||||
#adapter: AstalBluetooth.Adapter|null = this.astalBl.adapter ?? null;
|
#adapter: AstalBluetooth.Adapter|null = this.astalBl.adapter ?? null;
|
||||||
#scope!: Scope;
|
#scope!: Scope;
|
||||||
#isAvailable: boolean = false;
|
#isAvailable: boolean = false;
|
||||||
|
#lastDevice: AstalBluetooth.Device|null = null;
|
||||||
|
|
||||||
|
@property(Boolean)
|
||||||
|
saveDefaultAdapter: boolean = true;
|
||||||
|
|
||||||
@getter(Boolean)
|
@getter(Boolean)
|
||||||
get isAvailable() { return this.#isAvailable; }
|
get isAvailable() { return this.#isAvailable; }
|
||||||
|
|
||||||
@property(Boolean) saveDefaultAdapter = true;
|
/** last connected device, can be null */
|
||||||
|
@getter(AstalBluetooth.Device)
|
||||||
|
get lastDevice() { return this.#lastDevice!; }
|
||||||
|
|
||||||
@getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter))
|
@getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter))
|
||||||
get adapter() { return this.#adapter; }
|
get adapter() { return this.#adapter; }
|
||||||
|
|
||||||
@@ -94,6 +108,16 @@ export class Bluetooth extends GObject.Object {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.#lastDevice = this.getLastConnectedDevice();
|
||||||
|
this.notify("last-device");
|
||||||
|
|
||||||
|
this.#connections.set(AstalBluetooth.get_default(), [
|
||||||
|
AstalBluetooth.get_default().connect("notify::devices", (_) => {
|
||||||
|
this.#lastDevice = this.getLastConnectedDevice();
|
||||||
|
this.notify("last-device");
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
this.#scope.onCleanup(() => this.#connections.forEach((ids, gobj) =>
|
this.#scope.onCleanup(() => this.#connections.forEach((ids, gobj) =>
|
||||||
Array.isArray(ids) ?
|
Array.isArray(ids) ?
|
||||||
ids.forEach(id => gobj.disconnect(id))
|
ids.forEach(id => gobj.disconnect(id))
|
||||||
@@ -112,4 +136,22 @@ export class Bluetooth extends GObject.Object {
|
|||||||
vfunc_dispose(): void {
|
vfunc_dispose(): void {
|
||||||
this.#scope.dispose();
|
this.#scope.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getLastConnectedDevice(): AstalBluetooth.Device|null {
|
||||||
|
|
||||||
|
const connectedDevices = AstalBluetooth.get_default().devices
|
||||||
|
.filter(d => d.connected);
|
||||||
|
|
||||||
|
const lastDevice = connectedDevices[connectedDevices.length - 1];
|
||||||
|
|
||||||
|
console.log(`last device: ${lastDevice?.address}`);
|
||||||
|
|
||||||
|
return lastDevice ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect<Signal extends keyof (typeof this)["$signals"]>(
|
||||||
|
signal: Signal, callback: (typeof this["$signals"])[Signal]
|
||||||
|
): number {
|
||||||
|
return super.connect(signal as string, callback as () => void);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
import GLib from "gi://GLib?version=2.0";
|
|
||||||
|
|
||||||
import GObject, { getter, property, register } from "ags/gobject";
|
|
||||||
|
|
||||||
|
|
||||||
/** WIP Global implementation of a system that supports
|
|
||||||
* a variety of Wayland Compositors */
|
|
||||||
export namespace Compositor {
|
|
||||||
|
|
||||||
let instance: _Compositor;
|
|
||||||
|
|
||||||
@register({ GTypeName: "CompositorMonitor" })
|
|
||||||
class _CompositorMonitor extends GObject.Object {
|
|
||||||
public readonly width: number;
|
|
||||||
public readonly height: number;
|
|
||||||
|
|
||||||
@property(Boolean)
|
|
||||||
public readonly mirror: boolean;
|
|
||||||
|
|
||||||
constructor(width: number, height: number, mirror: boolean = false) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.mirror = mirror;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@register({ GTypeName: "CompositorWorkspace" })
|
|
||||||
class _CompositorWorkspace extends GObject.Object {
|
|
||||||
public readonly id: number;
|
|
||||||
|
|
||||||
@getter(_CompositorMonitor)
|
|
||||||
public readonly monitor: _CompositorMonitor;
|
|
||||||
|
|
||||||
constructor(monitor: _CompositorMonitor, id: number) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.monitor = monitor;
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@register({ GTypeName: "Compositor" })
|
|
||||||
class _Compositor extends GObject.Object {
|
|
||||||
#workspaces: Array<_CompositorWorkspace> = [];
|
|
||||||
|
|
||||||
@property()
|
|
||||||
public get workspaces() { return this.#workspaces; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export function getDefault(): _Compositor {
|
|
||||||
if(!instance)
|
|
||||||
instance = new _Compositor();
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Compositor = _Compositor,
|
|
||||||
CompositorWorkspace = _CompositorWorkspace,
|
|
||||||
CompositorMonitor = _CompositorMonitor;
|
|
||||||
|
|
||||||
/** Uses the XDG_CURRENT_DESKTOP variable to detect running compositor's name.
|
|
||||||
* ---
|
|
||||||
* @returns running wayland compositor's name (lowercase) or `undefined` if variable's not set */
|
|
||||||
export function getName(): string|undefined {
|
|
||||||
return GLib.getenv("XDG_CURRENT_DESKTOP") ?? undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ import { timeout } from "ags/time";
|
|||||||
import { monitorFile, readFileAsync, writeFileAsync } from "ags/file";
|
import { monitorFile, readFileAsync, writeFileAsync } from "ags/file";
|
||||||
import { Notifications } from "./notifications";
|
import { Notifications } from "./notifications";
|
||||||
import { Accessor } from "ags";
|
import { Accessor } from "ags";
|
||||||
import GObject, { getter, ParamSpec, register } from "ags/gobject";
|
import GObject, { getter, gtype, register } from "ags/gobject";
|
||||||
|
|
||||||
import Gio from "gi://Gio?version=2.0";
|
import Gio from "gi://Gio?version=2.0";
|
||||||
import AstalIO from "gi://AstalIO";
|
import AstalIO from "gi://AstalIO";
|
||||||
@@ -13,7 +13,7 @@ export { Config };
|
|||||||
type ValueTypes = "string" | "boolean" | "object" | "number" | "any";
|
type ValueTypes = "string" | "boolean" | "object" | "number" | "any";
|
||||||
|
|
||||||
@register({ GTypeName: "Config" })
|
@register({ GTypeName: "Config" })
|
||||||
class Config<K extends NonNullable<string|number|symbol>, V extends string|object|any> extends GObject.Object {
|
class Config<K extends string, V = any> extends GObject.Object {
|
||||||
declare $signals: GObject.Object.SignalSignatures & {
|
declare $signals: GObject.Object.SignalSignatures & {
|
||||||
"notify::entries": (entries: Record<K, V>) => void;
|
"notify::entries": (entries: Record<K, V>) => void;
|
||||||
};
|
};
|
||||||
@@ -22,7 +22,7 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
|
|||||||
* in the `entries` field */
|
* in the `entries` field */
|
||||||
public readonly defaults: Record<K, V>;
|
public readonly defaults: Record<K, V>;
|
||||||
|
|
||||||
@getter(Object as unknown as ParamSpec<Record<K, V>>)
|
@getter(gtype<Record<K, V>>(Object))
|
||||||
public get entries() { return this.#entries; }
|
public get entries() { return this.#entries; }
|
||||||
|
|
||||||
#file: Gio.File;
|
#file: Gio.File;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { accessMediaUrl, player, setPlayer } from "../../../modules/media";
|
|||||||
import GObject from "ags/gobject";
|
import GObject from "ags/gobject";
|
||||||
import AstalMpris from "gi://AstalMpris";
|
import AstalMpris from "gi://AstalMpris";
|
||||||
import Pango from "gi://Pango?version=1.0";
|
import Pango from "gi://Pango?version=1.0";
|
||||||
|
import { tr } from "../../../i18n/intl";
|
||||||
|
|
||||||
|
|
||||||
export const Media = () => {
|
export const Media = () => {
|
||||||
@@ -66,12 +67,12 @@ export const Media = () => {
|
|||||||
createBinding(player.get(), "busName").as(getPlayerIconFromBusName)}
|
createBinding(player.get(), "busName").as(getPlayerIconFromBusName)}
|
||||||
/>
|
/>
|
||||||
<Gtk.Label class={"title"} label={createBinding(player.get(), "title").as(title =>
|
<Gtk.Label class={"title"} label={createBinding(player.get(), "title").as(title =>
|
||||||
title ?? "No Title")} maxWidthChars={20} ellipsize={Pango.EllipsizeMode.END}
|
title ?? tr("media.no_title"))} maxWidthChars={20} ellipsize={Pango.EllipsizeMode.END}
|
||||||
/>
|
/>
|
||||||
<Separator orientation={Gtk.Orientation.HORIZONTAL} size={1} margin={5}
|
<Separator orientation={Gtk.Orientation.HORIZONTAL} size={1} margin={5}
|
||||||
alpha={.3} spacing={6} />
|
alpha={.3} spacing={6} />
|
||||||
<Gtk.Label class={"artist"} label={createBinding(player.get(), "artist").as(artist =>
|
<Gtk.Label class={"artist"} label={createBinding(player.get(), "artist").as(artist =>
|
||||||
artist ?? "No Artist")} maxWidthChars={18} ellipsize={Pango.EllipsizeMode.END}
|
artist ?? tr("media.no_artist"))} maxWidthChars={18} ellipsize={Pango.EllipsizeMode.END}
|
||||||
/>
|
/>
|
||||||
</Gtk.Box>}
|
</Gtk.Box>}
|
||||||
</With>
|
</With>
|
||||||
@@ -84,7 +85,7 @@ export const Media = () => {
|
|||||||
<Gtk.Box class={"extra button-row"}>
|
<Gtk.Box class={"extra button-row"}>
|
||||||
<Gtk.Button class={"link"} iconName={"edit-paste-symbolic"}
|
<Gtk.Button class={"link"} iconName={"edit-paste-symbolic"}
|
||||||
visible={variableToBoolean(accessMediaUrl(player.get()))}
|
visible={variableToBoolean(accessMediaUrl(player.get()))}
|
||||||
tooltipText={"Copy link to Clipboard"} onClicked={() => {
|
tooltipText={tr("copy_to_clipboard")} onClicked={() => {
|
||||||
const url = accessMediaUrl(player.get()).get();
|
const url = accessMediaUrl(player.get()).get();
|
||||||
url && Clipboard.getDefault().copyAsync(url);
|
url && Clipboard.getDefault().copyAsync(url);
|
||||||
}}
|
}}
|
||||||
@@ -92,20 +93,21 @@ export const Media = () => {
|
|||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
<Gtk.Box class={"media-controls button-row"}>
|
<Gtk.Box class={"media-controls button-row"}>
|
||||||
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
|
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
|
||||||
tooltipText={"Previous"} onClicked={() =>
|
tooltipText={tr("media.previous")} onClicked={() =>
|
||||||
player.get().canGoPrevious && player.get().previous()}
|
player.get().canGoPrevious && player.get().previous()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"play-pause"} iconName={createBinding(player.get(), "playbackStatus").as(status =>
|
<Gtk.Button class={"play-pause"} iconName={createBinding(player.get(), "playbackStatus").as(status =>
|
||||||
status === AstalMpris.PlaybackStatus.PAUSED ?
|
status === AstalMpris.PlaybackStatus.PAUSED ?
|
||||||
"media-playback-start-symbolic"
|
"media-playback-start-symbolic"
|
||||||
: "media-playback-pause-symbolic")}
|
: "media-playback-pause-symbolic")}
|
||||||
tooltipText={
|
tooltipText={createBinding(player.get(), "playbackStatus").as(status =>
|
||||||
createBinding(player.get(), "playbackStatus").as(status =>
|
status === AstalMpris.PlaybackStatus.PAUSED ?
|
||||||
status === AstalMpris.PlaybackStatus.PAUSED ? "Play" : "Pause")
|
tr("media.play")
|
||||||
} onClicked={() => player.get().play_pause()}
|
: tr("media.pause")
|
||||||
|
)} onClicked={() => player.get().play_pause()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
|
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
|
||||||
tooltipText={"Next"} onClicked={() => player.get().canGoNext &&
|
tooltipText={tr("media.next")} onClicked={() => player.get().canGoNext &&
|
||||||
player.get().next()}
|
player.get().next()}
|
||||||
/>
|
/>
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Clipboard } from "../../../modules/clipboard";
|
|||||||
import { accessMediaUrl } from "../../../modules/media";
|
import { accessMediaUrl } from "../../../modules/media";
|
||||||
import { player, setPlayer } from "../../../modules/media";
|
import { player, setPlayer } from "../../../modules/media";
|
||||||
import { pathToURI, variableToBoolean } from "../../../modules/utils";
|
import { pathToURI, variableToBoolean } from "../../../modules/utils";
|
||||||
|
import { tr } from "../../../i18n/intl";
|
||||||
|
|
||||||
import AstalMpris from "gi://AstalMpris";
|
import AstalMpris from "gi://AstalMpris";
|
||||||
import Pango from "gi://Pango?version=1.0";
|
import Pango from "gi://Pango?version=1.0";
|
||||||
@@ -31,7 +32,7 @@ export const BigMedia = () => {
|
|||||||
</For>
|
</For>
|
||||||
</Adw.Carousel> as Adw.Carousel;
|
</Adw.Carousel> as Adw.Carousel;
|
||||||
|
|
||||||
return <Gtk.Box class={"big-media"} orientation={Gtk.Orientation.VERTICAL} widthRequest={255}
|
return <Gtk.Box class={"big-media"} orientation={Gtk.Orientation.VERTICAL} widthRequest={270}
|
||||||
visible={variableToBoolean(availablePlayers)}>
|
visible={variableToBoolean(availablePlayers)}>
|
||||||
|
|
||||||
{carousel}
|
{carousel}
|
||||||
@@ -75,15 +76,15 @@ class PlayerWidget extends Gtk.Box {
|
|||||||
valign={Gtk.Align.CENTER} vexpand hexpand>
|
valign={Gtk.Align.CENTER} vexpand hexpand>
|
||||||
|
|
||||||
<Gtk.Label class={"title"} tooltipText={
|
<Gtk.Label class={"title"} tooltipText={
|
||||||
createBinding(player, "title").as(title => title ?? "No Title")
|
createBinding(player, "title").as(title => title ?? tr("media.no_title"))
|
||||||
} label={
|
} label={
|
||||||
createBinding(player, "title").as(title => title ?? "No Title")
|
createBinding(player, "title").as(title => title ?? tr("media.no_title"))
|
||||||
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25}
|
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25}
|
||||||
/>
|
/>
|
||||||
<Gtk.Label class={"artist"} tooltipText={
|
<Gtk.Label class={"artist"} tooltipText={
|
||||||
createBinding(player, "artist").as(artist => artist ?? "No Artist")
|
createBinding(player, "artist").as(artist => artist ?? tr("media.no_artist"))
|
||||||
} label={
|
} label={
|
||||||
createBinding(player, "artist").as(artist => artist ?? "No Artist")
|
createBinding(player, "artist").as(artist => artist ?? tr("media.no_artist"))
|
||||||
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28}
|
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28}
|
||||||
/>
|
/>
|
||||||
</Gtk.Box> as Gtk.Box
|
</Gtk.Box> as Gtk.Box
|
||||||
@@ -128,7 +129,7 @@ class PlayerWidget extends Gtk.Box {
|
|||||||
<Gtk.Box spacing={4} $type="center">
|
<Gtk.Box spacing={4} $type="center">
|
||||||
<Gtk.Box class={"extra button-row"}>
|
<Gtk.Box class={"extra button-row"}>
|
||||||
<Gtk.Button class={"link"}
|
<Gtk.Button class={"link"}
|
||||||
tooltipText={"Copy link to clipboard"}
|
tooltipText={tr("copy_to_clipboard")}
|
||||||
visible={variableToBoolean(accessMediaUrl(player))}
|
visible={variableToBoolean(accessMediaUrl(player))}
|
||||||
onClicked={(self) => {
|
onClicked={(self) => {
|
||||||
const url = accessMediaUrl(player).get();
|
const url = accessMediaUrl(player).get();
|
||||||
@@ -180,22 +181,22 @@ class PlayerWidget extends Gtk.Box {
|
|||||||
"media-playlist-shuffle-symbolic"
|
"media-playlist-shuffle-symbolic"
|
||||||
: "media-playlist-consecutive-symbolic")} tooltipText={
|
: "media-playlist-consecutive-symbolic")} tooltipText={
|
||||||
createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
|
createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
|
||||||
"Shuffle"
|
tr("media.shuffle")
|
||||||
: "No shuffle")} onClicked={() => player.shuffle()}
|
: tr("media.follow_order"))} onClicked={() => player.shuffle()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
|
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
|
||||||
tooltipText={"Previous"} onClicked={() => player.canGoPrevious && player.previous()}
|
tooltipText={tr("media.previous")} onClicked={() => player.canGoPrevious && player.previous()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"play-pause"} tooltipText={
|
<Gtk.Button class={"play-pause"} tooltipText={
|
||||||
createBinding(player, "playbackStatus").as(status =>
|
createBinding(player, "playbackStatus").as(status =>
|
||||||
status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play")}
|
status === AstalMpris.PlaybackStatus.PLAYING ? tr("media.pause") : tr("media.play"))}
|
||||||
iconName={createBinding(player, "playbackStatus").as(status =>
|
iconName={createBinding(player, "playbackStatus").as(status =>
|
||||||
status === AstalMpris.PlaybackStatus.PLAYING ?
|
status === AstalMpris.PlaybackStatus.PLAYING ?
|
||||||
"media-playback-pause-symbolic"
|
"media-playback-pause-symbolic"
|
||||||
: "media-playback-start-symbolic")} onClicked={() => player.play_pause()}
|
: "media-playback-start-symbolic")} onClicked={() => player.play_pause()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
|
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
|
||||||
tooltipText={"Next"} onClicked={() => player.canGoNext && player.next()}
|
tooltipText={tr("media.next")} onClicked={() => player.canGoNext && player.next()}
|
||||||
/>
|
/>
|
||||||
<Gtk.Button class={"repeat"} iconName={createBinding(player, "loopStatus").as(status => {
|
<Gtk.Button class={"repeat"} iconName={createBinding(player, "loopStatus").as(status => {
|
||||||
if(status === AstalMpris.Loop.TRACK)
|
if(status === AstalMpris.Loop.TRACK)
|
||||||
@@ -209,12 +210,12 @@ class PlayerWidget extends Gtk.Box {
|
|||||||
status !== AstalMpris.Loop.UNSUPPORTED)}
|
status !== AstalMpris.Loop.UNSUPPORTED)}
|
||||||
tooltipText={createBinding(player, "loopStatus").as(status => {
|
tooltipText={createBinding(player, "loopStatus").as(status => {
|
||||||
if(status === AstalMpris.Loop.TRACK)
|
if(status === AstalMpris.Loop.TRACK)
|
||||||
return "Loop song";
|
return tr("media.song_loop");
|
||||||
|
|
||||||
if(status === AstalMpris.Loop.PLAYLIST)
|
if(status === AstalMpris.Loop.PLAYLIST)
|
||||||
return "Loop playlist";
|
return tr("media.loop");
|
||||||
|
|
||||||
return "No loop";
|
return tr("media.no_loop");
|
||||||
})} onClicked={() => player.loop()}
|
})} onClicked={() => player.loop()}
|
||||||
/>
|
/>
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"types": [
|
"types": [
|
||||||
"./@girs"
|
"./@types"
|
||||||
],
|
],
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|||||||
Reference in New Issue
Block a user