✨ feat(launcher): improve launcher experience with mouse tracking, application search, and visual enhancements
This commit is contained in:
19 files changed
+513
-339
No files matched your search
+163
-54
@@ -1,15 +1,15 @@
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from gi.repository import Gdk, GLib
|
||||
|
||||
from fabric.core.service import Property
|
||||
from fabric.widgets.box import Box
|
||||
from fabric.widgets.entry import Entry
|
||||
from fabric.widgets.scrolledwindow import ScrolledWindow
|
||||
from gi.repository import Gdk, GLib
|
||||
|
||||
from modules.launcher.plugin_manager import PluginManager
|
||||
from modules.launcher.result import Result
|
||||
from modules.launcher.result_item import ResultItem
|
||||
from modules.launcher.trigger_config import TriggerConfig
|
||||
from widgets.smartscrolled import SmartScrolledBox
|
||||
from widgets.wayland import WaylandWindow as Window
|
||||
|
||||
# Constants
|
||||
@@ -44,26 +44,15 @@ class Launcher(Window):
|
||||
keyboard_mode="exclusive",
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# Initialization flag to prevent callbacks during setup
|
||||
self._initializing = True
|
||||
|
||||
# Flag to prevent recursion when automatically adding spaces
|
||||
self._auto_adding_space = False
|
||||
|
||||
# Flag to prevent search change handler interference during backspace processing
|
||||
self._processing_backspace = False
|
||||
|
||||
# Initialize plugin manager
|
||||
self.plugin_manager = PluginManager()
|
||||
|
||||
# Initialize trigger configuration
|
||||
self.trigger_config = TriggerConfig()
|
||||
|
||||
# Current results and selection
|
||||
self.results: List[Result] = []
|
||||
self.selected_index = 0
|
||||
self.max_results = 8 # Spotlight typically shows fewer results
|
||||
self.max_results = 5 # Show 4 applications by default instead of list
|
||||
|
||||
# Trigger system
|
||||
self.triggered_plugin = None # Currently active triggered plugin
|
||||
@@ -75,6 +64,16 @@ class Launcher(Window):
|
||||
# Focus management
|
||||
self.focus_mode = "search" # "search", "results"
|
||||
|
||||
# Mouse activity tracking
|
||||
self._mouse_active = False
|
||||
self._last_mouse_activity = 0
|
||||
self._mouse_activity_timeout = 1000 # 1 second timeout
|
||||
self._keyboard_used_recently = False
|
||||
self._last_keyboard_activity = 0
|
||||
self._keyboard_activity_timeout = 2000 # 2 second timeout
|
||||
self._launcher_just_opened = False
|
||||
self._mouse_interaction_delay = 500 # 500ms delay after opening
|
||||
|
||||
# Setup UI
|
||||
main_box = Box(
|
||||
name="launcher",
|
||||
@@ -107,28 +106,29 @@ class Launcher(Window):
|
||||
|
||||
main_box.add(self.header_box)
|
||||
|
||||
# Results container with increased height for Spotlight-style
|
||||
self.results_scroll = ScrolledWindow(
|
||||
name="launcher-results-scroll",
|
||||
h_scrollbar_policy="never",
|
||||
min_content_size=(LAUNCHER_WIDTH, LAUNCHER_HEIGHT),
|
||||
max_content_size=(LAUNCHER_WIDTH, LAUNCHER_HEIGHT),
|
||||
propagate_width=False,
|
||||
propagate_height=False,
|
||||
)
|
||||
self.results_scroll = SmartScrolledBox(max_height=LAUNCHER_HEIGHT)
|
||||
|
||||
self.results_box = Box(
|
||||
name="launcher-results",
|
||||
orientation="v",
|
||||
spacing=0,
|
||||
)
|
||||
self.results_scroll.add(self.results_box)
|
||||
self.results_scroll.append(self.results_box)
|
||||
main_box.add(self.results_scroll)
|
||||
|
||||
# Initially hide the results container
|
||||
self.results_scroll.hide()
|
||||
# Keep the results container visible initially
|
||||
|
||||
self.connect("key-press-event", self._on_key_press)
|
||||
|
||||
# Connect mouse events to track activity
|
||||
self.results_scroll.connect("button-press-event", self._on_mouse_activity)
|
||||
self.results_scroll.connect("motion-notify-event", self._on_mouse_activity)
|
||||
self.results_scroll.connect("scroll-event", self._on_mouse_activity)
|
||||
|
||||
# Also track mouse activity on the main window for better coverage
|
||||
self.connect("button-press-event", self._on_mouse_activity)
|
||||
self.connect("motion-notify-event", self._on_mouse_activity)
|
||||
|
||||
self.hide()
|
||||
|
||||
# Mark initialization as complete
|
||||
@@ -144,6 +144,20 @@ class Launcher(Window):
|
||||
trigger_keyword: Optional trigger keyword to activate immediately (e.g., "google", "calc", "app")
|
||||
external: If True, execute the command without showing the launcher UI
|
||||
"""
|
||||
# Reset mouse activity tracking when launcher is shown
|
||||
self._mouse_active = False
|
||||
self._last_mouse_activity = 0
|
||||
self._keyboard_used_recently = False
|
||||
self._last_keyboard_activity = 0
|
||||
self._launcher_just_opened = True
|
||||
|
||||
# Schedule to allow mouse interactions after a delay
|
||||
def enable_mouse_interactions():
|
||||
self._launcher_just_opened = False
|
||||
return False
|
||||
|
||||
GLib.timeout_add(self._mouse_interaction_delay, enable_mouse_interactions)
|
||||
|
||||
if external and trigger_keyword:
|
||||
# Execute command externally without showing launcher
|
||||
return self._execute_external_command(trigger_keyword)
|
||||
@@ -180,10 +194,11 @@ class Launcher(Window):
|
||||
self.search_entry.set_text("")
|
||||
self._clear_results()
|
||||
else:
|
||||
# Normal launcher opening - clear everything
|
||||
# Normal launcher opening - show applications
|
||||
self.opened_with_trigger = False
|
||||
self.search_entry.set_text("")
|
||||
self._clear_results()
|
||||
# Trigger initial search to show applications immediately
|
||||
self._perform_search("")
|
||||
|
||||
# Reset focus mode to search
|
||||
self.focus_mode = "search"
|
||||
@@ -305,8 +320,8 @@ class Launcher(Window):
|
||||
# Debounce search to avoid too many queries
|
||||
GLib.timeout_add(SEARCH_DEBOUNCE_MS, self._perform_search, query)
|
||||
else:
|
||||
# Hide results when query is empty
|
||||
self._clear_results()
|
||||
# Show applications when query is empty
|
||||
self._perform_search("")
|
||||
|
||||
def _perform_search(self, query: str) -> bool:
|
||||
"""Perform search across all plugins."""
|
||||
@@ -315,10 +330,25 @@ class Launcher(Window):
|
||||
return False
|
||||
|
||||
if not query:
|
||||
# Empty query - reset trigger mode and hide results
|
||||
# Empty query - show popular applications
|
||||
self.triggered_plugin = None
|
||||
self.active_trigger = ""
|
||||
self._clear_results()
|
||||
|
||||
# Get applications plugin and show popular apps
|
||||
applications_plugin = self._get_applications_plugin()
|
||||
if applications_plugin:
|
||||
try:
|
||||
# Query with empty string to get popular/frequently used applications
|
||||
all_results = applications_plugin.query("")
|
||||
# Limit to max_results for empty query
|
||||
self.results = all_results[: self.max_results]
|
||||
self.selected_index = 0
|
||||
self._update_results_display()
|
||||
except Exception as e:
|
||||
print(f"Error getting applications: {e}")
|
||||
self._clear_results()
|
||||
else:
|
||||
self._clear_results()
|
||||
return False
|
||||
|
||||
# Check if we're already in trigger mode
|
||||
@@ -365,13 +395,24 @@ class Launcher(Window):
|
||||
print(f"Error in triggered plugin {triggered_plugin.name}: {e}")
|
||||
all_results = []
|
||||
else:
|
||||
# No trigger detected - only show trigger suggestions
|
||||
# No trigger detected - search applications and show trigger suggestions
|
||||
self.triggered_plugin = None
|
||||
self.active_trigger = ""
|
||||
|
||||
# Show trigger suggestions if query matches trigger prefixes
|
||||
all_results = []
|
||||
|
||||
# Search applications directly without trigger
|
||||
applications_plugin = self._get_applications_plugin()
|
||||
if applications_plugin:
|
||||
try:
|
||||
app_results = applications_plugin.query(query)
|
||||
all_results.extend(app_results)
|
||||
except Exception as e:
|
||||
print(f"Error searching applications: {e}")
|
||||
|
||||
# Also show trigger suggestions if query matches trigger prefixes
|
||||
trigger_suggestions = self._get_trigger_suggestions(query)
|
||||
all_results = trigger_suggestions
|
||||
all_results.extend(trigger_suggestions)
|
||||
|
||||
# Sort results by relevance score
|
||||
all_results.sort(key=lambda r: r.relevance, reverse=True)
|
||||
@@ -387,8 +428,19 @@ class Launcher(Window):
|
||||
# In trigger mode - show all results from the triggered plugin
|
||||
self.results = all_results
|
||||
elif not has_bypass:
|
||||
# Global search or trigger suggestions - apply max_results limit
|
||||
self.results = all_results[: self.max_results]
|
||||
# Global search - check if it's an application search
|
||||
applications_plugin = self._get_applications_plugin()
|
||||
is_application_search = applications_plugin and any(
|
||||
hasattr(r, "plugin_name") and r.plugin_name == "Applications"
|
||||
for r in all_results
|
||||
)
|
||||
|
||||
if is_application_search:
|
||||
# Don't limit application search results
|
||||
self.results = all_results
|
||||
else:
|
||||
# Apply max_results limit for other global searches and trigger suggestions
|
||||
self.results = all_results[: self.max_results]
|
||||
else:
|
||||
# Has bypass flag - show all results
|
||||
self.results = all_results
|
||||
@@ -462,6 +514,16 @@ class Launcher(Window):
|
||||
|
||||
return None, ""
|
||||
|
||||
def _get_applications_plugin(self):
|
||||
"""Get the applications plugin instance."""
|
||||
for plugin in self.plugin_manager.get_active_plugins():
|
||||
if (
|
||||
hasattr(plugin, "display_name")
|
||||
and plugin.display_name == "Applications"
|
||||
):
|
||||
return plugin
|
||||
return None
|
||||
|
||||
def _get_trigger_suggestions(self, query: str) -> List[Result]:
|
||||
"""
|
||||
Get trigger suggestions based on the current query.
|
||||
@@ -515,7 +577,7 @@ class Launcher(Window):
|
||||
return Result(
|
||||
title=f"{trigger_clean}",
|
||||
subtitle=f"{description} - {', '.join(examples[:max_examples])}",
|
||||
icon_markup=icon_name,
|
||||
icon_name=icon_name,
|
||||
action=lambda t=trigger_clean: self._activate_trigger(t),
|
||||
# Shorter triggers get higher relevance
|
||||
relevance=100 - len(trigger_clean),
|
||||
@@ -678,11 +740,11 @@ class Launcher(Window):
|
||||
|
||||
self.results_box.show_all()
|
||||
|
||||
# Show/hide scroll container based on results
|
||||
if self.results:
|
||||
self.results_scroll.show()
|
||||
else:
|
||||
self.results_scroll.hide()
|
||||
# Force height constraints after adding results
|
||||
self.results_scroll.force_height_constraint()
|
||||
|
||||
# Always show scroll container
|
||||
self.results_scroll.show()
|
||||
|
||||
def _update_input_action_text(self):
|
||||
"""Update the input field with action text (Spotlight-style)."""
|
||||
@@ -716,8 +778,6 @@ class Launcher(Window):
|
||||
# Not in trigger mode - show Spotlight-style help
|
||||
if current_text == ":":
|
||||
self.search_entry.set_placeholder_text("Available search triggers")
|
||||
elif current_text:
|
||||
self.search_entry.set_placeholder_text("Spotlight Search")
|
||||
else:
|
||||
self.search_entry.set_placeholder_text("Spotlight Search")
|
||||
|
||||
@@ -727,7 +787,7 @@ class Launcher(Window):
|
||||
self.selected_index = 0
|
||||
for child in self.results_box.get_children():
|
||||
self.results_box.remove(child)
|
||||
self.results_scroll.hide()
|
||||
# Keep the results scroll visible even when empty
|
||||
|
||||
def _handle_escape_key(self) -> bool:
|
||||
"""Handle escape key press."""
|
||||
@@ -816,6 +876,13 @@ class Launcher(Window):
|
||||
|
||||
def _on_key_press(self, _widget, event):
|
||||
"""Handle key press events."""
|
||||
# Track keyboard activity
|
||||
import time
|
||||
|
||||
current_time = int(time.time() * 1000)
|
||||
self._last_keyboard_activity = current_time
|
||||
self._keyboard_used_recently = True
|
||||
|
||||
keyval = event.keyval
|
||||
|
||||
# Escape - handle password entry, exit trigger mode, or hide launcher
|
||||
@@ -1011,16 +1078,58 @@ class Launcher(Window):
|
||||
|
||||
def _on_result_clicked(self, _result_item, index):
|
||||
"""Handle result item click."""
|
||||
self.selected_index = index
|
||||
self._activate_selected()
|
||||
# Only allow clicks when mouse is active or keyboard hasn't been used recently
|
||||
if self._should_allow_mouse_interaction():
|
||||
self.selected_index = index
|
||||
self._activate_selected()
|
||||
|
||||
def _on_result_hovered(self, index):
|
||||
"""Handle result item hover."""
|
||||
# Update selection when mouse hovers over a result (without scrolling)
|
||||
if 0 <= index < len(self.results):
|
||||
self.selected_index = index
|
||||
self.focus_mode = "results" # Switch to results focus mode
|
||||
self._update_selection_visual_only()
|
||||
# Only allow hover selection when mouse is active and keyboard hasn't been used recently
|
||||
if self._should_allow_mouse_interaction():
|
||||
if 0 <= index < len(self.results):
|
||||
self.selected_index = index
|
||||
self.focus_mode = "results" # Switch to results focus mode
|
||||
self._update_selection_visual_only()
|
||||
|
||||
def _on_mouse_activity(self, widget, event):
|
||||
"""Track mouse activity to determine when mouse interactions should be enabled."""
|
||||
import time
|
||||
|
||||
current_time = int(time.time() * 1000)
|
||||
self._last_mouse_activity = current_time
|
||||
self._mouse_active = True
|
||||
|
||||
# Schedule a check to disable mouse activity after timeout
|
||||
def check_mouse_timeout():
|
||||
if current_time - self._last_mouse_activity >= self._mouse_activity_timeout:
|
||||
self._mouse_active = False
|
||||
return False
|
||||
|
||||
GLib.timeout_add(self._mouse_activity_timeout, check_mouse_timeout)
|
||||
return False
|
||||
|
||||
def _should_allow_mouse_interaction(self):
|
||||
"""Determine if mouse interactions should be allowed."""
|
||||
import time
|
||||
|
||||
current_time = int(time.time() * 1000)
|
||||
|
||||
# Don't allow mouse interactions immediately after launcher opens
|
||||
if self._launcher_just_opened:
|
||||
return False
|
||||
|
||||
# Allow mouse interaction if:
|
||||
# 1. Mouse is currently active (recent activity)
|
||||
# 2. OR keyboard hasn't been used recently (2 seconds)
|
||||
mouse_recently_active = (
|
||||
current_time - self._last_mouse_activity
|
||||
) < self._mouse_activity_timeout
|
||||
keyboard_not_recently_used = (
|
||||
current_time - self._last_keyboard_activity
|
||||
) > self._keyboard_activity_timeout
|
||||
|
||||
return mouse_recently_active or keyboard_not_recently_used
|
||||
|
||||
def _is_mouse_over_results(self):
|
||||
"""Check if mouse is over the results area."""
|
||||
|
||||
@@ -4,7 +4,6 @@ from typing import List
|
||||
|
||||
from fabric.utils import DesktopApp
|
||||
from fabric.utils.helpers import get_desktop_applications, get_relative_path
|
||||
|
||||
from modules.dock import Dock
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
@@ -17,8 +16,7 @@ class ApplicationsPlugin(PluginBase):
|
||||
self.description = "Search and launch desktop applications"
|
||||
|
||||
def initialize(self):
|
||||
# Set up triggers for applications - both with and without spaces
|
||||
self.set_triggers(["app"])
|
||||
pass
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
@@ -71,9 +69,8 @@ class ApplicationsPlugin(PluginBase):
|
||||
def query(self, query_string: str) -> List[Result]:
|
||||
"""Search applications based on query."""
|
||||
if not query_string.strip():
|
||||
return []
|
||||
return self._get_all_applications()
|
||||
|
||||
# Get fresh applications list each time (like examples/app-launcher)
|
||||
try:
|
||||
applications = get_desktop_applications(include_hidden=False)
|
||||
except Exception as e:
|
||||
@@ -86,9 +83,8 @@ class ApplicationsPlugin(PluginBase):
|
||||
for app in applications:
|
||||
relevance = self._calculate_relevance(app, query)
|
||||
if relevance > 0:
|
||||
# Truncate description to prevent overflow beyond 550px window
|
||||
description = app.description or app.generic_name or ""
|
||||
if len(description) > 80: # Limit to ~80 characters to fit in 550px
|
||||
if len(description) > 80:
|
||||
description = description[:70] + "..."
|
||||
|
||||
result = Result(
|
||||
@@ -161,3 +157,35 @@ class ApplicationsPlugin(PluginBase):
|
||||
|
||||
def _launch_application(self, app: DesktopApp):
|
||||
app.launch()
|
||||
|
||||
def _get_all_applications(self) -> List[Result]:
|
||||
"""Get a list of all available applications."""
|
||||
try:
|
||||
applications = get_desktop_applications(include_hidden=False)
|
||||
except Exception as e:
|
||||
print(f"Failed to load applications: {e}")
|
||||
return []
|
||||
|
||||
results = []
|
||||
|
||||
for app in applications:
|
||||
# Truncate description
|
||||
description = app.description or app.generic_name or ""
|
||||
if len(description) > 80:
|
||||
description = description[:70] + "..."
|
||||
|
||||
result = Result(
|
||||
title=app.display_name or app.name,
|
||||
subtitle=description,
|
||||
icon=app.get_icon_pixbuf(size=48),
|
||||
action=lambda a=app: self._launch_application(a),
|
||||
relevance=0.5, # Default relevance for all apps
|
||||
plugin_name=self.display_name,
|
||||
data={
|
||||
"app": app,
|
||||
"pin_action": lambda a=app: self._pin_application(a),
|
||||
},
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
return results
|
||||
@@ -4,10 +4,8 @@ import threading
|
||||
import time
|
||||
from typing import Dict, List
|
||||
|
||||
from fabric.utils import exec_shell_command_async
|
||||
|
||||
import config.data as data
|
||||
import utils.icons as icons
|
||||
from fabric.utils import exec_shell_command_async
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -38,17 +36,17 @@ class BashScriptsPlugin(PluginBase):
|
||||
"pm balanced": {
|
||||
"description": "Switch to balanced power profile",
|
||||
"profile": "balanced",
|
||||
"icon": icons.power_balanced,
|
||||
"icon": "power-balanced",
|
||||
},
|
||||
"pm performance": {
|
||||
"description": "Switch to performance power profile",
|
||||
"profile": "performance",
|
||||
"icon": icons.power_performance,
|
||||
"icon": "power-performance",
|
||||
},
|
||||
"pm saver": {
|
||||
"description": "Switch to power saver profile",
|
||||
"profile": "power-saver",
|
||||
"icon": icons.power_saving,
|
||||
"icon": "power-saving",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -134,12 +132,16 @@ class BashScriptsPlugin(PluginBase):
|
||||
if actual_profile:
|
||||
self._battery_service._profile_proxy.ActiveProfile = actual_profile
|
||||
print(
|
||||
f"BashScriptsPlugin: Successfully set power profile to {actual_profile}"
|
||||
f"BashScriptsPlugin: Successfully set power profile to {
|
||||
actual_profile
|
||||
}"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
print(
|
||||
f"BashScriptsPlugin: No matching profile found for '{profile}' in available profiles: {available_profiles}"
|
||||
f"BashScriptsPlugin: No matching profile found for '{
|
||||
profile
|
||||
}' in available profiles: {available_profiles}"
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -186,7 +188,6 @@ class BashScriptsPlugin(PluginBase):
|
||||
current_time - self._last_cache_update > self._cache_update_interval
|
||||
or not self._scripts_cache
|
||||
):
|
||||
|
||||
if not self._cache_building:
|
||||
self._cache_building = True
|
||||
self._cache_thread = threading.Thread(
|
||||
@@ -197,7 +198,6 @@ class BashScriptsPlugin(PluginBase):
|
||||
def _build_scripts_cache_background(self):
|
||||
"""Build scripts cache in background thread."""
|
||||
try:
|
||||
|
||||
new_cache = {}
|
||||
|
||||
# Scan Modus scripts directory for discovered scripts
|
||||
@@ -208,7 +208,9 @@ class BashScriptsPlugin(PluginBase):
|
||||
self._scan_directory_for_scripts(self.modus_scripts_dir, new_cache)
|
||||
except (PermissionError, FileNotFoundError, OSError) as e:
|
||||
print(
|
||||
f"BashScriptsPlugin: Error scanning Modus scripts directory: {e}"
|
||||
f"BashScriptsPlugin: Error scanning Modus scripts directory: {
|
||||
e
|
||||
}"
|
||||
)
|
||||
|
||||
# Update cache atomically
|
||||
@@ -423,13 +425,12 @@ class BashScriptsPlugin(PluginBase):
|
||||
or query_lower in cmd_lower
|
||||
or query_lower in description_lower
|
||||
):
|
||||
|
||||
relevance = 1.0 if query_lower == cmd_lower else 0.9
|
||||
|
||||
result = Result(
|
||||
title=cmd,
|
||||
subtitle=info["description"],
|
||||
icon_markup=info["icon"],
|
||||
icon_name=info["icon"],
|
||||
action=self._create_power_action(info["profile"]),
|
||||
relevance=relevance,
|
||||
plugin_name=self.display_name,
|
||||
@@ -451,7 +452,7 @@ class BashScriptsPlugin(PluginBase):
|
||||
result = Result(
|
||||
title=cmd,
|
||||
subtitle=info["description"],
|
||||
icon_markup=info["icon"],
|
||||
icon_name=info["icon"],
|
||||
action=self._create_power_action(info["profile"]),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -473,9 +474,10 @@ class BashScriptsPlugin(PluginBase):
|
||||
if success:
|
||||
# Clear the search query after successful execution
|
||||
try:
|
||||
from fabric import Application
|
||||
from gi.repository import GLib
|
||||
|
||||
from fabric import Application
|
||||
|
||||
app = Application.get_default()
|
||||
if app and hasattr(app, "launcher"):
|
||||
launcher = app.launcher
|
||||
@@ -517,16 +519,16 @@ class BashScriptsPlugin(PluginBase):
|
||||
|
||||
# Choose icon based on script type and status
|
||||
if not executable:
|
||||
icon_markup = icons.file
|
||||
icon_name = "gtk-file"
|
||||
elif script_type == "custom":
|
||||
icon_markup = icons.star
|
||||
icon_name = "folder-script-symbolic"
|
||||
else:
|
||||
icon_markup = icons.terminal
|
||||
icon_name = "terminalc"
|
||||
|
||||
return Result(
|
||||
title=script_name,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icon_markup,
|
||||
icon_name=icon_name,
|
||||
action=self._create_script_action(script_name, script_info),
|
||||
relevance=relevance,
|
||||
plugin_name=self.display_name,
|
||||
@@ -556,7 +558,7 @@ class BashScriptsPlugin(PluginBase):
|
||||
variant_result = Result(
|
||||
title=f"{script_name} {arg}",
|
||||
subtitle=f"{desc} | [scripts]",
|
||||
icon_markup=icons.terminal,
|
||||
icon_name="terminal-symbolic",
|
||||
action=self._create_script_action_with_args(
|
||||
script_name, script_info, [arg]
|
||||
),
|
||||
|
||||
@@ -6,10 +6,9 @@ from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from fabric.utils.helpers import get_relative_path
|
||||
from thefuzz import fuzz
|
||||
|
||||
import utils.icons as icons
|
||||
from fabric.utils.helpers import get_relative_path
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -268,7 +267,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="No Bookmarks Found",
|
||||
subtitle="Use 'add <title> <url>' to add first bookmark",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -298,7 +297,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="No Bookmarks Yet",
|
||||
subtitle="Use 'add <title> <url>' to add first bookmark",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -307,7 +306,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Example: Add Google",
|
||||
subtitle="add Google https://google.com",
|
||||
icon_markup=icons.bulb,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -334,7 +333,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Add Bookmark",
|
||||
subtitle="Usage: add <title> <url> [description]",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -343,7 +342,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Example",
|
||||
subtitle="add Google https://google.com Search engine",
|
||||
icon_markup=icons.bulb,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -358,7 +357,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid Format",
|
||||
subtitle="Usage: add <title> <url> [description]",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -387,7 +386,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Bookmark Already Exists",
|
||||
subtitle=f"URL '{display_url}' already exists",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -407,7 +406,7 @@ class BookmarksPlugin(PluginBase):
|
||||
# Truncate description to prevent launcher resize
|
||||
max_desc_len = 35 - len(domain) # Account for domain + separator
|
||||
if len(description) > max_desc_len:
|
||||
description = description[:max_desc_len-3] + "..."
|
||||
description = description[: max_desc_len - 3] + "..."
|
||||
subtitle += f" • {description}"
|
||||
|
||||
# Truncate title for display
|
||||
@@ -419,7 +418,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Add bookmark '{display_title}'",
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.plus,
|
||||
icon_name="plus",
|
||||
action=lambda: self._add_bookmark_action(title, url, description),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -451,7 +450,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Bookmark Not Found",
|
||||
subtitle=f"No bookmark found matching '{identifier}'",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -477,7 +476,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Remove '{display_title}'?",
|
||||
subtitle=f"Click to confirm: {display_domain}",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="trash",
|
||||
action=lambda: self._remove_bookmark_action(identifier),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -492,7 +491,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Remove Bookmark",
|
||||
subtitle="Usage: remove <title|url|domain>",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -506,7 +505,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title="Available Bookmarks:",
|
||||
subtitle=f"{len(bookmarks)} bookmarks available to remove",
|
||||
icon_markup=icons.bookmark,
|
||||
icon_name="bookmarks-organize",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -532,7 +531,7 @@ class BookmarksPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"remove {display_title}",
|
||||
subtitle=f"Click to remove: {display_title} ({display_domain})",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="trash",
|
||||
action=lambda t=title: self._remove_bookmark_action(t),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -643,9 +642,10 @@ class BookmarksPlugin(PluginBase):
|
||||
|
||||
if description:
|
||||
# Truncate description to prevent launcher resize
|
||||
max_desc_len = 50 - len(domain) # Account for domain + separator
|
||||
# Account for domain + separator
|
||||
max_desc_len = 50 - len(domain)
|
||||
if len(description) > max_desc_len:
|
||||
description = description[:max_desc_len-3] + "..."
|
||||
description = description[: max_desc_len - 3] + "..."
|
||||
subtitle = f"{domain} • {description}"
|
||||
else:
|
||||
subtitle = domain
|
||||
@@ -657,7 +657,7 @@ class BookmarksPlugin(PluginBase):
|
||||
return Result(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.bookmark,
|
||||
icon_name="bookmark-organize",
|
||||
action=lambda u=url: self._open_bookmark(u),
|
||||
relevance=relevance,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -3,11 +3,10 @@ from threading import Timer
|
||||
from typing import List
|
||||
|
||||
import gi
|
||||
from fabric.utils import get_relative_path
|
||||
from fabric.utils.helpers import exec_shell_command_async
|
||||
|
||||
import config.data as data
|
||||
import utils.icons as icons
|
||||
from fabric.utils import get_relative_path
|
||||
from fabric.utils.helpers import exec_shell_command_async
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -173,7 +172,7 @@ class CaffeinePlugin(PluginBase):
|
||||
result = Result(
|
||||
title=f"Custom: {query}",
|
||||
subtitle="Set custom duration",
|
||||
icon_markup=icons.coffee,
|
||||
icon_name="caffeine",
|
||||
action=self._create_inhibit_action(query),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -194,7 +193,7 @@ class CaffeinePlugin(PluginBase):
|
||||
result = Result(
|
||||
title=description,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.coffee,
|
||||
icon_name="caffeine",
|
||||
action=self._create_inhibit_action(duration),
|
||||
relevance=0.9 if query == duration else 0.7,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -4,7 +4,6 @@ import subprocess
|
||||
import time
|
||||
from typing import List
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
from utils.conversion import Conversion
|
||||
@@ -99,7 +98,7 @@ class CalculatorPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"{result:.6g} {to_unit}",
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.calculator,
|
||||
icon_name="calculator-symbolic",
|
||||
action=lambda r=f"{result:.6g}": self._copy_to_clipboard(r),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -111,7 +110,7 @@ class CalculatorPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid conversion",
|
||||
subtitle=str(e),
|
||||
icon_markup=icons.calculator,
|
||||
icon_name="calculator-symbolic",
|
||||
relevance=0.0,
|
||||
plugin_name=self.display_name,
|
||||
)
|
||||
@@ -127,7 +126,7 @@ class CalculatorPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"{result:.6g}",
|
||||
subtitle=f"{query} = {result:.6g}",
|
||||
icon_markup=icons.calculator,
|
||||
icon_name="calculator-symbolic",
|
||||
action=lambda r=f"{result:.6g}": self._copy_to_clipboard(r),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -5,9 +5,8 @@ import time
|
||||
from collections import OrderedDict
|
||||
from typing import Dict, List
|
||||
|
||||
from fabric.utils import get_relative_path
|
||||
|
||||
import config.data as data
|
||||
from fabric.utils import get_relative_path
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from fabric.utils import get_relative_path
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
from services.auth import (
|
||||
@@ -354,7 +352,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid format",
|
||||
subtitle="Usage: add <account_name> <secret> or add <account_name>```<secret>```",
|
||||
icon_markup=icons.question,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -373,7 +371,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Error adding account",
|
||||
subtitle=f"Debug: {str(e)}",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="cancel",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -390,7 +388,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="No OTP accounts configured",
|
||||
subtitle="Use 'add <account> <secret>' to add your first account",
|
||||
icon_markup=icons.key,
|
||||
icon_name="gtk-authentication-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -401,7 +399,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Available commands:",
|
||||
subtitle="add <account> <secret> | remove <account> | qr <account>",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -425,7 +423,7 @@ class OTPPlugin(PluginBase):
|
||||
subtitle_markup=f"{display_name} • {
|
||||
time_display
|
||||
} remaining • Shift+Enter: remove",
|
||||
icon_markup=icons.key,
|
||||
icon_name="gtk-authentication-symbolic",
|
||||
action=lambda code=totp_code: self._copy_to_clipboard(code),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -444,7 +442,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Error: {account_name}",
|
||||
subtitle="Invalid secret or configuration",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="dialog-cancel-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -485,7 +483,7 @@ class OTPPlugin(PluginBase):
|
||||
subtitle_markup=f"{display_name} • {
|
||||
time_display
|
||||
} remaining • Shift+Enter: remove",
|
||||
icon_markup=icons.key,
|
||||
icon_name="gtk-authentication-symbolic",
|
||||
action=lambda code=totp_code: self._copy_to_clipboard(code),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -505,7 +503,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"No accounts found for '{query}'",
|
||||
subtitle="Use 'add <account> <secret>' to create new account",
|
||||
icon_markup=icons.magnifier,
|
||||
icon_name="edit-find-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -516,7 +514,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Available commands:",
|
||||
subtitle="add <account> <secret> | remove <account> | qr <account>",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.4,
|
||||
plugin_name=self.display_name,
|
||||
@@ -533,7 +531,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Enter account name",
|
||||
subtitle="Usage: add <account_name> <secret>",
|
||||
icon_markup=icons.question,
|
||||
icon_name="dialog-question-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -545,7 +543,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"To add '{account_name}':",
|
||||
subtitle=f"Type: add {account_name} <secret>",
|
||||
icon_markup=icons.bulb,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -558,7 +556,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Base32 Secret Format:",
|
||||
subtitle="Example: add gmail JBSWY3DPEHPK3PXP",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -567,7 +565,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="otpauth URI Format:",
|
||||
subtitle="Example: add github otpauth://totp/GitHub:user?secret=JBSWY3DPEHPK3PXP",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -576,7 +574,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Remove Account:",
|
||||
subtitle="Example: remove gmail",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="trash",
|
||||
action=lambda: None,
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -591,7 +589,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Scan QR Code",
|
||||
subtitle="Click to scan QR code from screen",
|
||||
icon_markup=icons.connect,
|
||||
icon_name="view-barcode-qr-symbolic",
|
||||
action=lambda: self._scan_qr_and_add_account(""),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -600,7 +598,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="QR Scan Instructions:",
|
||||
subtitle="Use 'qr <account_name>' to specify account name",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -612,7 +610,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Scan QR Code for '{account_name}'",
|
||||
subtitle="Click to scan QR code from screen",
|
||||
icon_markup=icons.connect,
|
||||
icon_name="view-barcode-qr-symbolic",
|
||||
action=lambda name=account_name: self._scan_qr_and_add_account(
|
||||
name
|
||||
),
|
||||
@@ -658,7 +656,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="No OTP accounts to remove",
|
||||
subtitle="Use 'add <account> <secret>' to add accounts first",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -670,7 +668,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Select account to remove:",
|
||||
subtitle="Type: remove <account_name> to remove an account",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="user-trash-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -697,7 +695,7 @@ class OTPPlugin(PluginBase):
|
||||
subtitle_markup=f"Press Enter to remove • {
|
||||
time_display
|
||||
} remaining",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="user-trash-symbolic",
|
||||
action=lambda acc=acc_name: self._remove_account_and_refresh(
|
||||
acc
|
||||
),
|
||||
@@ -716,7 +714,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Error: {acc_name}",
|
||||
subtitle="Press Enter to remove (Invalid secret)",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="user-trash-symbolic",
|
||||
action=lambda acc=acc_name: self._remove_account_and_refresh(
|
||||
acc
|
||||
),
|
||||
@@ -738,7 +736,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Account '{account_name}' not found",
|
||||
subtitle="Use 'remove' to see all available accounts",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="dialog-cancel-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -756,7 +754,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Remove '{display_name}'?",
|
||||
subtitle="Press Enter to confirm removal",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="user-trash-symbolic",
|
||||
action=lambda acc=account_name: self._remove_account_and_refresh(acc),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -777,7 +775,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid Base32 secret",
|
||||
subtitle=result["error"],
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="dialog-cancel-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -800,7 +798,7 @@ class OTPPlugin(PluginBase):
|
||||
subtitle=f"OTP account added successfully (secret: {
|
||||
result['secret'][:4]
|
||||
}...)",
|
||||
icon_markup=icons.check,
|
||||
icon_name="emblem-ok-symbolic",
|
||||
action=lambda: self._trigger_refresh(),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -817,7 +815,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title="Error parsing otpauth URI",
|
||||
subtitle=result["error"],
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="dialog-cancel-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -843,7 +841,7 @@ class OTPPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"✓ Added '{display_name}'",
|
||||
subtitle="OTP account added from URI",
|
||||
icon_markup=icons.check,
|
||||
icon_name="emblem-ok-symbolic",
|
||||
action=lambda: self._trigger_refresh(),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -8,8 +8,6 @@ from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from fabric.utils import get_relative_path
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -242,7 +240,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title="No passwords stored",
|
||||
subtitle="Use 'pass add <name> <password>' to add your first password",
|
||||
icon_markup=icons.key,
|
||||
icon_name="password-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -253,7 +251,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title="Available commands:",
|
||||
subtitle="add <name> <password> | remove <name> | <name> (to search)",
|
||||
icon_markup=icons.info,
|
||||
icon_name="info",
|
||||
action=lambda: None,
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -284,7 +282,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.key,
|
||||
icon_name="key",
|
||||
action=lambda n=name: self._copy_password_to_clipboard(n),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -311,7 +309,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title="Add Password - Invalid format",
|
||||
subtitle="Usage: add <name> <password> [description]",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="cancel",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -330,7 +328,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Update password for '{name}'?",
|
||||
subtitle="Password already exists. Click to update it.",
|
||||
icon_markup=icons.key,
|
||||
icon_name="key",
|
||||
action=lambda: self._add_password_action(
|
||||
name, password, description, update=True
|
||||
),
|
||||
@@ -345,7 +343,7 @@ class PasswordPlugin(PluginBase):
|
||||
title=f"Add password for '{name}'",
|
||||
subtitle="Click to save password"
|
||||
+ (f" | {description}" if description else ""),
|
||||
icon_markup=icons.plus,
|
||||
icon_name="plus",
|
||||
action=lambda: self._add_password_action(
|
||||
name, password, description
|
||||
),
|
||||
@@ -367,7 +365,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title="Remove Password - Invalid format",
|
||||
subtitle="Usage: remove <name>",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="cancel",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -383,7 +381,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Password '{name}' not found",
|
||||
subtitle="Check the name and try again",
|
||||
icon_markup=icons.cancel,
|
||||
icon_name="cancel",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -395,7 +393,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Remove password '{name}'?",
|
||||
subtitle="Click to confirm deletion (this cannot be undone)",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="trash",
|
||||
action=lambda: self._remove_password_action(name),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -420,7 +418,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"No passwords found matching '{query}'",
|
||||
subtitle="Try a different search term or use 'pass' to see all passwords",
|
||||
icon_markup=icons.magnifier,
|
||||
icon_name="magnifier",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -462,7 +460,7 @@ class PasswordPlugin(PluginBase):
|
||||
Result(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icons.key,
|
||||
icon_name="key",
|
||||
action=lambda n=name: self._copy_password_to_clipboard(n),
|
||||
relevance=get_relevance(name),
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
from typing import List
|
||||
|
||||
from fabric.utils import exec_shell_command_async
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -19,27 +17,27 @@ class PowerPlugin(PluginBase):
|
||||
self.commands = {
|
||||
"shutdown": {
|
||||
"description": "Shutdown the system",
|
||||
"icon": icons.shutdown,
|
||||
"icon": "system-shutdown-symbolic",
|
||||
"action": self.shutdown,
|
||||
},
|
||||
"restart": {
|
||||
"description": "Restart the system",
|
||||
"icon": icons.reboot,
|
||||
"icon": "system-reboot-symbolic",
|
||||
"action": self.restart,
|
||||
},
|
||||
"lock": {
|
||||
"description": "Lock the screen",
|
||||
"icon": icons.lock,
|
||||
"icon": "system-lock-screen-symbolic",
|
||||
"action": self.lock,
|
||||
},
|
||||
"suspend": {
|
||||
"description": "Suspend the system",
|
||||
"icon": icons.suspend,
|
||||
"icon": "system-suspend-symbolic",
|
||||
"action": self.suspend,
|
||||
},
|
||||
"logout": {
|
||||
"description": "Logout from current session",
|
||||
"icon": icons.logout,
|
||||
"icon": "system-log-out-symbolic",
|
||||
"action": self.logout,
|
||||
},
|
||||
}
|
||||
@@ -63,7 +61,7 @@ class PowerPlugin(PluginBase):
|
||||
result = Result(
|
||||
title=cmd.capitalize(),
|
||||
subtitle=info["description"],
|
||||
icon_markup=info["icon"],
|
||||
icon_name=info["icon"],
|
||||
action=info["action"],
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -77,7 +75,7 @@ class PowerPlugin(PluginBase):
|
||||
result = Result(
|
||||
title=cmd.capitalize(),
|
||||
subtitle=info["description"],
|
||||
icon_markup=info["icon"],
|
||||
icon_name=info["icon"],
|
||||
action=info["action"],
|
||||
relevance=1.0 if query == cmd else 0.7,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -4,7 +4,6 @@ import threading
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -258,7 +257,7 @@ class RemindersPlugin(PluginBase):
|
||||
subtitle=f"Active reminders: {
|
||||
active_count
|
||||
} | Usage: remind 5m Take a break",
|
||||
icon_markup=icons.timer_on,
|
||||
icon_name="alarm-timer",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -279,7 +278,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title=example,
|
||||
subtitle=desc,
|
||||
icon_markup=icons.timer_on,
|
||||
icon_name="alarm-timer",
|
||||
action=lambda: None,
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -296,7 +295,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title="No Active Reminders",
|
||||
subtitle="Use 'remind 5m message' to set a reminder",
|
||||
icon_markup=icons.timer_off,
|
||||
icon_name="timer-off",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -314,7 +313,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"#{reminder.id}: {reminder.message}",
|
||||
subtitle=f"In {time_remaining} (at {target_time})",
|
||||
icon_markup=icons.timer_on,
|
||||
icon_name="alarm-timer",
|
||||
action=lambda rid=reminder.id: self._cancel_reminder(rid),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -334,7 +333,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Cancelled {count} Reminders",
|
||||
subtitle="All active reminders have been cancelled",
|
||||
icon_markup=icons.timer_off,
|
||||
icon_name="timer-off",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -351,7 +350,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Cancelled Reminder #{reminder_id}",
|
||||
subtitle="Reminder has been cancelled",
|
||||
icon_markup=icons.timer_off,
|
||||
icon_name="timer-off",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -363,7 +362,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title="Reminder Not Found",
|
||||
subtitle=f"No reminder with ID #{reminder_id}",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -375,7 +374,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid Reminder ID",
|
||||
subtitle="Please provide a valid reminder ID number",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -407,7 +406,7 @@ class RemindersPlugin(PluginBase):
|
||||
subtitle=f"Will remind in {time_remaining} (at {
|
||||
target_time_str
|
||||
})",
|
||||
icon_markup=icons.timer_on,
|
||||
icon_name="alarm-timer",
|
||||
action=lambda ts=time_str, msg=message: self._create_and_confirm_reminder(
|
||||
ts, msg
|
||||
),
|
||||
@@ -425,7 +424,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title="Time is in the Past",
|
||||
subtitle="Please specify a future time",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -438,7 +437,7 @@ class RemindersPlugin(PluginBase):
|
||||
Result(
|
||||
title="Invalid Time Format",
|
||||
subtitle="Use formats like: 5m, 30s, 2h, 14:30, or '5 minutes'",
|
||||
icon_markup=icons.alert,
|
||||
icon_name="alert",
|
||||
action=lambda: None,
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -2,10 +2,8 @@ import subprocess
|
||||
from typing import List
|
||||
|
||||
from fabric.utils import get_relative_path
|
||||
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
from utils.icons import screenrecord, screenshots, ssfull, ssregion, stop
|
||||
|
||||
|
||||
class ScreencapturePlugin(PluginBase):
|
||||
@@ -17,7 +15,6 @@ class ScreencapturePlugin(PluginBase):
|
||||
super().__init__()
|
||||
self.display_name = "Screencapture"
|
||||
self.description = "Take screenshots and screen recordings"
|
||||
# Path to the screen-capture script
|
||||
self.script_path = get_relative_path("../../../scripts/screen-capture.sh")
|
||||
|
||||
def initialize(self):
|
||||
@@ -121,290 +118,290 @@ class ScreencapturePlugin(PluginBase):
|
||||
"screenshot": (
|
||||
"Take Screenshot (eDP-1)",
|
||||
"Capture the main display",
|
||||
ssfull,
|
||||
"camera-photo-symbolic",
|
||||
lambda: self._run_script("screenshot", "eDP-1"),
|
||||
),
|
||||
"ss": (
|
||||
"Take Screenshot (eDP-1)",
|
||||
"Capture the main display",
|
||||
ssfull,
|
||||
"camera-photo-symbolic",
|
||||
lambda: self._run_script("screenshot", "eDP-1"),
|
||||
),
|
||||
"screenshot-region": (
|
||||
"Take Region Screenshot",
|
||||
"Capture a selected region",
|
||||
ssregion,
|
||||
"camera-photo-symbolic",
|
||||
lambda: self._run_script("screenshot", "selection"),
|
||||
),
|
||||
"ss-region": (
|
||||
"Take Region Screenshot",
|
||||
"Capture a selected region",
|
||||
ssregion,
|
||||
"camera-photo-symbolic",
|
||||
lambda: self._run_script("screenshot", "selection"),
|
||||
),
|
||||
"screenshot-both": (
|
||||
"Take Screenshot (Both Displays)",
|
||||
"Capture both displays combined",
|
||||
screenshots,
|
||||
"video-joined-displays-symbolic",
|
||||
lambda: self._run_script("screenshot", "both"),
|
||||
),
|
||||
"ss-both": (
|
||||
"Take Screenshot (Both Displays)",
|
||||
"Capture both displays combined",
|
||||
screenshots,
|
||||
"video-joined-displays-symbolic",
|
||||
lambda: self._run_script("screenshot", "both"),
|
||||
),
|
||||
"screenshot-hdmi": (
|
||||
"Take Screenshot (HDMI-A-1)",
|
||||
"Capture HDMI display",
|
||||
ssfull,
|
||||
"video-display-symbolic",
|
||||
lambda: self._run_script("screenshot", "HDMI-A-1"),
|
||||
),
|
||||
"ss-hdmi": (
|
||||
"Take Screenshot (HDMI-A-1)",
|
||||
"Capture HDMI display",
|
||||
ssfull,
|
||||
"video-display-symbolic",
|
||||
lambda: self._run_script("screenshot", "HDMI-A-1"),
|
||||
),
|
||||
# Recording commands (with audio)
|
||||
"record": (
|
||||
"Start Recording (eDP-1)",
|
||||
"Record the main display with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "eDP-1"),
|
||||
),
|
||||
"rec": (
|
||||
"Start Recording (eDP-1)",
|
||||
"Record the main display with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "eDP-1"),
|
||||
),
|
||||
"record-region": (
|
||||
"Start Region Recording",
|
||||
"Record a selected region with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "selection"),
|
||||
),
|
||||
"rec-region": (
|
||||
"Start Region Recording",
|
||||
"Record a selected region with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "selection"),
|
||||
),
|
||||
"record-hdmi": (
|
||||
"Start Recording (HDMI-A-1)",
|
||||
"Record HDMI display with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "HDMI-A-1"),
|
||||
),
|
||||
"rec-hdmi": (
|
||||
"Start Recording (HDMI-A-1)",
|
||||
"Record HDMI display with audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record", "HDMI-A-1"),
|
||||
),
|
||||
# Recording commands (no audio)
|
||||
"record-noaudio": (
|
||||
"Start Recording No Audio (eDP-1)",
|
||||
"Record the main display without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "eDP-1"),
|
||||
),
|
||||
"rec-noaudio": (
|
||||
"Start Recording No Audio (eDP-1)",
|
||||
"Record the main display without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "eDP-1"),
|
||||
),
|
||||
"record-noaudio-region": (
|
||||
"Start Region Recording No Audio",
|
||||
"Record a selected region without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "selection"),
|
||||
),
|
||||
"rec-noaudio-region": (
|
||||
"Start Region Recording No Audio",
|
||||
"Record a selected region without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "selection"),
|
||||
),
|
||||
"record-noaudio-hdmi": (
|
||||
"Start Recording No Audio (HDMI-A-1)",
|
||||
"Record HDMI display without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "HDMI-A-1"),
|
||||
),
|
||||
"rec-noaudio-hdmi": (
|
||||
"Start Recording No Audio (HDMI-A-1)",
|
||||
"Record HDMI display without audio",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-noaudio", "HDMI-A-1"),
|
||||
),
|
||||
# High-quality recording commands
|
||||
"record-hq": (
|
||||
"Start HQ Recording (eDP-1)",
|
||||
"High-quality recording for YouTube",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "eDP-1"),
|
||||
),
|
||||
"rec-hq": (
|
||||
"Start HQ Recording (eDP-1)",
|
||||
"High-quality recording for YouTube",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "eDP-1"),
|
||||
),
|
||||
"record-hq-region": (
|
||||
"Start HQ Region Recording",
|
||||
"High-quality region recording",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "selection"),
|
||||
),
|
||||
"rec-hq-region": (
|
||||
"Start HQ Region Recording",
|
||||
"High-quality region recording",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "selection"),
|
||||
),
|
||||
"record-hq-hdmi": (
|
||||
"Start HQ Recording (HDMI-A-1)",
|
||||
"High-quality HDMI recording",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "HDMI-A-1"),
|
||||
),
|
||||
"rec-hq-hdmi": (
|
||||
"Start HQ Recording (HDMI-A-1)",
|
||||
"High-quality HDMI recording",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-hq", "HDMI-A-1"),
|
||||
),
|
||||
# GIF recording commands
|
||||
"record-gif": (
|
||||
"Start GIF Recording (eDP-1)",
|
||||
"Record as optimized GIF",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-gif", "eDP-1"),
|
||||
),
|
||||
"rec-gif": (
|
||||
"Start GIF Recording (eDP-1)",
|
||||
"Record as optimized GIF",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-gif", "eDP-1"),
|
||||
),
|
||||
"record-gif-region": (
|
||||
"Start GIF Region Recording",
|
||||
"Record selected region as GIF",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-gif", "selection"),
|
||||
),
|
||||
"rec-gif-region": (
|
||||
"Start GIF Region Recording",
|
||||
"Record selected region as GIF",
|
||||
screenrecord,
|
||||
"media-record-symbolic",
|
||||
lambda: self._run_script("record-gif", "selection"),
|
||||
),
|
||||
# Control commands
|
||||
"stop": (
|
||||
"Stop Recording",
|
||||
"Stop the current screen recording",
|
||||
stop,
|
||||
"media-playback-stop-symbolic",
|
||||
lambda: self._run_script("record", "stop"),
|
||||
),
|
||||
# Conversion commands
|
||||
"convert-webm": (
|
||||
"Convert Latest to WebM",
|
||||
"Convert latest MKV recording to WebM format",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "webm"),
|
||||
),
|
||||
"conv-webm": (
|
||||
"Convert Latest to WebM",
|
||||
"Convert latest MKV recording to WebM format",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "webm"),
|
||||
),
|
||||
"convert-iphone": (
|
||||
"Convert Latest for iPhone",
|
||||
"Convert latest MKV recording for iPhone compatibility",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "iphone"),
|
||||
),
|
||||
"conv-iphone": (
|
||||
"Convert Latest for iPhone",
|
||||
"Convert latest MKV recording for iPhone compatibility",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "iphone"),
|
||||
),
|
||||
"convert-youtube": (
|
||||
"Convert Latest for YouTube",
|
||||
"Convert latest recording for YouTube upload",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "youtube"),
|
||||
),
|
||||
"conv-youtube": (
|
||||
"Convert Latest for YouTube",
|
||||
"Convert latest recording for YouTube upload",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "youtube"),
|
||||
),
|
||||
"convert-gif": (
|
||||
"Convert Latest to GIF",
|
||||
"Convert latest recording to GIF format",
|
||||
screenrecord,
|
||||
"image-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "gif"),
|
||||
),
|
||||
"conv-gif": (
|
||||
"Convert Latest to GIF",
|
||||
"Convert latest recording to GIF format",
|
||||
screenrecord,
|
||||
"image-x-generic-symbolic",
|
||||
lambda: self._run_script("convert", "gif"),
|
||||
),
|
||||
# File-based conversion commands (these will be handled specially)
|
||||
"convert-webm-file": (
|
||||
"Convert File to WebM",
|
||||
"Type filename after command (e.g., convert-webm-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"conv-webm-file": (
|
||||
"Convert File to WebM",
|
||||
"Type filename after command (e.g., conv-webm-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"convert-iphone-file": (
|
||||
"Convert File for iPhone",
|
||||
"Type filename after command (e.g., convert-iphone-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"conv-iphone-file": (
|
||||
"Convert File for iPhone",
|
||||
"Type filename after command (e.g., conv-iphone-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"convert-youtube-file": (
|
||||
"Convert File for YouTube",
|
||||
"Type filename after command (e.g., convert-youtube-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"conv-youtube-file": (
|
||||
"Convert File for YouTube",
|
||||
"Type filename after command (e.g., conv-youtube-file video.mkv)",
|
||||
screenrecord,
|
||||
"video-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"convert-gif-file": (
|
||||
"Convert File to GIF",
|
||||
"Type filename after command (e.g., convert-gif-file video.mkv)",
|
||||
screenrecord,
|
||||
"image-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
"conv-gif-file": (
|
||||
"Convert File to GIF",
|
||||
"Type filename after command (e.g., conv-gif-file video.mkv)",
|
||||
screenrecord,
|
||||
"image-x-generic-symbolic",
|
||||
None, # Will be handled in query method
|
||||
),
|
||||
}
|
||||
@@ -415,7 +412,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
return Result(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icon,
|
||||
icon_name=icon,
|
||||
action=action,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -424,7 +421,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
return Result(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
icon_markup=icon,
|
||||
icon_name=icon,
|
||||
action=lambda: None, # No action for instruction
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -465,7 +462,11 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Convert {file_param} to {format_type.upper()}",
|
||||
subtitle=f"Convert specified file to {format_type} format",
|
||||
icon_markup=screenrecord,
|
||||
icon_name=(
|
||||
"video-x-generic-symbolic"
|
||||
if format_type != "gif"
|
||||
else "image-x-generic-symbolic"
|
||||
),
|
||||
action=lambda fp=file_param, ft=format_type: self._run_script_with_file(
|
||||
ft, fp
|
||||
),
|
||||
@@ -488,7 +489,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Stop Recording",
|
||||
subtitle="Stop the current screen recording",
|
||||
icon_markup=stop,
|
||||
icon_name="media-playback-stop-symbolic",
|
||||
action=lambda: self._run_script("record", "stop"),
|
||||
relevance=2.0, # Highest relevance to appear at top
|
||||
plugin_name=self.display_name,
|
||||
@@ -501,7 +502,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Take Screenshot",
|
||||
subtitle="Capture the entire screen (eDP-1)",
|
||||
icon_markup=ssfull,
|
||||
icon_name="camera-photo-symbolic",
|
||||
action=lambda: self._run_script("screenshot", "eDP-1"),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -509,7 +510,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Take Region Screenshot",
|
||||
subtitle="Capture a selected region",
|
||||
icon_markup=ssregion,
|
||||
icon_name="camera-photo-symbolic",
|
||||
action=lambda: self._run_script("screenshot", "selection"),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -517,7 +518,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Take Screenshot (Both Displays)",
|
||||
subtitle="Capture both displays combined",
|
||||
icon_markup=screenshots,
|
||||
icon_name="video-joined-displays-symbolic",
|
||||
action=lambda: self._run_script("screenshot", "both"),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -525,7 +526,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Take Screenshot (HDMI-A-1)",
|
||||
subtitle="Capture HDMI display",
|
||||
icon_markup=ssfull,
|
||||
icon_name="video-display-symbolic",
|
||||
action=lambda: self._run_script("screenshot", "HDMI-A-1"),
|
||||
relevance=0.7,
|
||||
plugin_name=self.display_name,
|
||||
@@ -539,7 +540,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Recording (eDP-1)",
|
||||
subtitle="Record the main display with audio",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record", "eDP-1"),
|
||||
relevance=0.7,
|
||||
plugin_name=self.display_name,
|
||||
@@ -547,7 +548,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Region Recording",
|
||||
subtitle="Record a selected region",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record", "selection"),
|
||||
relevance=0.6,
|
||||
plugin_name=self.display_name,
|
||||
@@ -555,7 +556,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Recording (HDMI-A-1)",
|
||||
subtitle="Record HDMI display with audio",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record", "HDMI-A-1"),
|
||||
relevance=0.5,
|
||||
plugin_name=self.display_name,
|
||||
@@ -569,7 +570,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Recording No Audio (eDP-1)",
|
||||
subtitle="Record the main display without audio",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-noaudio", "eDP-1"),
|
||||
relevance=0.65,
|
||||
plugin_name=self.display_name,
|
||||
@@ -577,7 +578,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Region Recording No Audio",
|
||||
subtitle="Record a selected region without audio",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-noaudio", "selection"),
|
||||
relevance=0.55,
|
||||
plugin_name=self.display_name,
|
||||
@@ -585,7 +586,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start Recording No Audio (HDMI-A-1)",
|
||||
subtitle="Record HDMI display without audio",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-noaudio", "HDMI-A-1"),
|
||||
relevance=0.45,
|
||||
plugin_name=self.display_name,
|
||||
@@ -599,7 +600,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start HQ Recording (eDP-1)",
|
||||
subtitle="High-quality recording for YouTube",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-hq", "eDP-1"),
|
||||
relevance=0.4,
|
||||
plugin_name=self.display_name,
|
||||
@@ -607,7 +608,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start HQ Region Recording",
|
||||
subtitle="High-quality region recording",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-hq", "selection"),
|
||||
relevance=0.3,
|
||||
plugin_name=self.display_name,
|
||||
@@ -615,7 +616,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start HQ Recording (HDMI-A-1)",
|
||||
subtitle="High-quality HDMI recording",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-hq", "HDMI-A-1"),
|
||||
relevance=0.2,
|
||||
plugin_name=self.display_name,
|
||||
@@ -629,7 +630,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start GIF Recording (eDP-1)",
|
||||
subtitle="Record as optimized GIF",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-gif", "eDP-1"),
|
||||
relevance=0.1,
|
||||
plugin_name=self.display_name,
|
||||
@@ -637,7 +638,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Start GIF Region Recording",
|
||||
subtitle="Record selected region as GIF",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="media-record-symbolic",
|
||||
action=lambda: self._run_script("record-gif", "selection"),
|
||||
relevance=0.05,
|
||||
plugin_name=self.display_name,
|
||||
@@ -651,7 +652,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Convert Latest to WebM",
|
||||
subtitle="Convert latest MKV recording to WebM format",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="video-x-generic-symbolic",
|
||||
action=lambda: self._run_script("convert", "webm"),
|
||||
relevance=0.01,
|
||||
plugin_name=self.display_name,
|
||||
@@ -659,7 +660,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Convert Latest for iPhone",
|
||||
subtitle="Convert latest MKV recording for iPhone compatibility",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="video-x-generic-symbolic",
|
||||
action=lambda: self._run_script("convert", "iphone"),
|
||||
relevance=0.01,
|
||||
plugin_name=self.display_name,
|
||||
@@ -667,7 +668,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Convert Latest for YouTube",
|
||||
subtitle="Convert latest recording for YouTube upload",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="video-x-generic-symbolic",
|
||||
action=lambda: self._run_script("convert", "youtube"),
|
||||
relevance=0.01,
|
||||
plugin_name=self.display_name,
|
||||
@@ -675,7 +676,7 @@ class ScreencapturePlugin(PluginBase):
|
||||
Result(
|
||||
title="Convert Latest to GIF",
|
||||
subtitle="Convert latest recording to GIF format",
|
||||
icon_markup=screenrecord,
|
||||
icon_name="image-x-generic-symbolic",
|
||||
action=lambda: self._run_script("convert", "gif"),
|
||||
relevance=0.01,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -5,10 +5,8 @@ import threading
|
||||
import time
|
||||
from typing import List, Set, Union
|
||||
|
||||
from fabric.utils import exec_shell_command_async
|
||||
|
||||
import config.data as data
|
||||
import utils.icons as icons
|
||||
from fabric.utils import exec_shell_command_async
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -91,7 +89,6 @@ class SystemPlugin(PluginBase):
|
||||
current_time - self._last_bin_update > self._bin_update_interval
|
||||
or not self._bin_cache
|
||||
):
|
||||
|
||||
if not self._cache_building:
|
||||
self._cache_building = True
|
||||
self._cache_thread = threading.Thread(
|
||||
@@ -213,7 +210,7 @@ class SystemPlugin(PluginBase):
|
||||
result = Result(
|
||||
title=display_command,
|
||||
subtitle=f"Execute: {display_command}",
|
||||
icon_markup=icons.terminal,
|
||||
icon_name="terminal",
|
||||
action=self._create_action(command_to_execute),
|
||||
relevance=relevance,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -3,10 +3,8 @@ import threading
|
||||
import time
|
||||
from typing import List
|
||||
|
||||
from fabric.utils import exec_shell_command_async
|
||||
|
||||
import config.data as data
|
||||
import utils.icons as icons
|
||||
from fabric.utils import exec_shell_command_async
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -24,13 +22,15 @@ class TmuxPlugin(PluginBase):
|
||||
# Cache for sessions to avoid repeated subprocess calls
|
||||
self._sessions_cache = []
|
||||
self._last_cache_update = 0
|
||||
self._cache_ttl = 10 # Cache sessions for 10 seconds (increased from 2)
|
||||
# Cache sessions for 10 seconds (increased from 2)
|
||||
self._cache_ttl = 10
|
||||
|
||||
# Threading for auto-refresh - only when actively used
|
||||
self.refresh_thread = None
|
||||
self.stop_refresh = threading.Event()
|
||||
self._last_query_time = 0
|
||||
self._active_refresh_timeout = 30 # Stop refreshing after 30 seconds of inactivity
|
||||
# Stop refreshing after 30 seconds of inactivity
|
||||
self._active_refresh_timeout = 30
|
||||
|
||||
def initialize(self):
|
||||
"""Initialize the tmux plugin."""
|
||||
@@ -67,7 +67,7 @@ class TmuxPlugin(PluginBase):
|
||||
self._sessions_cache = self._get_tmux_sessions()
|
||||
self._last_cache_update = current_time
|
||||
|
||||
self.stop_refresh.wait(5)
|
||||
self.stop_refresh.wait(5)
|
||||
except Exception as e:
|
||||
print(f"TmuxPlugin: Error in refresh thread: {e}")
|
||||
self.stop_refresh.wait(10) # Wait longer on error
|
||||
@@ -166,7 +166,7 @@ class TmuxPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"Attach to '{session_name}'",
|
||||
subtitle=f"Connect to tmux session: {session_name}",
|
||||
icon_markup=icons.terminal,
|
||||
icon_name="terminal",
|
||||
action=lambda: self._attach_to_session(session_name),
|
||||
relevance=0.9,
|
||||
data={"type": "attach", "session": session_name},
|
||||
@@ -177,8 +177,10 @@ class TmuxPlugin(PluginBase):
|
||||
display_name = session_name if session_name else "new session"
|
||||
return Result(
|
||||
title=f"Create '{display_name}'",
|
||||
subtitle=f"Create new tmux session{f': {session_name}' if session_name else ''}",
|
||||
icon_markup=icons.plus,
|
||||
subtitle=f"Create new tmux session{
|
||||
f': {session_name}' if session_name else ''
|
||||
}",
|
||||
icon_name="plus",
|
||||
action=lambda: self._create_session(session_name),
|
||||
relevance=0.8,
|
||||
data={"type": "create", "session": session_name},
|
||||
@@ -189,7 +191,7 @@ class TmuxPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"Kill '{session_name}'",
|
||||
subtitle=f"Terminate tmux session: {session_name}",
|
||||
icon_markup=icons.trash,
|
||||
icon_name="trash",
|
||||
action=lambda: self._kill_session(session_name),
|
||||
relevance=0.7,
|
||||
data={"type": "kill", "session": session_name},
|
||||
@@ -200,7 +202,7 @@ class TmuxPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"Rename '{old_name}' to '{new_name}'",
|
||||
subtitle=f"Rename tmux session from {old_name} to {new_name}",
|
||||
icon_markup=icons.config,
|
||||
icon_name="config",
|
||||
action=lambda: self._rename_session(old_name, new_name),
|
||||
relevance=0.6,
|
||||
data={"type": "rename", "old_session": old_name, "new_session": new_name},
|
||||
|
||||
@@ -8,12 +8,11 @@ import threading
|
||||
import time
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from fabric.utils.helpers import exec_shell_command_async
|
||||
from gi.repository import GdkPixbuf
|
||||
from PIL import Image
|
||||
|
||||
import config.data as data
|
||||
import utils.icons as icons
|
||||
from fabric.utils.helpers import exec_shell_command_async
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -124,9 +123,10 @@ class WallpaperPlugin(PluginBase):
|
||||
"""Clear the launcher search query and reset to trigger."""
|
||||
try:
|
||||
# Try to access the launcher through the fabric Application
|
||||
from fabric import Application
|
||||
from gi.repository import GLib
|
||||
|
||||
from fabric import Application
|
||||
|
||||
app = Application.get_default()
|
||||
|
||||
if app and hasattr(app, "launcher"):
|
||||
@@ -467,16 +467,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Random Wallpaper{indicator_text}",
|
||||
subtitle=f"Set a random wallpaper • {status_text}",
|
||||
icon_markup=random.choice(
|
||||
[
|
||||
icons.dice_1,
|
||||
icons.dice_2,
|
||||
icons.dice_3,
|
||||
icons.dice_4,
|
||||
icons.dice_5,
|
||||
icons.dice_6,
|
||||
]
|
||||
),
|
||||
icon_name="media-playlist-shuffle-symbolic",
|
||||
action=lambda: self._set_random_wallpaper(),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -493,16 +484,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Random Wallpaper{indicator_text}",
|
||||
subtitle=f"Set a random wallpaper • {status_text}",
|
||||
icon_markup=random.choice(
|
||||
[
|
||||
icons.dice_1,
|
||||
icons.dice_2,
|
||||
icons.dice_3,
|
||||
icons.dice_4,
|
||||
icons.dice_5,
|
||||
icons.dice_6,
|
||||
]
|
||||
),
|
||||
icon_name="media-playlist-shuffle-symbolic",
|
||||
action=lambda: self._set_random_wallpaper(),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -552,10 +534,9 @@ class WallpaperPlugin(PluginBase):
|
||||
subtitle=f"Apply with {scheme_name} scheme • {
|
||||
status_text
|
||||
}",
|
||||
icon_markup=icons.palette,
|
||||
action=lambda c=hex_color, s=scheme: self._apply_hex_color_direct(
|
||||
c, s
|
||||
),
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda c=hex_color,
|
||||
s=scheme: self._apply_hex_color_direct(c, s),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
data={
|
||||
@@ -575,7 +556,7 @@ class WallpaperPlugin(PluginBase):
|
||||
indicator_text
|
||||
}",
|
||||
subtitle="Matugen is enabled • Disable matugen to use hex colors",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -594,7 +575,7 @@ class WallpaperPlugin(PluginBase):
|
||||
subtitle=f"Apply with {scheme_name} scheme • {
|
||||
status_text
|
||||
}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda c=hex_color, s=scheme: (
|
||||
self._apply_hex_color_direct(c, s)
|
||||
if not matugen_enabled
|
||||
@@ -617,7 +598,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Hex Color (incomplete): {hex_color}",
|
||||
subtitle="Complete the 6-digit hex color to apply",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.7,
|
||||
plugin_name=self.display_name,
|
||||
@@ -647,7 +628,7 @@ class WallpaperPlugin(PluginBase):
|
||||
subtitle=f"Generate and apply random color with {
|
||||
scheme_name
|
||||
} scheme • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda s=scheme: self._apply_hex_color_direct(
|
||||
self._generate_random_hex_color(), s
|
||||
),
|
||||
@@ -667,7 +648,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Cannot Apply Random Color{indicator_text}",
|
||||
subtitle="Matugen is enabled • Disable matugen to use hex colors",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -683,7 +664,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Random Hex Color{indicator_text}",
|
||||
subtitle=f"Generate and apply random color • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda s=scheme: (
|
||||
self._apply_hex_color_direct(
|
||||
self._generate_random_hex_color(), s
|
||||
@@ -707,7 +688,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title="Hex Color Commands",
|
||||
subtitle="Use: color #FF5733, hex #00FF00, color random",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-picker-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -761,7 +742,7 @@ class WallpaperPlugin(PluginBase):
|
||||
if not matugen_enabled
|
||||
else ""
|
||||
),
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda s=scheme_id: self._set_current_scheme(s),
|
||||
relevance=1.0 if scheme_id == current_scheme else 0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -785,7 +766,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Enable Matugen{indicator_text}",
|
||||
subtitle=f"Turn on dynamic color generation • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(True),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -802,7 +783,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Disable Matugen{indicator_text}",
|
||||
subtitle=f"Turn off dynamic color generation • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(False),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -824,7 +805,7 @@ class WallpaperPlugin(PluginBase):
|
||||
subtitle=f"Switch matugen to {
|
||||
'enabled' if new_state else 'disabled'
|
||||
} • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(new_state),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -843,7 +824,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Enable Matugen{indicator_text}",
|
||||
subtitle=f"Turn on dynamic color generation • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(True),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -862,7 +843,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Disable Matugen{indicator_text}",
|
||||
subtitle=f"Turn off dynamic color generation • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(False),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -879,7 +860,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Toggle Matugen{indicator_text}",
|
||||
subtitle=f"Switch matugen state • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: self._set_matugen_state(not current_state),
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -898,7 +879,7 @@ class WallpaperPlugin(PluginBase):
|
||||
indicator_text
|
||||
}",
|
||||
subtitle=f"Dynamic colors • {status_text}",
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -912,7 +893,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Wallpaper System Status{indicator_text}",
|
||||
subtitle=status_text,
|
||||
icon_markup=icons.palette,
|
||||
icon_name="color-management-symbolic",
|
||||
action=lambda: None,
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -925,16 +906,7 @@ class WallpaperPlugin(PluginBase):
|
||||
Result(
|
||||
title=f"Random Wallpaper{indicator_text}",
|
||||
subtitle=f"Set a random wallpaper • {status_text}",
|
||||
icon_markup=random.choice(
|
||||
[
|
||||
icons.dice_1,
|
||||
icons.dice_2,
|
||||
icons.dice_3,
|
||||
icons.dice_4,
|
||||
icons.dice_5,
|
||||
icons.dice_6,
|
||||
]
|
||||
),
|
||||
icon_name="media-playlist-shuffle-symbolic",
|
||||
action=lambda: self._set_random_wallpaper(),
|
||||
relevance=0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -981,7 +953,7 @@ class WallpaperPlugin(PluginBase):
|
||||
' • ' + status_text if not query else ''
|
||||
}",
|
||||
icon=icon,
|
||||
icon_markup=icons.wallpapers if not icon else None,
|
||||
icon_name="image-x-generic-symbolic" if not icon else None,
|
||||
action=lambda w=wallpaper: self._set_wallpaper(w),
|
||||
relevance=relevance,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -2,7 +2,6 @@ import subprocess
|
||||
import urllib.parse
|
||||
from typing import List
|
||||
|
||||
import utils.icons as icons
|
||||
from modules.launcher.plugin_base import PluginBase
|
||||
from modules.launcher.result import Result
|
||||
|
||||
@@ -23,49 +22,49 @@ class WebSearchPlugin(PluginBase):
|
||||
"google": {
|
||||
"name": "Google",
|
||||
"url": "https://www.google.com/search?q={}",
|
||||
"icon": icons.google,
|
||||
"icon": "google-symbolic",
|
||||
"description": "Search with Google",
|
||||
},
|
||||
"duckduckgo": {
|
||||
"name": "DuckDuckGo",
|
||||
"url": "https://duckduckgo.com/?q={}",
|
||||
"icon": icons.duckduckgo,
|
||||
"icon": "preferences-desktop-search",
|
||||
"description": "Search with DuckDuckGo (privacy-focused)",
|
||||
},
|
||||
"youtube": {
|
||||
"name": "YouTube",
|
||||
"url": "https://www.youtube.com/results?search_query={}",
|
||||
"icon": icons.youtube,
|
||||
"icon": "youtube-symbolic",
|
||||
"description": "Search videos on YouTube",
|
||||
},
|
||||
"github": {
|
||||
"name": "GitHub",
|
||||
"url": "https://github.com/search?q={}",
|
||||
"icon": icons.github,
|
||||
"icon": "github-desktop-symbolic",
|
||||
"description": "Search repositories on GitHub",
|
||||
},
|
||||
"stackoverflow": {
|
||||
"name": "Stack Overflow",
|
||||
"url": "https://stackoverflow.com/search?q={}",
|
||||
"icon": icons.stackoverflow,
|
||||
"icon": "stack",
|
||||
"description": "Search programming questions on Stack Overflow",
|
||||
},
|
||||
"wikipedia": {
|
||||
"name": "Wikipedia",
|
||||
"url": "https://en.wikipedia.org/wiki/Special:Search?search={}",
|
||||
"icon": icons.wikipedia,
|
||||
"icon": "search-menus-symbolic",
|
||||
"description": "Search articles on Wikipedia",
|
||||
},
|
||||
"reddit": {
|
||||
"name": "Reddit",
|
||||
"url": "https://www.reddit.com/search/?q={}",
|
||||
"icon": icons.reddit,
|
||||
"icon": "reddit-symbolic",
|
||||
"description": "Search discussions on Reddit",
|
||||
},
|
||||
"linkedin": {
|
||||
"name": "LinkedIn",
|
||||
"url": "https://www.linkedin.com/search/results/all/?keywords={}",
|
||||
"icon": icons.linkedin,
|
||||
"icon": "link",
|
||||
"description": "Search professionals and jobs on LinkedIn",
|
||||
},
|
||||
}
|
||||
@@ -166,7 +165,7 @@ class WebSearchPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"Open {url}",
|
||||
subtitle="Open this URL in your default browser",
|
||||
icon_markup=icons.world,
|
||||
icon_name="link",
|
||||
action=lambda u=url: self._open_url(u),
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
@@ -190,7 +189,7 @@ class WebSearchPlugin(PluginBase):
|
||||
result = Result(
|
||||
title=engine_info["name"],
|
||||
subtitle=engine_info["description"],
|
||||
icon_markup=engine_info["icon"],
|
||||
icon_name=engine_info["icon"],
|
||||
action=lambda e=engine_id: self._show_engine_help(e),
|
||||
relevance=1.0 if engine_id == self.default_engine else 0.8,
|
||||
plugin_name=self.display_name,
|
||||
@@ -207,7 +206,7 @@ class WebSearchPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"Search '{query}' on {engine_info['name']}",
|
||||
subtitle=f"{engine_info['description']} - {query}",
|
||||
icon_markup=engine_info["icon"],
|
||||
icon_name=engine_info["icon"],
|
||||
action=lambda e=engine_id, q=query: self._perform_search(e, q),
|
||||
relevance=1.0 if engine_id == self.default_engine else 0.9,
|
||||
plugin_name=self.display_name,
|
||||
@@ -221,7 +220,7 @@ class WebSearchPlugin(PluginBase):
|
||||
return Result(
|
||||
title=f"{engine_info['name']} Search",
|
||||
subtitle=f"{engine_info['description']} - Type your search query",
|
||||
icon_markup=engine_info["icon"],
|
||||
icon_name=engine_info["icon"],
|
||||
action=lambda: None, # No action for info result
|
||||
relevance=1.0,
|
||||
plugin_name=self.display_name,
|
||||
|
||||
@@ -62,7 +62,7 @@ class ResultItem(EventBox):
|
||||
icon_widget = Image(pixbuf=self.result.icon, name="result-item-icon")
|
||||
elif self.result.icon_name:
|
||||
icon_widget = Image(
|
||||
icon_name=self.result.icon_name, icon_size=32, name="result-item-icon"
|
||||
icon_name=self.result.icon_name, icon_size=48, name="result-item-icon"
|
||||
)
|
||||
elif self.result.icon_markup:
|
||||
icon_widget = Label(
|
||||
@@ -71,8 +71,8 @@ class ResultItem(EventBox):
|
||||
else:
|
||||
# Default icon
|
||||
icon_widget = Image(
|
||||
icon_name="application-x-executable",
|
||||
icon_size=32,
|
||||
icon_name="application-default-icon",
|
||||
icon_size=48,
|
||||
name="result-item-icon",
|
||||
)
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ from typing import Any, Dict, List
|
||||
|
||||
from fabric.utils import get_relative_path
|
||||
|
||||
import utils.icons as icons
|
||||
|
||||
|
||||
class TriggerConfig:
|
||||
def __init__(self, config_path: str = None):
|
||||
@@ -29,7 +27,7 @@ class TriggerConfig:
|
||||
# Initialize settings with defaults
|
||||
default_settings = {
|
||||
"max_examples_shown": 2,
|
||||
"default_icon": "apps",
|
||||
"default_icon": "application-default-icon",
|
||||
"fallback_example_template": "{trigger} <search>",
|
||||
"config_version": "1.0",
|
||||
}
|
||||
@@ -45,10 +43,10 @@ class TriggerConfig:
|
||||
return examples
|
||||
|
||||
def get_trigger_icon(self, trigger: str) -> str:
|
||||
icon_name = self.launcher_config.get(trigger, {}).get(
|
||||
"icon", self.settings.get("default_icon", "apps")
|
||||
icon = self.launcher_config.get(trigger, {}).get(
|
||||
"icon", self.settings.get("default_icon", "application-default-icon")
|
||||
)
|
||||
return getattr(icons, icon_name, icons.apps)
|
||||
return icon
|
||||
|
||||
def get_trigger_description(self, trigger: str) -> str:
|
||||
return self.launcher_config.get(trigger, {}).get(
|
||||
|
||||
Reference in new issue
Block a user