Skip to content

Commit a27a77b

Browse files
committed
v1.0.1: Fix backup path structure and improve UI sync
- Fixed backup directory structure (SurfManagerBackups -> Documents/SurfManager) - Auto-backups now in Documents/SurfManager/auto-backup - Notes in Documents/SurfManager/notes - Improved auto-backup toggle button with badge counter - Fixed Reset Data tab sync with App Configuration - Better scroll height calculation for dynamic content - Skip internal folders when scanning sessions
1 parent 33e9438 commit a27a77b

File tree

5 files changed

+126
-45
lines changed

5 files changed

+126
-45
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
All notable changes to SurfManager will be documented in this file.
44

5+
## [1.0.1] - 2025-12-05
6+
7+
### Fixed
8+
- **Backup Path Structure**: Fixed incorrect backup directory naming
9+
- Changed from `SurfManagerBackups` to `Documents/SurfManager/backup`
10+
- Auto-backups now stored in `Documents/SurfManager/auto-backup`
11+
- Notes stored in `Documents/SurfManager/notes`
12+
- Cleaner and more organized folder structure
13+
14+
### Improved
15+
- **Auto-Backup Toggle Button**: Better UX with badge counter
16+
- Shows `Show Auto-Backup (N)` with count of available backups
17+
- Changes to `← Back to Sessions` when active for clarity
18+
- Real-time badge update on refresh
19+
- **Reset Data Tab Sync**: Fixed app list not syncing with App Configuration
20+
- Immediate UI update when toggling apps active/inactive
21+
- Proper height calculation based on number of programs
22+
- No more "social distancing" spacing with few programs
23+
- **Session Scanning**: Skip internal folders (sessions, auto-backups) when listing backups
24+
25+
### Technical
26+
- Updated `platform_adapter.py` with new path structure
27+
- Added `get_app_dir()` method for app root directory
28+
- Improved `_update_scroll_height()` for dynamic sizing
29+
- Enhanced `refresh_ui()` with geometry updates and event processing
30+
31+
---
32+
533
## [1.0.0] - 2025-12-04
634

735
### Highlights

app/core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ConfigManager:
2525
def __init__(self):
2626
self.adapter = get_platform_adapter()
2727
self.documents_path = str(self.adapter.get_documents_dir())
28-
self.surfmanager_path = str(self.adapter.get_backup_dir("SurfManager"))
28+
self.surfmanager_path = str(self.adapter.get_app_dir("SurfManager"))
2929

3030
def get_path(self, key: str) -> str:
3131
"""Get path by key."""

app/core/platform_adapter.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -132,32 +132,22 @@ def normalize_path(self, path: str) -> Path:
132132
# Resolve path (handles .. and .)
133133
return path_obj.resolve()
134134

135+
def get_app_dir(self, app_name: str = "SurfManager", username: str = None) -> Path:
136+
"""Get application root directory in Documents."""
137+
docs = self.get_documents_dir(username)
138+
return docs / app_name
139+
135140
def get_backup_dir(self, app_name: str = "SurfManager", username: str = None) -> Path:
136141
"""Get backup directory for the application."""
137-
docs = self.get_documents_dir(username)
138-
139-
if self.system == "Windows":
140-
return docs / f"{app_name}Backups"
141-
else:
142-
return docs / f".{app_name.lower()}/backups"
142+
return self.get_app_dir(app_name, username) / "backup"
143143

144144
def get_session_dir(self, app_name: str = "SurfManager", username: str = None) -> Path:
145145
"""Get session directory for the application."""
146-
backup_dir = self.get_backup_dir(app_name, username)
147-
148-
if self.system == "Windows":
149-
return backup_dir / "sessions"
150-
else:
151-
return backup_dir / "sessions"
146+
return self.get_backup_dir(app_name, username) / "sessions"
152147

153148
def get_auto_backup_dir(self, app_name: str, username: str = None) -> Path:
154149
"""Get auto-backup directory for an app."""
155-
backup_dir = self.get_backup_dir(username=username)
156-
157-
if self.system == "Windows":
158-
return backup_dir / "auto-backups" / app_name
159-
else:
160-
return backup_dir / "auto-backups" / app_name
150+
return self.get_app_dir(app_name, username) / "auto-backup"
161151

162152
# Platform detection helpers
163153
def is_windows(self) -> bool:

app/gui/tab_account.py

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -390,13 +390,13 @@ def _create_sessions_section(self, parent):
390390
toolbar.addWidget(self.search)
391391

392392
# Auto-backups toggle button
393-
self.auto_backup_toggle_btn = QPushButton("Auto-Backups")
394-
self.auto_backup_toggle_btn.setFixedWidth(100)
393+
self.auto_backup_toggle_btn = QPushButton("Show Auto-Backup")
394+
self.auto_backup_toggle_btn.setFixedWidth(140)
395395
self.auto_backup_toggle_btn.setFixedHeight(24)
396396
self.auto_backup_toggle_btn.setCheckable(True)
397-
self.auto_backup_toggle_btn.setToolTip("Toggle auto-backups view")
397+
self.auto_backup_toggle_btn.setToolTip("Click to show auto-backups only")
398398
self.auto_backup_toggle_btn.clicked.connect(self._toggle_auto_backups_view)
399-
self._update_auto_backup_toggle_style()
399+
self._update_auto_backup_btn()
400400
toolbar.addWidget(self.auto_backup_toggle_btn)
401401

402402
sessions_layout.addLayout(toolbar)
@@ -559,11 +559,13 @@ def _refresh(self):
559559
all_sessions = []
560560

561561
if self.show_auto_backups:
562-
# Show auto-backups from cross-platform auto-backups folder
563-
auto_backup_path = str(self.config.get_platform_path("backup") / "auto-backups")
564-
if os.path.exists(auto_backup_path):
565-
for app_name in os.listdir(auto_backup_path):
566-
app_folder = os.path.join(auto_backup_path, app_name)
562+
# Show auto-backups from Documents/SurfManager/auto-backupss/app_name/auto-xxx
563+
docs = self.config.documents_path
564+
auto_backup_base = os.path.join(docs, "SurfManager", "auto-backups")
565+
566+
if os.path.exists(auto_backup_base):
567+
for app_name in os.listdir(auto_backup_base):
568+
app_folder = os.path.join(auto_backup_base, app_name)
567569
if not os.path.isdir(app_folder):
568570
continue
569571

@@ -593,8 +595,8 @@ def _refresh(self):
593595
if not os.path.isdir(app_folder):
594596
continue
595597

596-
# Skip auto-backups folder completely
597-
if app_name.lower() == "auto-backups":
598+
# Skip special folders
599+
if app_name.lower() in ("auto-backups", "sessions"):
598600
continue
599601

600602
# Skip if not in filter
@@ -627,6 +629,9 @@ def _refresh(self):
627629
self.count_label.setText(f"{total} auto-backup(s)")
628630
else:
629631
self.count_label.setText(f"{total} session(s)")
632+
633+
# Update auto-backup button badge
634+
self._update_auto_backup_btn()
630635

631636
for row, (app, name, created_dt) in enumerate(all_sessions):
632637
# Row number
@@ -690,8 +695,9 @@ def _refresh(self):
690695
def _get_size(self, app, name):
691696
try:
692697
if self.show_auto_backups:
693-
# Auto-backups path
694-
folder = str(self.config.get_platform_path("backup") / "auto-backups" / app / name)
698+
# Auto-backups path: Documents/SurfManager/auto-backups/app/name
699+
docs = self.config.documents_path
700+
folder = os.path.join(docs, "SurfManager", "auto-backups", app, name)
695701
else:
696702
# Regular sessions path
697703
folder = os.path.join(self.backup_path, app, name)
@@ -718,16 +724,38 @@ def _filter_table(self, text):
718724
def _toggle_auto_backups_view(self, checked):
719725
"""Toggle between normal sessions and auto-backups view."""
720726
self.show_auto_backups = checked
721-
self._update_auto_backup_toggle_style()
722-
self._refresh() # Refresh to show different data
727+
self._refresh() # Refresh will update button and show different data
723728

724729
# Clear search when switching views
725730
self.search.clear()
731+
732+
def _count_auto_backups(self) -> int:
733+
"""Count total auto-backups across all apps."""
734+
count = 0
735+
# Auto-backups are stored in Documents/SurfManager/auto-backups/app_name/auto-xxx
736+
docs = self.config.documents_path
737+
auto_backup_base = os.path.join(docs, "SurfManager", "auto-backups")
738+
739+
if os.path.exists(auto_backup_base):
740+
for app_name in os.listdir(auto_backup_base):
741+
app_folder = os.path.join(auto_backup_base, app_name)
742+
if os.path.isdir(app_folder):
743+
try:
744+
for item in os.listdir(app_folder):
745+
item_path = os.path.join(app_folder, item)
746+
if os.path.isdir(item_path) and item.startswith("auto-"):
747+
count += 1
748+
except (PermissionError, OSError):
749+
pass
750+
return count
751+
752+
def _update_auto_backup_btn(self):
753+
"""Update auto-backup toggle button text and style."""
754+
count = self._count_auto_backups()
726755

727-
def _update_auto_backup_toggle_style(self):
728-
"""Update auto-backup toggle button style."""
729756
if self.show_auto_backups:
730-
self.auto_backup_toggle_btn.setText("Auto-Backups [ON]")
757+
self.auto_backup_toggle_btn.setText("← Back to Sessions")
758+
self.auto_backup_toggle_btn.setToolTip("Click to go back to manual sessions")
731759
self.auto_backup_toggle_btn.setStyleSheet("""
732760
QPushButton {
733761
background-color: #0d7377;
@@ -742,7 +770,11 @@ def _update_auto_backup_toggle_style(self):
742770
}
743771
""")
744772
else:
745-
self.auto_backup_toggle_btn.setText("Auto-Backups")
773+
if count > 0:
774+
self.auto_backup_toggle_btn.setText(f"Show Auto-Backup ({count})")
775+
else:
776+
self.auto_backup_toggle_btn.setText("Show Auto-Backup")
777+
self.auto_backup_toggle_btn.setToolTip("Click to show auto-backups only")
746778
self.auto_backup_toggle_btn.setStyleSheet("""
747779
QPushButton {
748780
background-color: #3d3d3d;

app/gui/tab_reset.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from PyQt6.QtWidgets import (
99
QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QGroupBox,
1010
QLabel, QPushButton, QLineEdit, QTextEdit, QScrollArea, QProgressBar,
11-
QMessageBox
11+
QMessageBox, QSizePolicy
1212
)
1313
from PyQt6.QtCore import Qt
1414
import qtawesome as qta
@@ -132,12 +132,11 @@ def _create_programs_section(self, layout):
132132

133133
programs_layout.addWidget(self.empty_placeholder)
134134

135-
# Scroll area for programs (max 8 visible, scroll if more)
135+
# Scroll area for programs (dynamic height based on content)
136136
self.scroll_area = QScrollArea()
137137
self.scroll_area.setWidgetResizable(True)
138138
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
139-
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
140-
self.scroll_area.setMaximumHeight(240) # ~8 compact rows
139+
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
141140
self.scroll_area.setStyleSheet("""
142141
QScrollArea { border: none; background: transparent; }
143142
QScrollBar:vertical { background: #2d2d2d; width: 8px; border-radius: 4px; }
@@ -557,6 +556,7 @@ def _load_apps_from_config(self):
557556
# Show empty placeholder
558557
self.empty_placeholder.show()
559558
self.scroll_area.hide()
559+
self._update_scroll_height()
560560
return
561561

562562
# Add each active app
@@ -573,6 +573,9 @@ def _load_apps_from_config(self):
573573
break
574574

575575
self.add_program(display_name, app_name, detected_path)
576+
577+
# Update scroll area height to fit content
578+
self._update_scroll_height()
576579

577580
def _clear_programs(self):
578581
"""Clear all program widgets from grid."""
@@ -594,6 +597,29 @@ def _clear_programs(self):
594597
self.scroll_area.hide()
595598
self.empty_placeholder.show()
596599

600+
def _update_scroll_height(self):
601+
"""Update scroll area height based on number of programs."""
602+
num_programs = len(self.program_widgets)
603+
604+
if num_programs == 0:
605+
self.scroll_area.setFixedHeight(0)
606+
return
607+
608+
# Each row is ~30px (24px widget + 6px spacing)
609+
row_height = 30
610+
max_visible = 8 # Max rows before scrolling
611+
612+
if num_programs <= max_visible:
613+
# Fit exactly to content (no scroll needed)
614+
height = num_programs * row_height + 10 # +10 for padding
615+
self.scroll_area.setFixedHeight(height)
616+
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
617+
else:
618+
# Enable scrolling for many programs
619+
height = max_visible * row_height + 10
620+
self.scroll_area.setFixedHeight(height)
621+
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
622+
597623
def refresh_ui(self):
598624
"""Refresh UI when app configs change."""
599625
# Force reload from disk
@@ -602,8 +628,13 @@ def refresh_ui(self):
602628
# Rebuild UI
603629
self._load_apps_from_config()
604630

605-
# Force update layout
606-
self.programs_grid.update()
607-
self.scroll_area.update()
631+
# Force update layout and geometry
632+
self.programs_grid.updateGeometry()
633+
self.scroll_area.updateGeometry()
634+
self.programs_group.updateGeometry()
635+
636+
# Process events to ensure UI updates immediately
637+
from PyQt6.QtWidgets import QApplication
638+
QApplication.processEvents()
608639

609640
self.log("[Refresh] Programs list updated")

0 commit comments

Comments
 (0)