Skip to content

Commit 41460a9

Browse files
feat: QoL improvements
1 parent f79588c commit 41460a9

File tree

6 files changed

+373
-57
lines changed

6 files changed

+373
-57
lines changed

.github/workflows/release.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,14 @@ jobs:
191191
Get-ChildItem dist -Force
192192
echo ""
193193
if (Test-Path "dist\glimpse.exe") {
194-
$newName = "glimpse-${{ needs.semantic-release.outputs.new-release-version }}-windows-${{ steps.arch-windows.outputs.arch }}.exe"
194+
$newName = "glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-windows-${{ steps.arch-windows.outputs.arch }}.exe"
195195
Copy-Item "dist\glimpse.exe" $newName
196196
echo "Successfully created $newName"
197197
echo "File created:"
198198
Get-ChildItem $newName -Force
199199
} elseif (Test-Path "dist\glimpse") {
200200
echo "Found 'glimpse' without .exe extension - renaming it"
201-
$newName = "glimpse-${{ needs.semantic-release.outputs.new-release-version }}-windows-${{ steps.arch-windows.outputs.arch }}.exe"
201+
$newName = "glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-windows-${{ steps.arch-windows.outputs.arch }}.exe"
202202
Copy-Item "dist\glimpse" $newName
203203
echo "Successfully created $newName from 'glimpse'"
204204
echo "File created:"
@@ -233,11 +233,11 @@ jobs:
233233
if: matrix.os == 'ubuntu-latest'
234234
run: |
235235
# Create renamed binary
236-
cp dist/glimpse glimpse-${{ needs.semantic-release.outputs.new-release-version }}-linux-${{ steps.arch-linux.outputs.arch }}
236+
cp dist/glimpse glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-linux-${{ steps.arch-linux.outputs.arch }}
237237
238238
# Create tar.gz archive
239239
cd dist
240-
tar -czf ../glimpse-${{ needs.semantic-release.outputs.new-release-version }}-linux-${{ steps.arch-linux.outputs.arch }}.tar.gz glimpse
240+
tar -czf ../glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-linux-${{ steps.arch-linux.outputs.arch }}.tar.gz glimpse
241241
cd ..
242242
243243
- name: Create .deb package (Linux)
@@ -333,7 +333,7 @@ jobs:
333333
if: matrix.os == 'macos-latest'
334334
run: |
335335
# Create renamed binary
336-
cp dist/glimpse glimpse-${{ needs.semantic-release.outputs.new-release-version }}-macos-${{ steps.arch-macos.outputs.arch }}
336+
cp dist/glimpse glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-macos-${{ steps.arch-macos.outputs.arch }}
337337
338338
# Create a temporary directory for the DMG contents
339339
mkdir -p dmg-contents
@@ -344,13 +344,13 @@ jobs:
344344
-srcfolder dmg-contents \
345345
-ov \
346346
-format UDZO \
347-
glimpse-${{ needs.semantic-release.outputs.new-release-version }}-macos-${{ steps.arch-macos.outputs.arch }}.dmg
347+
glimpse-viewer-${{ needs.semantic-release.outputs.new-release-version }}-macos-${{ steps.arch-macos.outputs.arch }}.dmg
348348
349349
- name: Verify artifacts before upload (Windows)
350350
if: matrix.os == 'windows-latest'
351351
run: |
352352
echo "=== FILES AVAILABLE FOR UPLOAD ==="
353-
Get-ChildItem . -Filter "glimpse-*" -Force | Select-Object Name, Length, LastWriteTime
353+
Get-ChildItem . -Filter "glimpse-viewer-*" -Force | Select-Object Name, Length, LastWriteTime
354354
echo ""
355355
echo "=== ALL FILES IN CURRENT DIRECTORY ==="
356356
Get-ChildItem . -Force
@@ -360,15 +360,15 @@ jobs:
360360
if: matrix.os != 'windows-latest'
361361
run: |
362362
echo "=== FILES AVAILABLE FOR UPLOAD ==="
363-
ls -la glimpse-* 2>/dev/null || echo "No glimpse-* files found with ls"
363+
ls -la glimpse-viewer-* 2>/dev/null || echo "No glimpse-viewer-* files found with ls"
364364
echo "=== ALL FILES IN CURRENT DIRECTORY ==="
365365
ls -la
366366
367367
- name: Upload artifacts
368368
uses: actions/upload-artifact@v4
369369
with:
370-
name: glimpse-${{ matrix.name }}
371-
path: glimpse-*
370+
name: glimpse-viewer-${{ matrix.name }}
371+
path: glimpse-viewer-*
372372
if-no-files-found: error
373373

374374
# Create the actual release with binaries
@@ -409,7 +409,7 @@ jobs:
409409
- name: Prepare release assets
410410
run: |
411411
mkdir -p release-assets
412-
find ./artifacts -name "*.exe" -o -name "*.tar.gz" -o -name "*.deb" -o -name "*.dmg" | xargs -I {} cp {} release-assets/
412+
find ./artifacts -name "glimpse-viewer-*.exe" -o -name "glimpse-viewer-*.tar.gz" -o -name "glimpse-viewer-*.deb" -o -name "glimpse-viewer-*.dmg" | xargs -I {} cp {} release-assets/
413413
ls -la release-assets/
414414
415415
- name: Create version file for semantic-release

README.md

Lines changed: 107 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,24 @@
88

99
A cross-platform desktop application for viewing random images from folders or collections. Useful for reference studies, browsing large image libraries, and rediscovering artwork.
1010

11+
[![Latest Release](https://img.shields.io/github/v/release/radioactiveorange/glimpse)](https://github.com/radioactiveorange/glimpse/releases/latest)
12+
[![Downloads](https://img.shields.io/github/downloads/radioactiveorange/glimpse/total)](https://github.com/radioactiveorange/glimpse/releases)
13+
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
14+
15+
## 📋 Table of Contents
16+
17+
- [✨ Features](#-features)
18+
- [📦 Installation](#-installation)
19+
- [🚀 Quick Start](#-quick-start)
20+
- [🎯 Use Cases](#-use-cases)
21+
- [⌨️ Keyboard Shortcuts](#️-keyboard-shortcuts)
22+
- [🖱️ Mouse Controls](#️-mouse-controls)
23+
- [🛠️ Advanced Features](#️-advanced-features)
24+
- [🏗️ Technical Details](#️-technical-details)
25+
- [🎨 Screenshots](#-screenshots)
26+
- [🤝 Contributing](#-contributing)
27+
- [📝 License](#-license)
28+
1129
## ✨ Features
1230

1331
### 🎲 **Collections & Random Viewing**
@@ -31,64 +49,60 @@ A cross-platform desktop application for viewing random images from folders or c
3149
- Minimal UI design
3250

3351
### 💾 **Collection Management**
34-
- Multi-folder collections
52+
- Multi-folder collections with professional startup dialog
3553
- Persistent storage between sessions
54+
- Collection editing, deletion, and organization
55+
- Quick folder location access
3656
- Cross-platform support (Windows, macOS, Linux)
3757

3858
---
3959

40-
## 🚀 Quick Start
60+
## 📦 Installation
4161

42-
### Installation
62+
### 🎯 Recommended: Download Pre-built Binaries
4363

44-
**Prerequisites:**
45-
- Python 3.13+
46-
- [uv](https://docs.astral.sh/uv/) (fast Python package manager) - Install with: `pip install uv`
64+
**[📥 Download Latest Release](https://github.com/radioactiveorange/glimpse/releases/latest)**
4765

48-
**Option 1: Run from Source**
49-
```bash
50-
# Clone the repository
51-
git clone https://github.com/radioactiveorange/glimpse.git
52-
cd glimpse
66+
| Platform | File | Installation |
67+
|----------|------|--------------|
68+
| **Windows** | `glimpse-viewer-*.exe` | Download and run directly |
69+
| **macOS** | `glimpse-viewer-*.dmg` | Download, mount, and drag to Applications |
70+
| **Linux** | `glimpse-viewer-*.deb` | `sudo dpkg -i glimpse-viewer-*.deb` |
71+
| **Linux** | `glimpse-viewer-*.tar.gz` | Extract and run `./glimpse` |
5372

54-
# Create and activate virtual environment with uv (recommended)
55-
uv venv
56-
source .venv/bin/activate # On Windows: .venv\Scripts\activate
73+
### 🛠️ Development Installation
5774

58-
# Install dependencies
59-
uv pip install -e .
60-
61-
# Run the application
62-
uv run main.py
63-
```
75+
**Prerequisites:**
76+
- Python 3.13+
77+
- [uv](https://docs.astral.sh/uv/) (fast Python package manager) - Install with: `pip install uv`
6478

65-
**Alternative with uv (no manual venv activation needed):**
79+
**Run from Source:**
6680
```bash
6781
# Clone the repository
6882
git clone https://github.com/radioactiveorange/glimpse.git
6983
cd glimpse
7084

71-
# Install dependencies (uv handles venv automatically)
72-
uv pip install -e .
85+
# Install dependencies and run (uv handles venv automatically)
86+
uv pip install pyside6
7387

7488
# Run the application
7589
uv run main.py
7690
```
7791

78-
**Option 2: Build Executable**
92+
**Build Your Own Executable:**
7993
```bash
8094
# Install build dependencies
81-
uv pip install -e ".[build]"
95+
uv pip install pyinstaller pyside6
8296

83-
# Build standalone executable
84-
pyinstaller --noconfirm --onefile --windowed --icon=app_icon.ico --name=glimpse main.py
97+
# Build standalone executable using the spec file
98+
pyinstaller glimpse.spec
8599

86100
# Find your executable in the dist/ folder
87101
```
88102

89103
---
90104

91-
### First Launch
105+
## 🚀 Quick Start
92106

93107
1. Create a collection by clicking "New Collection" and selecting folders
94108
2. Configure timer settings (or disable for manual browsing)
@@ -112,9 +126,15 @@ Alternatively, use "Quick Shuffle Folder" to browse any folder immediately.
112126
| Shortcut | Action |
113127
|----------|--------|
114128
| `` `` | Navigate previous/next image |
129+
| `Space` | Play/pause timer |
115130
| `Ctrl` `+` | Zoom in |
116131
| `Ctrl` `-` | Zoom out |
117-
| `Ctrl` `0` | Reset zoom to 100% |
132+
| `Ctrl` `0` | Reset zoom and center image |
133+
| `F` | Flip image horizontally |
134+
| `G` | Toggle grayscale mode |
135+
| `B` | Cycle background modes (black/gray/adaptive) |
136+
| `H` | Toggle history panel |
137+
| `Esc` | Switch collection/folder |
118138
| `Right-click` | Open context menu |
119139

120140
## 🖱️ Mouse Controls
@@ -128,27 +148,50 @@ Alternatively, use "Quick Shuffle Folder" to browse any folder immediately.
128148
## 🛠️ Advanced Features
129149

130150
### Collection Management
131-
- Edit collections (rename, manage folders)
132-
- Delete collections
151+
- Professional startup dialog with ShuffleBird-inspired design
152+
- Edit collections (rename, manage folders)
153+
- Delete collections with confirmation
133154
- Auto-sorted by recent usage
155+
- Quick folder location access button
156+
- Async loading for large collections (72K+ images tested)
134157

135158
### Image Processing
136159
- Supported formats: JPG, JPEG, PNG, BMP, GIF
137160
- Recursive search in subfolders
138-
- Grayscale mode and flip controls
161+
- Image transformations: flip horizontal/vertical, grayscale
162+
- Smart image caching for performance
139163

140164
### Customization
141-
- Background modes: Black, Gray, Adaptive Color
142-
- Timer intervals: 30s, 1min, 2min, 5min, or custom
143-
- Configurable history panel
165+
- Background modes: Black, Gray, Smart Adaptive Color
166+
- Timer intervals: 30s, 1min, 2min, 5min, 10min, 30min, or custom
167+
- Configurable history panel with thumbnails
168+
- Professional button styling with SVG icons
144169

145170
## 🏗️ Technical Details
146171

147-
- Framework: PySide6 (Qt for Python)
148-
- Modular architecture
149-
- JSON-based collection storage
150-
- Cross-platform settings and data directories
151-
- Image caching for smooth performance
172+
- **Framework**: PySide6 (Qt for Python)
173+
- **Architecture**: Clean modular structure with UI/core separation
174+
- **Collection Storage**: JSON files in platform-appropriate directories:
175+
- Linux: `~/.local/share/glimpse/collections/`
176+
- Windows: `%LOCALAPPDATA%/glimpse/collections/`
177+
- macOS: `~/Library/Application Support/glimpse/collections/`
178+
- **Image Processing**: Optimized pixmap caching and async loading
179+
- **UI Components**: Custom widgets with professional dark theme
180+
- **Icons**: SVG-based with coded fallbacks for consistency
181+
- **Settings**: QSettings with cross-platform persistence
182+
- **Threading**: Worker threads for large collection operations
183+
- **Build System**: PyInstaller with optimized spec file for all platforms
184+
- **Package Management**: Debian (.deb), DMG (macOS), and portable binaries
185+
186+
### System Requirements
187+
188+
| Platform | Minimum | Recommended |
189+
|----------|---------|-------------|
190+
| **Windows** | Windows 10 | Windows 11 |
191+
| **macOS** | macOS 10.15 | macOS 12+ |
192+
| **Linux** | Ubuntu 20.04 / equivalent | Ubuntu 22.04+ |
193+
| **RAM** | 2GB | 4GB+ |
194+
| **Storage** | 50MB | 100MB+ |
152195

153196
## 🎨 Screenshots
154197

@@ -168,7 +211,30 @@ Alternatively, use "Quick Shuffle Folder" to browse any folder immediately.
168211

169212
## 🤝 Contributing
170213

171-
This project was built collaboratively with Claude Code. Contributions, bug reports, and feature requests are welcome!
214+
This project was built collaboratively with Claude Code. We welcome:
215+
216+
- 🐛 **Bug reports** - [Open an issue](https://github.com/radioactiveorange/glimpse/issues)
217+
- 💡 **Feature requests** - [Suggest improvements](https://github.com/radioactiveorange/glimpse/issues)
218+
- 🔧 **Pull requests** - Fork and contribute code
219+
- 📖 **Documentation** - Help improve docs and examples
220+
- 🧪 **Testing** - Try on different platforms and report findings
221+
222+
### Development Setup
223+
224+
1. Fork the repository
225+
2. Follow the [Development Installation](#🛠️-development-installation) steps
226+
3. Make your changes
227+
4. Test on your platform
228+
5. Submit a pull request
229+
230+
### Reporting Issues
231+
232+
When reporting bugs, please include:
233+
- Operating system and version
234+
- Python version
235+
- Steps to reproduce
236+
- Expected vs actual behavior
237+
- Screenshots if relevant
172238

173239
---
174240

icons/folder.svg

Lines changed: 4 additions & 0 deletions
Loading

src/core/image_utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,25 @@ def _create_coded_icon(icon_type, size=24, color="#ffffff"):
430430
painter.drawLine(margin + 2, size - margin - 2, margin + 2 + head_size//2, size - margin - 2 - head_size)
431431
painter.drawLine(margin + 2, size - margin - 2, margin + size//3, size - margin - 2)
432432
painter.drawLine(margin + size//3, size - margin - 2, margin + size//3 - head_size, size - margin - 2 - head_size//2)
433+
434+
elif icon_type == "folder":
435+
# Folder icon
436+
painter.setBrush(Qt.NoBrush)
437+
painter.setPen(pen)
438+
439+
# Folder body
440+
folder_width = size - 2 * margin
441+
folder_height = (size - 2 * margin) * 2 // 3
442+
folder_y = margin + size // 6
443+
444+
# Draw folder outline
445+
painter.drawRoundedRect(margin, folder_y, folder_width, folder_height, 2, 2)
446+
447+
# Folder tab (top part)
448+
tab_width = folder_width // 3
449+
tab_height = size // 8
450+
tab_y = folder_y - tab_height // 2
451+
painter.drawRoundedRect(margin, tab_y, tab_width, tab_height, 1, 1)
433452

434453
painter.end()
435454
return QIcon(pixmap)

0 commit comments

Comments
 (0)