Feat: Added a configuration option to define the save location of recordings.
* Add file picker for saving screen recordings Implemented a file picker using Zenity to allow users to choose the save location for their screen recordings after stopping. Replaced the hardcoded save path with dynamic user input. Improved the notification system to inform users when recordings are saved or discarded. * Refactored RecordingButton to fetch the latest recording path dynamically. Removed static path references, ensuring the updated path from Hyprpanel config is always used. * Update screen_record.sh Added comment why use "sleep 1" at line 80 * Update module.nix Updated nix module. * Expand ~ in output directory, set default path, and add validation - Properly expand `~` to `$HOME` in the output directory path. - Set default recording directory to `$HOME/Videos` if none is provided. - Validate that the output directory exists before starting a recording. * Update scripts/screen_record.sh Co-authored-by: Chase Taylor <11805686+dotaxis@users.noreply.github.com> * Update scripts/screen_record.sh Co-authored-by: Chase Taylor <11805686+dotaxis@users.noreply.github.com> * Code Quality Check. * Update RecordingButton.tsx Removed debug logs as well. * Update src/components/menus/dashboard/shortcuts/buttons/RecordingButton.tsx Co-authored-by: Jas Singh <jaskiratpal.singh@outlook.com> * updated RecordingButton.tsx && helper.tsx Fixed the issues pointed by @Jas-SinghFSU * Update RecordingButton.tsx Fixed few linter errors. --------- Co-authored-by: Chase Taylor <11805686+dotaxis@users.noreply.github.com> Co-authored-by: Jas Singh <jaskiratpal.singh@outlook.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { bind, execAsync, Variable } from 'astal';
|
||||
import { bind, Variable } from 'astal';
|
||||
import { App, Gdk, Gtk } from 'astal/gtk3';
|
||||
import Menu from 'src/components/shared/Menu';
|
||||
import MenuItem from 'src/components/shared/MenuItem';
|
||||
import { isRecording } from '../helpers';
|
||||
import { isRecording, getRecordingPath, executeCommand } from '../helpers';
|
||||
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
|
||||
|
||||
const hyprlandService = AstalHyprland.get_default();
|
||||
@@ -10,44 +10,41 @@ const hyprlandService = AstalHyprland.get_default();
|
||||
const MonitorListDropdown = (): JSX.Element => {
|
||||
const monitorList: Variable<AstalHyprland.Monitor[]> = Variable([]);
|
||||
|
||||
const monitorBinding = Variable.derive([bind(hyprlandService, 'monitors')], () =>
|
||||
monitorList.set(hyprlandService.get_monitors()),
|
||||
);
|
||||
const monitorBinding = Variable.derive([bind(hyprlandService, 'monitors')], () => {
|
||||
monitorList.set(hyprlandService.get_monitors());
|
||||
});
|
||||
|
||||
return (
|
||||
<Menu className={'dropdown recording'} halign={Gtk.Align.FILL} onDestroy={() => monitorBinding.drop()} hexpand>
|
||||
{bind(monitorList).as((monitors) => {
|
||||
return monitors.map((monitor) => (
|
||||
<MenuItem
|
||||
label={`Display ${monitor.name}`}
|
||||
onButtonPressEvent={(_, event) => {
|
||||
const buttonClicked = event.get_button()[1];
|
||||
{bind(monitorList).as((monitors) =>
|
||||
monitors.map((monitor) => {
|
||||
const sanitizedPath = getRecordingPath().replace(/"/g, '\\"');
|
||||
|
||||
if (buttonClicked !== Gdk.BUTTON_PRIMARY) {
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<MenuItem
|
||||
label={`Display ${monitor.name}`}
|
||||
onButtonPressEvent={(_, event) => {
|
||||
if (event.get_button()[1] !== Gdk.BUTTON_PRIMARY) return;
|
||||
|
||||
App.get_window('dashboardmenu')?.set_visible(false);
|
||||
App.get_window('dashboardmenu')?.set_visible(false);
|
||||
|
||||
execAsync(`${SRC_DIR}/scripts/screen_record.sh start screen ${monitor.name}`).catch((err) =>
|
||||
console.error(err),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
));
|
||||
})}
|
||||
const command = `${SRC_DIR}/scripts/screen_record.sh start screen "${monitor.name}" "${sanitizedPath}"`;
|
||||
executeCommand(command);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
)}
|
||||
<MenuItem
|
||||
label="Region"
|
||||
onButtonPressEvent={(_, event) => {
|
||||
const buttonClicked = event.get_button()[1];
|
||||
|
||||
if (buttonClicked !== Gdk.BUTTON_PRIMARY) {
|
||||
return;
|
||||
}
|
||||
if (event.get_button()[1] !== Gdk.BUTTON_PRIMARY) return;
|
||||
|
||||
App.get_window('dashboardmenu')?.set_visible(false);
|
||||
|
||||
execAsync(`${SRC_DIR}/scripts/screen_record.sh start region`).catch((err) => console.error(err));
|
||||
const sanitizedPath = getRecordingPath().replace(/"/g, '\\"');
|
||||
const command = `${SRC_DIR}/scripts/screen_record.sh start region "${sanitizedPath}"`;
|
||||
executeCommand(command);
|
||||
}}
|
||||
/>
|
||||
</Menu>
|
||||
@@ -58,7 +55,7 @@ export const RecordingButton = (): JSX.Element => {
|
||||
return (
|
||||
<button
|
||||
className={`dashboard-button record ${isRecording.get() ? 'active' : ''}`}
|
||||
tooltipText={'Record Screen'}
|
||||
tooltipText="Record Screen"
|
||||
vexpand
|
||||
onButtonPressEvent={(_, event) => {
|
||||
const buttonClicked = event.get_button()[1];
|
||||
@@ -67,9 +64,12 @@ export const RecordingButton = (): JSX.Element => {
|
||||
return;
|
||||
}
|
||||
|
||||
const sanitizedPath = getRecordingPath().replace(/"/g, '\\"');
|
||||
|
||||
if (isRecording.get() === true) {
|
||||
App.get_window('dashboardmenu')?.set_visible(false);
|
||||
return execAsync(`${SRC_DIR}/scripts/screen_record.sh stop`).catch((err) => console.error(err));
|
||||
const command = `${SRC_DIR}/scripts/screen_record.sh stop "${sanitizedPath}"`;
|
||||
executeCommand(command);
|
||||
} else {
|
||||
const monitorDropdownList = MonitorListDropdown() as Gtk.Menu;
|
||||
monitorDropdownList.popup_at_pointer(event);
|
||||
|
||||
@@ -6,6 +6,27 @@ import options from 'src/options';
|
||||
|
||||
const { left } = options.menus.dashboard.shortcuts;
|
||||
|
||||
/**
|
||||
* Retrieves the latest recording path from options.
|
||||
*
|
||||
* @returns The configured recording path.
|
||||
*/
|
||||
export const getRecordingPath = (): string => options.menus.dashboard.recording.path.get();
|
||||
|
||||
/**
|
||||
* Executes a shell command asynchronously with proper error handling.
|
||||
*
|
||||
* @param command The command to execute.
|
||||
*/
|
||||
export const executeCommand = async (command: string): Promise<void> => {
|
||||
try {
|
||||
await execAsync(`/bin/bash -c '${command}'`);
|
||||
} catch (err) {
|
||||
console.error('Command failed:', command);
|
||||
console.error('Error:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the recorder status based on the command output.
|
||||
*
|
||||
@@ -16,10 +37,7 @@ const { left } = options.menus.dashboard.shortcuts;
|
||||
* @returns True if the command output is 'recording', false otherwise.
|
||||
*/
|
||||
export const handleRecorder = (commandOutput: string): boolean => {
|
||||
if (commandOutput === 'recording') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return commandOutput === 'recording';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -35,9 +53,7 @@ export const handleClick = (action: string, tOut: number = 0): void => {
|
||||
|
||||
timeout(tOut, () => {
|
||||
execAsync(`bash -c "${action}"`)
|
||||
.then((res) => {
|
||||
return res;
|
||||
})
|
||||
.then((res) => res)
|
||||
.catch((err) => console.error(err));
|
||||
});
|
||||
};
|
||||
@@ -45,10 +61,7 @@ export const handleClick = (action: string, tOut: number = 0): void => {
|
||||
/**
|
||||
* Checks if a shortcut has a command.
|
||||
*
|
||||
* This function determines if the provided shortcut has a command defined.
|
||||
*
|
||||
* @param shortCut The shortcut to check.
|
||||
*
|
||||
* @returns True if the shortcut has a command, false otherwise.
|
||||
*/
|
||||
export const hasCommand = (shortCut: ShortcutVariable): boolean => {
|
||||
@@ -58,7 +71,7 @@ export const hasCommand = (shortCut: ShortcutVariable): boolean => {
|
||||
/**
|
||||
* A variable indicating whether the left card is hidden.
|
||||
*
|
||||
* This variable is set to true if none of the left shortcuts have commands defined.
|
||||
* This is set to true if none of the left shortcuts have commands.
|
||||
*/
|
||||
export const leftCardHidden = Variable(
|
||||
!(
|
||||
@@ -82,7 +95,8 @@ export const isRecording = Variable(false);
|
||||
/**
|
||||
* A poller for checking the recording status.
|
||||
*
|
||||
* This poller periodically checks the recording status by executing a bash command and updates the `isRecording` variable.
|
||||
* This poller periodically checks the recording status by executing a bash command
|
||||
* and updates the `isRecording` variable accordingly.
|
||||
*/
|
||||
export const recordingPoller = new BashPoller<boolean, []>(
|
||||
isRecording,
|
||||
|
||||
Reference in New Issue
Block a user