-
Notifications
You must be signed in to change notification settings - Fork 19
Add QuickSettingsPage with drag and drop reorder logic and rename to QuickPanelPage #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
e6704e7 to
e458018
Compare
Implemented drag-and-drop reordering for quick settings toggles in a vertical ListView, allowing users to sort 9 slots (3 top, 6 main) with a long press (500ms). Added auto-scroll near edges, 150ms displaced animations for smooth transitions, and immediate ConfigurationValue storage (/desktop/asteroid/quicksettings/[top|main]/slotX) after each drop to persist order in QuickSettings.qml. Prevents duplicates within top/main slots and includes a drag proxy for natural UX. Styled to match QuickSettingsToggle and UnitsPage.qml layout.
…ull-screen ListView - Redesigned rows to use 0.2 opacity for backgrounds, matching untoggled QuickSettingsToggle, with #222222 color and 0.7 opacity icon backgrounds like toggled state. Made rows pill-shaped with dynamic widths based on content (icon + label + equal padding), ensuring consistent left/right spacing. Increased row height and content size by 20% for better legibility. Extended ListView to the screen bottom to maximize scrollable area, removing bottom spacing. Removed static separator line between top/main slots for cleaner design. Doubled left/right padding in rows to prevent labels touching pill ends, set icon and label to solid 1.0 opacity above background, increased only row height by 20% while keeping content size original, and renamed file to QuickSettingsPage.qml. Adjusted row height to 16 units with slimmer 14-unit pills, increased icon size to 10 units, label to 8 units, and tightened spacing to 2 units for compact rows. Reduced top margin to 20 units, shortened animation duration to 120ms, and lowered long press to 400ms for faster interaction. Changed page title to Quick Settings via qsTrId. Styled drag proxy with semi-transparent #AA222222 background and 1-unit #222222 border for distinct dragging.
…itle, empty slot, and 9 toggles) to i18n/*.ts files using lupdate-qt5 for localization.
Replaced 9 individual ConfigurationValue objects with two array-based ones for top and main toggle rows, stored at /desktop/asteroid/quicksettings/top and /desktop/asteroid/quicksettings/main. Enabled dynamic toggle counts by sizing ListModel based on array lengths, maintaining drag-and-drop reordering, duplicate prevention, and immediate storage. Used new configuration keys for a clean start while preserving pill-shaped rows, animations, translations, and full-screen ListView design.
Introduced a toggleEnabled ConfigurationValue at /desktop/asteroid/quicksettings/enabled to store per-toggle enabled states. Added a checkmark per row to toggle the enabled state, clearing the slot to empty when disabled and dimming the row for visual feedback. Preserved drag-and-drop functionality for disabled toggles, ensuring seamless reordering and persistence across sessions.
Removed pill-shaped slotRect backgrounds, keeping only circular icon backgrounds to align with AsteroidOS style. Updated dragProxy to a full-width, borderless Rectangle (#222222, 0.7 opacity) for dragged items. Set Row.spacing to Dims.l(2), removed extra spacers between icon, label, and checkmark for tight alignment. Dropped custom font size in Label to match PageHeader’s default, ensuring title text consistency with main settings page. Moved checkmark to left of icon (Dims.l(2) spacing), outside Row, restoring clickable MouseArea by separating it from dragArea, which now covers only icon and label. Shifted all row content left by Dims.l(10) for round watch layout, anchoring checkmark to left margin. Replaced displaced item preview with invisible Rectangle (same rowHeight) to eliminate glitchy visuals during drag, ensuring clean dragProxy appearance. Restored ListView.displaced animation (200ms, InOutQuad) to smoothly push rows during drag, testing slower timing for fluid feel.
Introduced 'Fixed Row' label at index 0 to mark the two topToggles slots (index 1-2) and 'Sliding Row' label at index 3 to indicate mainToggles (index 4+) for the slider in QuickSettings.qml. Labels are centered, use font.pixelSize: Dims.l(5), height: rowHeight * 0.75, and scroll with the ListView. Blocked dragging labels and dropping items at index 0 or 3 to enforce structure. Added mechanism to keep Sliding Row at index 3 after any drag-drop by moving it back if displaced to index 2 or 4. Updated slotModel with type: 'label'/'toggle' to avoid binding errors, ensuring discrete items and clean configuration updates. Add config validation to QuickSettingsPage.qml to prevent empty UI Added checks in slotModel Component.onCompleted to validate topToggles, mainToggles, and toggleEnabled configurations. Resets topToggles mainToggles and toggleEnabled to all true if empty, undefined, or invalid. Filters out invalid toggle IDs and pads topToggles to ensure two slots. Ensures slotModel always populates 10 items (2 labels + 2 topToggles + 6 mainToggles), preventing empty UI after config errors. Preserves Fixed Row (index 0), Sliding Row (index 3), and all drag-drop functionality. Polish QuickSettingsPage.qml UI with design tweaks Set Fixed Row and Sliding Row labels to italic (font.italic: true) for visual distinction. Reduced label row height to rowHeight * 0.5 (~8px) from 0.75 for compact look, keeping font.pixelSize: Dims.l(5). Lowered dragProxy opacity to 0.5 from 0.7 for lighter dragged item appearance. Added fake press highlight (Rectangle, #222222, 0.2 opacity) on toggle items during dragArea press, fading in/out over 200ms (InOutQuad), visible only before drag starts (400ms) or if scrolling list. Added Weblate translation comments in slotModel for proper i18n source text. Preserved config validation, drag rules, and all functionality.
Added 'Battery Meter aligned to bottom?' config option (ConfigurationValue, /desktop/asteroid/quicksettings/batteryBottom, default true) to let users choose battery meter position in QuickSettings.qml. Implemented as a dynamic bottom label in slotModel (type: config, appended last) with word-wrapped Text (left-aligned to toggle checkmarks, Dims.l(10)), default font size, and right-aligned checkmark (ios-checkmark-circle-outline/ios-circle-outline, Dims.l(10) margin). Prevents dragging toggles to the last two indices (spacer at count-2, config at count-1), adding ~16px spacer item (type: spacer) before config and ~24px (rowHeight * 1.5) footer after to ease bottom item manipulation and checkmark access on round screens. Entire page (list + spacer + label) scrolls in ListView, avoiding MouseArea conflicts. Reduced fake press highlight transition to 100ms (from 200ms) for snappier toggle tap feedback. Made config label dynamic to support future toggle additions. Preserved all drag rules, config validation, and UI styles.
…eflect the orientation of the quicksettings batteryMeter in the main.qml quicksettings settings icon
- Moved QuickSettings item from 7th place (below launcher items) to 4th place, below Sound settings item. - Improved visual harmony by aligning round QuickSettings icon after squarish icons for a cohesive look. - Enhanced UX by placing QuickSettings in the top 4 spots, ensuring it’s always visible on settings app startup.
- Eliminated empty-slot logic and qsTrId('id-empty-slot') from QuickSettingsPage.qml.
- Fixed TypeError: Cannot read property 'toggleId' of undefined by ensuring only valid toggleIds are used.
- Updated slotModel to prevent appending empty toggleIds and enforce two valid toggles in top row.
- Corrected typo in property declaration from 'rowspan' to 'rowHeight' to fix layout issues and ReferenceError.
- Resolved TypeError in dragCheckmark by adding checks for valid draggedItemIndex and model access.
- Updated dragArea to reset draggedItemIndex before hiding dragProxy, preventing stale index errors.
- Added onContentYChanged and onMovementStarted handlers to abort drag on invalid scroll states.
- Enhanced scrollTimer with state validation, safeGet, and try-catch for robust drag handling.
- Improved dragArea with error handling for startDrag and onPositionChanged to prevent invalid drags.
- Added abortDrag function to centralize drag cleanup with error handling.
- Added safeGet utility to safely access object properties with fallback values.
Layout Regresson fixes
- Removed Column layout to prevent clipping and incorrect top spacing of ListView.
- Anchored ListView to screen top to allow scrolling under transparent PageHeader.
- Added ListView header to offset id-fixed-row below PageHeader initially, ensuring visibility.
- Moved PageHeader below ListView in code for rendering clarity, relying on default self-anchoring.
- Updated id-fixed-row and id-sliding-row translations to include 'Content'.
- Set ListView header height to title.height for minimal id-fixed-row spacing, blending seamlessly with PageHeader's fade.
Refactor Nomenclature
- Rename topToggles to fixedToggles and mainToggles to sliderToggles
- update topLength to fixedLength
- streamline nomenclature for clarity
…s and disabling overscroll Resolved 'TypeError: Cannot read property 'width' of null' on overscrolling ListView by: - Using safe width bindings (slotList.width instead of parent.width) in delegate and dragProxy - Setting boundsBehavior to StopAtBounds to prevent overscroll, stabilizing delegate access - Increasing cacheBuffer for better delegate recycling Disabling overscroll also improves drag-and-drop usability by reducing list jitter.
….qml with LabeledSwitch and Options label - Renamed batteryBottom ConfigurationValue to options, using an object with batteryBottom, batteryAnimation, and batteryColored booleans - Renamed batteryAnimations to batteryAnimation for clarity (single animation) - Updated ListModel Component.onCompleted to: - Validate and append config items for batteryAnimation and batteryColored - Remove all spacers, relying on ListView header and footer for spacing - Add 'Options' label (id-options) as a divider between draggable items and battery-bottom config - Updated translation texts to remove 'Meter': 'Battery aligned to bottom?', 'Show Battery Animation?', 'Enable colored Battery?' - Modified config delegate to use LabeledSwitch: - Dynamically adjust height based on wrapped text (Math.max(rowHeight * 2, implicitHeight)) - Set text, checked state, and onCheckedChanged to manage options array - Removed unnecessary font.pixelSize, leftPadding, rightPadding, topPadding as LabeledSwitch has built-in padding - Updated main delegate to: - Respect dynamic config item heights using childrenRect.height - Remove spacer logic - Increased toggle checkmark leftMargin to Dims.l(15) for consistency
- Updated translation files to include latest strings: 'Options' (id-options), 'Battery aligned to bottom?' (id-battery-bottom), 'Show Battery Animation?' (id-battery-animation), 'Enable colored Battery?' (id-battery-colored) - Removed console.log debug statements from drag-and-drop logic to clean up code
…oggle logic - Modified QuickSettingsPage.qml toggle checkmark MouseArea to enforce minimum active toggles: - Fixed row: Minimum 1 active toggle - Slider row: Minimum 2 active toggles - Implemented self-contained active toggle counting within MouseArea using fixedToggles and sliderToggles - Prevented disabling toggles when minimum active count is reached, ensuring no empty rows
…ong text/translation strings showing in the center, the widest part of round screens
…ttingsPage.qml - Added org.asteroid.utils import for DeviceInfo to check hasWlan and hasSpeaker - Option to mark wifiToggle and soundToggle as unavailable, disabling them in toggleEnabled, sorting last, hiding checkmark, and matching inactive toggle opacity - Fixed slider row toggle swapping on reload by persisting stable sorted order to sliderToggles.value - Prevented dropping toggles below unavailable slider toggles using first unavailable index restriction - Fixed cross-row toggle move persistence by updating listView property during drags - Fixed toggle doubling when moving from fixed to slider row by tracking usedToggleIds and updating replacement toggle listView - Fixed broken drag-and-drop by moving slotModel refresh to finalizeMove, ensuring real-time reordering and drop persistence - Fixed disappearing displaced toggles by syncing listView before index-based assignment in updateConfiguration - Fixed unavailable soundToggle visibility by appending to slotModel and sliderToggles.value, ensuring presence after QuickSettings load
…stUnavailableIndex according to its position
- Replaced scrollTimer with autoScrollTimer using scrollSpeed and explicit contentY clamping - Updated dragProxy.y to follow mouse coordinates, decoupling from contentY - Added clip: true and interactive: draggedItemIndex === -1 to ListView - Removed initResetTimer with forceLayout and positionViewAtBeginning - Adopted itemAt(slotList.width / 2, pos.y + slotList.contentY) for drop target detection - Preserved complex version’s moveItems, restoreOriginalOrder, and toggle animations - Excluded dropIndicator from stripped-down version - Added contentY clamping in abortDrag and onReleased
- Fixed slider-to-fixed move logic in moveItems to correctly swap toggles - Deferred draggedItemIndex update until after successful move - Updated onReleased handler to validate drops using draggedToggleId - Added detailed logging for swap operations - Preserved slotList.forceLayout() for visual consistency
- Removed contentY reset in abortDrag to respect header offset (e.g., contentY=-80) - Removed contentY reset in onReleased for valid drops to maintain scroll position - Remove all debug logging since the issue contentY jump issue is solved - Ensures ListView stays at current scroll position (e.g., -33 or -80) after rejected drops
- Added header offset handling in autoScrollTimer to allow negative contentY - Skipped drag processing in onPositionChanged for dropY < 0 (header area) - Aborted drags in onReleased when dropY < 0 to prevent list jump - Ensures stable ListView position during header drags
- Reset pressHighlight and stop longPressTimer at start of onReleased to clear state for all presses - Unified drag cleanup in onReleased to always reset dragProxy, draggedItemIndex, and targetIndex - Removed redundant abortDrag calls for invalid drops, simplifying state management - Increased autoScrollTimer scrollSpeed to 25 for smoother drag scrolling - Fixes stuck highlights, unresponsive toggles, and persistent dragProxy
- Introduced moveTimer with 50ms delay to stagger slotModel.move operations in inter-row swaps - Added crossRowMoveInProgress flag to track inter-row move state - Implemented ListView move and add transitions for consistent 200ms Easing.InOutQuad animations - Moved saveConfiguration to moveTimer for inter-row swaps to ensure model consistency - Ensures fluid animations for fixed-to-slider and slider-to-fixed toggle movements
- Added sortToggles function to prioritize available toggles in fixed and slider rows - Updated refreshModel to sort fixedToggles and sliderToggles by availability - Modified fixed row population to prefer available toggles, falling back to unavailable ones - Adjusted iconRectangle, toggleIcon, and Label opacities to visually distinguish unavailable toggles - Restricted dragArea to available toggles only, preventing interaction with unavailable ones - Maintained smooth 200ms Easing.InOutQuad animations for all toggle swaps
- Added isValidDropPosition function to validate drop targets, preventing drops on non-toggles or below unavailable toggles - Updated moveItems, onPositionChanged, and onReleased to use isValidDropPosition for stricter drag-and-drop rules - Maintained sorted order of available/unavailable toggles in fixed and slider rows - Preserved 200ms Easing.InOutQuad animations for all toggle swaps
- Replaced pressHighlight Rectangle with HighlightBar in ListView delegate for consistent white #33ffffff highlights - Updated dragProxy background to use HighlightBar with containsPress bound to visibility, matching toggle highlight style - Removed manual opacity changes in dragArea, leveraging HighlightBar's 150ms Easing.OutQuad ColorAnimation - Ensured visual consistency with LabeledSwitch highlights, enhancing overall UI polish - Preserved 200ms Easing.InOutQuad animations and drag-and-drop functionality
…gn selection - Extended options config to include particleDesign, aligning with QuickSettings.qml. - Introduced particleDesigns array with design options: diamonds, bubbles, logos, flashes. - Added necessary imports: QtGraphicalEffects 1.15 for OpacityMask, Nemo.Mce 1.0, and MCE components (MceBatteryLevel, MceBatteryState, MceChargerType) for batteryMeter functionality. - Created new OptionCycler component in org.asteroid.controls, analogous to LabeledSwitch, with documentation and example, for cycling through configuration values without battery meter. - Replaced inline optionCycler item in QuickSettingsPage.qml with new OptionCycler component for particleDesign selection. - Moved batteryMeter to a separate static display slot with label 'id-battery-preview', maintaining parameters (toggleSize: Dims.l(28), no states/Connections/Component.onCompleted). - Updated refreshModel to include new display slot and findOptionsLabelIndex to account for additional slot. - Ensured OptionCycler and batteryMeter (display type) cannot be dragged and prevent toggle drops, consistent with LabeledSwitch behavior. - Modified isValidDropPosition to include display type in non-droppable items. - Added title property to OptionCycler for context, with height set to rowHeight * 2, title label top/left-aligned, and value label below right-aligned. - Reordered LabeledSwitch items in QuickSettings.qml to place id-battery-colored before id-battery-animation. - Implemented touch disabling for id-particle-design OptionCycler when id-battery-animation is disabled, with 0.5 opacity, using conditional HighlightBar onClicked handler to preserve ListView scrolling.
…and particle system - Added toggleOptions for toggle metadata and management. - Enhanced batteryMeter with dynamic particle spawning (60px/s charging, 20px/s discharging), horizontal stratification, and clipping destruction. - Set particle spawn intervals to 200ms (charging) and 750ms (discharging), with TTLs at 2500ms and 8500ms. - Adjusted particle maxOpacity to 0.6, aligned with QuickSettings.qml.
Integrate 'powerOffToggle' and 'rebootToggle' into 'QuickSettingsPage.qml', enabling users to configure these toggles via the drag-and-drop interface. The toggles, introduced in 'QuickSettings.qml' with 'RemorseTimer' for safe power-off and reboot actions, are now manageable in the settings page.
Changes:
- Added 'powerOffToggle' and 'rebootToggle' to 'toggleOptions' with translated names ('qsTrId(id-toggle-power-off)', 'qsTrId(id-toggle-reboot)') and icons ('ios-power', 'ios-refresh').
- Updated 'sliderToggles' defaultValue to include 'powerOffToggle' and 'rebootToggle' in the sliding row.
- Extended 'toggleEnabled' defaultValue to enable both toggles by default.
Fix toggle order in QuickSettingsPage to respect toggleOptions
Correct the toggle order in 'QuickSettingsPage.qml' to ensure available toggles appear in the 'slotList' and 'sliderToggles' configuration in the order defined by 'toggleOptions', with unavailable toggles sorted alphabetically at the end. Previously, the 'powerOffToggle' and 'rebootToggle' (added in the prior commit) were sorted incorrectly due to the 'sortToggles' function ignoring 'toggleOptions' order for available toggles.
Changes:
- Updated 'sortToggles' to prioritize 'toggleOptions' index for available toggles, after sorting by availability.
- Rewrote 'refreshModel' to initialize 'fixedToggles' and 'sliderToggles' using 'toggleOptions' order for available toggles, appending unavailable toggles last.
- Ensured 'saveConfiguration' writes the correct order to dconf, placing 'powerOffToggle' and 'rebootToggle' at the end of available toggles.
Signed-off-by: Timo Könnecke <[email protected]>
Integrate 'aodToggle' into 'QuickSettingsPage.qml' to allow configuration of the always-on display (AoD) alongside other quick settings toggles. Changes: - Added 'aodToggle' to 'toggleOptions' with 'qsTrId(id-always-on-display)' and 'ios-watch-aod-on' icon from 'asteroid-icons-ion'. - Updated 'sliderToggles' and 'toggleEnabled' to include before 'powerOffToggle'. This enables users to enable, disable, and reorder the 'aodToggle' in the quick settings configuration UI, with proper internationalization and visual consistency. Signed-off-by: Timo Könnecke <[email protected]>
- Simplify the cross-row drag logic by handling both directions in a single operation - Remove two-step process that interrupted continuous drag operations - Eliminate unnecessary moveTimer and crossRowMoveInProgress flag - Improve position calculation during drag to better determine valid drop positions - Ensure consistent behavior when dragging toggles between fixed and sliding rows - Allow continuous drag operations between rows in both directions
- Reduce animation duration to 150ms (from 200ms) - Use simpler easing functions (Linear or OutQuad instead of InOutQuad) - Reduce cacheBuffer size Signed-off-by: Timo Könnecke <[email protected]> Signed-off-by: Timo Könnecke <[email protected]>
- Increase intervals for less critical animations - Use running state management to disable timers when not needed Signed-off-by: Timo Könnecke <[email protected]>
…figuration in asteroid-settings
- Replaced batteryMeter Item in slotList delegate with ValueMeter component for the battery preview, enabling reuse for other value types. - Moved battery-specific color logic to ValueMeter's fillColor property, matching QuickSettings.qml behavior. - Updated anchoring to maintain layout consistency. - Removed erroneous particleTimer addition, as ValueMeter handles particle logic internally. - Ensured compatibility with options.value settings for animations, colors, and particle design.
Prevent list order reset when dropping a toggle below the last valid position in the sliding row. - Updated isValidDropPosition to explicitly handle boundary cases, preventing drops into the options section. - Modified MouseArea's onPositionChanged and onReleased to adjust dropIndex to the last valid toggle position. - Removed restoreOriginalOrder from abortDrag to avoid unintended list resets. - Ensured stable drag behavior at the end of the sliding row.
Ensure user-defined order of sliding and fixed row toggles persists on page restart. - Modified refreshModel to use sliderToggles.value directly, preserving user-defined order for sliding row. - Split sliding row population into two loops: available toggles first, then unavailable toggles. - Modified refreshModel to use fixedToggles.value directly, preserving user-defined order for fixed row. - Split fixed row population into two loops: available toggles first, then unavailable toggles to fill slots.
2e44584 to
5f17346
Compare
As suggested by @MagenFire. - Moved toggle logic to dragArea MouseArea's onReleased, using press duration (<400ms) to detect short taps. - Preserved long-press (>400ms) for drag-and-drop with real-time item reordering. - Removed checkmarkIcon MouseArea, making it a visual indicator only. Co-authored-by: Darrel Griët <[email protected]> Signed-off-by: Timo Könnecke <[email protected]>
Eliminate ListView startup animations for instant, static display. - Use Loader to defer ListView creation until model is fully populated. - Apply forceLayout() to pre-position delegates, avoiding render glitches.
Polish QuickSettingsPage UI for consistency and better visibility. - Remove checkmark icon from ListView delegate and dragProxy for cleaner layout. - Remove PageHeader, set ListView header height to 0, and update autoScrollTimer minContentY to 0. - Increase rowHeight to Dims.h(18) and use for all rows, removing labelHeight property. - Increase iconRectangle size to Dims.w(16) and leftMargin to Dims.l(14) in delegate and dragProxy. - Adjust opacity: iconRectangle (0.2 unavailable, 0.7 enabled), toggleIcon (0.4 unavailable, 0.8 disabled), Label (0.5 unavailable, 0.6 disabled), dragProxy (0.8 icon, 0.9 text). - Increase label font.pixelSize to Dims.l(6) for better readability. - Extend longPressTimer interval to 500ms to prevent accidental drags. - Set boundsBehavior to Flickable.DragAndOvershootBounds for scroll feedback and to fix toggle misfires.
…ons and Content from the slidng and fixed row labels
6976944 to
c270b3a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the high amount of changes I've decided to make some changes myself via https://github.com/MagneFire/asteroid-settings/commits/add-quicksettingsPage/
This also helps me understand some of the logic used in this PR.
Also, given the huge amount of commits (50+) I think it's best to just use the GitHub squash function once this PR is ready. A sensible name for the commit would probable be: Add QuickPanel settings page
| newEnabled[toggleId] = !newEnabled[toggleId]; | ||
| toggleEnabled.value = newEnabled; | ||
| } else { | ||
| longPressTimer.stop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
longPressTimer.stop(); is used in all branches of this if-statement. Why not move it outside this if-statement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid using these magic numbers, when someone decides to add or/remove options or changes the fixed row count, things might break.
| return i; | ||
| } | ||
| } | ||
| return 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is 3 returned here?
| function ensureSliderLabelPosition() { | ||
| var sliderIndex = findSliderLabelIndex(); | ||
| if (sliderIndex !== 3) { | ||
| slotModel.move(sliderIndex, 3, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again why 3 here? Is it to ensure that the slider label is after position 2 (i.e. the fixed toggles)?
| return i; | ||
| } | ||
| } | ||
| return slotModel.count - 6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is 6 subtracted here? Is it because there are 6 options, and in case you can't find the label, just get the length and subtract the amount of options?
Add QuickSettingsPage.qml for QuickSettings Customization in asteroid-settings
This pull request introduces
QuickSettingsPage.qmlto theasteroid-settingsrepository, a requirement for the AsteroidOS QuickSettings redesign and depends on the addition of the required qml components in this PR: AsteroidOS/qml-asteroid#58. This new settings page controls theQuickSettings.qmlpanel inasteroid-launcherby providing a user-friendly interface to customize the appearance, layout, and behavior of the QuickSettings panel. Most notably, it introduces a novel feature to AsteroidOS: the ability to reorder and enable/disable toggles and buttons in both the fixed and sliding rows via an intuitive drag-and-drop implementation. Below is a detailed feature breakdown.The new page is sorted to 3rd place in the main.qml to account for expected long translation strings and to reflect the importance of the feature set.
QuickSettingsPage uses the new ios-quicksettings icon and reflects the current selected batteryBottom option to display the icon in same state as the actual QuickSettings panel layout.
Features of QuickSettingsPage.qml
1. Toggle and Button Reordering via Drag-and-Drop
Description:

QuickSettingsPage.qmlenables users to reorder toggles and buttons in the QuickSettings panel’s fixed (two toggles) and sliding (multiple toggles in rows of three) rows. The drag-and-drop implementation is sophisticated, respecting the two-row structure while ensuring usability on a smartwatch’s small screen. Users long-press (400ms) a toggle to initiate dragging, move it to a new position, and release to confirm. The system prevents invalid drops (e.g., on labels or unavailable toggles) and maintains the fixed row’s maximum length (two toggles). Auto-scrolling activates when dragging near the screen’s top or bottom, with a dynamic scroll speed based on proximity to the edge (threshold: 20% of screen height).Implementation Details:
ListView(slotList) with aListModel(slotModel) to represent toggles, labels, and configuration options.MouseArea(dragArea) handles long-press detection and drag events, with adragProxyitem displaying the dragged toggle’s icon and name.moveItems,isValidDropPosition, andensureSliderLabelPositionmanage row boundaries and toggle availability, ensuring seamless cross-row moves (fixed ↔ sliding).displaced,add,move) withNumberAnimation(150ms,OutQuadeasing) provide smooth visual feedback.Example Use Case:
A user drags the
brightnessTogglefrom the sliding row to the fixed row, replacinglockButton. The interface updates instantly, and the new order is saved tofixedTogglesandsliderTogglesconfigurations, persisting across sessions.2. Enable/Disable Toggles and Buttons
Description:

Users can enable or disable individual toggles/buttons, controlling their visibility in the QuickSettings panel. Each toggle is represented with a checkmark icon (
ios-checkmark-circle-outlinewhen enabled,ios-circle-outlinewhen disabled). Tapping the checkmark toggles the state, with constraints to ensure at least one toggle remains active in the fixed row and two in the sliding row for usability. This feature allows users to declutter the QuickSettings panel by hiding unused toggles.Implementation Details:
toggleEnabledConfigurationValue, a key-value object mapping toggle IDs to boolean values.MouseAreaon thecheckmarkIconupdatestoggleEnabled.value, with logic in theonClickedhandler to enforce minimum active toggle counts.slotModeldynamically reflects enabled/disabled states, updating toggle opacity (1.0 for enabled, 0.5 for disabled) and icon visibility.Example Use Case:
A user disables the
musicButtonbecause they don’t use the music app. The button disappears from the sliding row inQuickSettings.qml, streamlining the interface, and the change is saved totoggleEnabled.3. Visual Appearance Customization
Description:
The page allows users to customize the QuickSettings panel’s visual appearance through configuration options, including:
ValueMeter) appears at the bottom or top of the panel (batteryBottom).batteryColored).batteryAnimation).These options are presented as
LabeledSwitchcomponents for boolean settings and anOptionCyclerfor particle designs, with a preview via aValueMeterdisplaying the current battery percentage.Implementation Details:
optionsConfigurationValue, with keys likebatteryBottom,batteryColored,batteryAnimation, andparticleDesign.LabeledSwitchcomponents bind tooptions.valueproperties, updating the configuration on change.OptionCyclermanages theparticleDesignkey, cycling throughparticleDesignsarray with opacity feedback (1.0 when animations enabled, 0.5 when disabled).ValueMeterat the bottom of the page previews the battery meter’s appearance, reflecting currentoptionssettings (e.g., colored fill, particle design).Example Use Case:
A user enables
batteryColoredand selects "flashes" viaOptionCycler. The QuickSettings panel’s battery meter now shows a color-coded fill (green >50%, yellow 20–50%, red <20%) with flash-shaped particles during charging, enhancing visual appeal.4. Intuitive and Localized UI
Description:
The page is designed for intuitive use on a smartwatch, with a clean layout, touch-friendly controls, and full internationalization. All text (labels, toggle names, configuration options) uses
qsTrIdfor translation via Weblate, ensuring accessibility across languages. The UI includes visual cues like highlight bars (HighlightBar) for pressed states, italicized section labels (Fixed Row Content,Sliding Row Content,Options), and consistent iconography (e.g.,ios-*icons for toggles).Implementation Details:
PageHeaderdisplays the title "Quick Settings" (qsTrId("id-quicksettings-page")).slotModelorganizes content into sections with translatable labels (qsTrId("id-fixed-row"),qsTrId("id-sliding-row"),qsTrId("id-options")).qsTrId(e.g.,id-toggle-brightness,id-battery-bottom) for Weblate compatibility.HighlightBarfor touch interactions and opacity transitions (e.g., 0.7 for enabled toggle icons, 0.3 for disabled).5. Robust Configuration Management
Description:
The page ensures persistent and reliable configuration management by synchronizing changes to
fixedToggles,sliderToggles,toggleEnabled, andoptionsConfigurationValueobjects. It sorts toggles by availability (available first, then bytoggleOptionsindex, unavailable alphabetically) and fills empty fixed row slots with available toggles. A caching mechanism (toggleCache) optimizes toggle lookups for lag mitigated scrolling, and thesaveConfigurationfunction updates settings in real-time.Implementation Details:
sortTogglessorts toggle IDs based on availability and index, used inrefreshModelto populateslotModel.findToggleusestoggleCacheto reduce lookup overhead for toggle metadata (name, icon, availability).saveConfigurationextracts toggle IDs fromslotModelintofixedTogglesandsliderTogglesarrays, ensuring persistence.countFixedTogglesandisToggleInFixedRowenforce layout constraints, whilerefreshModelhandles dynamic updates.Example Use Case:
A user reorders
wifiToggleto the fixed row and disablesbluetoothToggle. The changes are instantly saved tofixedTogglesandtoggleEnabled, ensuring the QuickSettings panel reflects the new layout and toggle states on the next access.6. Preview and Feedback Mechanisms
Description:
A live preview of the battery meter (
ValueMeter) at the bottom of the page reflects currentoptionssettings, providing immediate feedback on appearance changes. The drag-and-drop system includes visual feedback viadragProxyandHighlightBar, and auto-scrolling enhances usability for long lists. The page enforces valid drop positions, preventing users from placing toggles below unavailable ones or on non-toggle items.Implementation Details:
ValueMeterin thedisplaytype slot shows battery percentage with currentfillColor,particleDesign, andenableAnimationssettings.dragProxymirrors the dragged toggle’s appearance, withHighlightBarindicating active dragging.autoScrollTimer(16ms interval) adjustsslotList.contentYdynamically, with speed proportional to drag proximity to screen edges.isValidDropPositionchecks drop validity, considering toggle availability and section boundaries.Example Use Case:
While adjusting
particleDesignto "bubbles", the user sees theValueMeterpreview update with bubble-shaped particles, confirming the change before applying it to the QuickSettings panel.Changes
QuickSettingsPage.qmltoasteroid-settingsfor QuickSettings customization.batteryBottom,batteryColored,batteryAnimation,particleDesign) with live preview viaValueMeter.qsTrIdfor all user-facing text, compatible with Weblate.toggleCache) and dynamic sorting (sortToggles).Commit Notes
QuickSettings.qmlinasteroid-launcherensures seamless customization of the QuickSettings panel.This PR enhances the AsteroidOS QuickSettings experience by giving users control over the panel’s layout and appearance, with a robust and intuitive interface.
Please review and provide feedback!