new: docs website (#1033)

* new: docs website
Fixes #1032

* opt.

* opt.

* opt.

* fix
This commit is contained in:
lollipopkit🏳️‍⚧️
2026-01-29 14:24:08 +08:00
committed by GitHub
parent a0a62acdbc
commit 71e757fe13
52 changed files with 5545 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

30
docs/src/assets/logo.svg Normal file
View File

@@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<!-- Background Circle -->
<circle cx="32" cy="32" r="30" fill="#02569B"/>
<!-- Terminal Window -->
<rect x="14" y="16" width="36" height="32" rx="3" fill="#fff" opacity="0.9"/>
<!-- Terminal Header -->
<rect x="14" y="16" width="36" height="8" rx="3" fill="#02569B" opacity="0.3"/>
<circle cx="19" cy="20" r="1.5" fill="#ff5f57"/>
<circle cx="24" cy="20" r="1.5" fill="#ffbd2e"/>
<circle cx="29" cy="20" r="1.5" fill="#28c940"/>
<!-- Terminal Prompt -->
<text x="18" y="34" font-family="monospace" font-size="6" fill="#333">></text>
<!-- Terminal Cursor -->
<rect x="23" y="30" width="6" height="6" fill="#02569B" opacity="0.5">
<animate attributeName="opacity" values="0.5;1;0.5" dur="1s" repeatCount="indefinite"/>
</rect>
<!-- Server Icon -->
<g transform="translate(38, 24)">
<rect x="0" y="0" width="8" height="12" rx="1" fill="#02569B"/>
<circle cx="2" cy="3" r="0.8" fill="#28c940"/>
<circle cx="4" cy="3" r="0.8" fill="#28c940"/>
<circle cx="6" cy="3" r="0.8" fill="#28c940"/>
<line x1="1" y1="8" x2="7" y2="8" stroke="#fff" stroke-width="0.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content';
import { docsLoader } from '@astrojs/starlight/loaders';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
};

View File

@@ -0,0 +1,83 @@
---
title: Bulk Import Servers
description: Import multiple servers from JSON file
---
Import multiple server configurations at once using a JSON file.
## JSON Format
:::danger[Security Warning]
**Never store plaintext passwords in files!** This JSON example shows a password field for demonstration only, but you should:
- **Prefer SSH keys** (`keyId`) instead of `pwd` - they're more secure
- **Use secret managers** or environment variables if you must use passwords
- **Delete the file immediately** after import - don't leave credentials lying around
- **Add to .gitignore** - never commit credential files to version control
:::
```json
[
{
"name": "My Server",
"ip": "example.com",
"port": 22,
"user": "root",
"pwd": "password",
"keyId": "",
"tags": ["production"],
"autoConnect": false
}
]
```
## Fields
| Field | Required | Description |
|-------|----------|-------------|
| `name` | Yes | Display name |
| `ip` | Yes | Domain or IP address |
| `port` | Yes | SSH port (usually 22) |
| `user` | Yes | SSH username |
| `pwd` | No | Password (avoid - use SSH keys instead) |
| `keyId` | No | SSH key name (from Private Keys - recommended) |
| `tags` | No | Organization tags |
| `autoConnect` | No | Auto-connect on startup |
## Import Steps
1. Create JSON file with server configurations
2. Settings → Backup → Bulk Import Servers
3. Select your JSON file
4. Confirm import
## Example
```json
[
{
"name": "Production",
"ip": "prod.example.com",
"port": 22,
"user": "admin",
"keyId": "my-key",
"tags": ["production", "web"]
},
{
"name": "Development",
"ip": "dev.example.com",
"port": 2222,
"user": "dev",
"keyId": "dev-key",
"tags": ["development"]
}
]
```
## Tips
- **Use SSH keys** instead of passwords when possible
- **Test connection** after import
- **Organize with tags** for easier management
- **Delete JSON file** after import
- **Never commit** JSON files with credentials to version control

View File

@@ -0,0 +1,72 @@
---
title: Custom Commands
description: Display custom command output on server page
---
Add custom shell commands to show their output on the server detail page.
## Setup
1. Server settings → Custom Commands
2. Enter commands in JSON format
## Basic Format
```json
{
"Display Name": "shell command"
}
```
**Example:**
```json
{
"Memory": "free -h",
"Disk": "df -h",
"Uptime": "uptime"
}
```
## Viewing Results
After setup, custom commands appear on server detail page and refresh automatically.
## Special Command Names
### server_card_top_right
Display on home page server card (top-right corner):
```json
{
"server_card_top_right": "your-command-here"
}
```
## Tips
**Use absolute paths:**
```json
{"My Script": "/usr/local/bin/my-script.sh"}
```
**Pipe commands:**
```json
{"Top Process": "ps aux | sort -rk 3 | head -5"}
```
**Format output:**
```json
{"CPU Load": "uptime | awk -F'load average:' '{print $2}'"}
```
**Keep commands fast:** Under 5 seconds for best experience
**Limit output:**
```json
{"Logs": "tail -20 /var/log/syslog"}
```
## Security
Commands run with SSH user permissions. Avoid commands that modify system state.

View File

@@ -0,0 +1,54 @@
---
title: Custom Server Logo
description: Use custom images for server cards
---
Display custom logos on server cards using image URLs.
## Setup
1. Server settings → Custom Logo
2. Enter image URL
## URL Placeholders
### {DIST} - Linux Distribution
Auto-replaced with detected distribution:
```
https://example.com/{DIST}.png
```
Becomes: `debian.png`, `ubuntu.png`, `arch.png`, etc.
### {BRIGHT} - Theme
Auto-replaced with current theme:
```
https://example.com/{BRIGHT}.png
```
Becomes: `light.png` or `dark.png`
### Combine Both
```
https://example.com/{DIST}-{BRIGHT}.png
```
Becomes: `debian-light.png`, `ubuntu-dark.png`, etc.
## Tips
- Use PNG or SVG formats
- Recommended size: 64x64 to 128x128 pixels
- Use HTTPS URLs
- Keep file sizes small
## Supported Distributions
debian, ubuntu, centos, fedora, opensuse, kali, alpine, arch, rocky, deepin, armbian, wrt
Full list: [`dist.dart`](https://github.com/lollipopkit/flutter_server_box/blob/main/lib/data/model/server/dist.dart)

View File

@@ -0,0 +1,75 @@
---
title: Hidden Settings (JSON)
description: Access advanced settings via JSON editor
---
Some settings are hidden from the UI but accessible via JSON editor.
## Access
Long-press **Settings** in drawer to open JSON editor.
## Common Hidden Settings
### serverTabUseOldUI
Use old server tab UI.
```json
{"serverTabUseOldUI": true}
```
**Type:** boolean | **Default:** false
### timeout
Connection timeout in seconds.
```json
{"timeout": 10}
```
**Type:** integer | **Default:** 5 | **Range:** 1-60
### recordHistory
Save history (SFTP paths, etc.).
```json
{"recordHistory": true}
```
**Type:** boolean | **Default:** true
### textFactor
Text scaling factor.
```json
{"textFactor": 1.2}
```
**Type:** double | **Default:** 1.0 | **Range:** 0.8-1.5
## Finding More Settings
All settings defined in [`setting.dart`](https://github.com/lollipopkit/flutter_server_box/blob/main/lib/data/store/setting.dart).
Look for:
```dart
late final settingName = StoreProperty(box, 'settingKey', defaultValue);
```
## ⚠️ Important
**Before editing:**
- **Create backup** - Wrong settings can cause app to not open
- **Edit carefully** - JSON must be valid
- **Change one at a time** - Test each setting
## Recovery
If app won't open after editing:
1. Clear app data (last resort)
2. Reinstall app
3. Restore from backup

View File

@@ -0,0 +1,118 @@
---
title: Common Issues
description: Solutions to common problems
---
## Connection Issues
### SSH Won't Connect
**Symptoms:** Timeout, connection refused, auth failed
**Solutions:**
1. **Verify server type:** Only Unix-like systems supported (Linux, macOS, Android/Termux)
2. **Test manually:** `ssh user@server -p port`
3. **Check firewall:** Port 22 must be open
4. **Verify credentials:** Username and password/key correct
### Frequent Disconnections
**Symptoms:** Terminal disconnects after inactivity
**Solutions:**
1. **Server keep-alive:**
```bash
# /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3
```
2. **Disable battery optimization:**
- MIUI: Battery → "No limits"
- Android: Settings → Apps → Disable optimization
- iOS: Enable background refresh
## Input Issues
### Can't Type Certain Characters
**Solution:** Settings → Keyboard Type → Switch to `visiblePassword`
Note: CJK input may not work after this change.
## App Issues
### App Crashes on Startup
**Symptoms:** App won't open, black screen
**Causes:** Corrupted settings, especially from JSON editor
**Solutions:**
1. **Clear app data:**
- Android: Settings → Apps → ServerBox → Clear Data
- iOS: Delete and reinstall
2. **Restore backup:** Import backup created before changing settings
### Backup/Restore Issues
**Backup not working:**
- Check storage space
- Verify app has storage permissions
- Try different location
**Restore fails:**
- Verify backup file integrity
- Check app version compatibility
## Widget Issues
### Widget Not Updating
**iOS:**
- Wait up to 30 minutes for automatic refresh
- Remove and re-add widget
- Check URL ends with `/status`
**Android:**
- Tap widget to force refresh
- Verify widget ID matches configuration in app settings
**watchOS:**
- Restart watch app
- Wait a few minutes after config change
- Verify URL format
### Widget Shows Error
- Verify ServerBox Monitor is running on server
- Test URL in browser
- Check authentication credentials
## Performance Issues
### App is Slow
**Solutions:**
- Reduce refresh rate in settings
- Check network speed
- Disable unused servers
### High Battery Usage
**Solutions:**
- Increase refresh intervals
- Disable background refresh
- Close unused SSH sessions
## Getting Help
If issues persist:
1. **Search GitHub Issues:** https://github.com/lollipopkit/flutter_server_box/issues
2. **Create New Issue:** Include app version, platform, and steps to reproduce
3. **Check Wiki:** This documentation and GitHub Wiki

View File

@@ -0,0 +1,91 @@
---
title: Home Screen Widgets
description: Add server status widgets to your home screen
---
Requires [ServerBox Monitor](https://github.com/lollipopkit/server_box_monitor) installed on your servers.
## Prerequisites
Install ServerBox Monitor on your server first. See [ServerBox Monitor Wiki](https://github.com/lollipopkit/server_box_monitor/wiki/Home) for setup instructions.
After installation, your server should have:
- HTTP/HTTPS endpoint
- `/status` API endpoint
- Optional authentication
## URL Format
```
https://your-server.com/status
```
Must end with `/status`.
## iOS Widget
### Setup
1. Long press home screen → Tap **+**
2. Search "ServerBox"
3. Choose widget size
4. Long press widget → **Edit Widget**
5. Enter URL ending with `/status`
### Notes
- Must use HTTPS (except local IPs)
- Max refresh rate: 30 minutes (iOS limit)
- Add multiple widgets for multiple servers
## Android Widget
### Setup
1. Long press home screen → **Widgets**
2. Find "ServerBox" → Add to home screen
3. Note the widget ID number displayed
4. Open ServerBox app → Settings
5. Tap **Config home widget link**
6. Add entry: `Widget ID` = `Status URL`
Example:
- Key: `17`
- Value: `https://my-server.com/status`
7. Tap widget on home screen to refresh
## watchOS Widget
### Setup
1. Open iPhone app → Settings
2. **iOS Settings****Watch app**
3. Tap **Add URL**
4. Enter URL ending with `/status`
5. Wait for watch app to sync
### Notes
- Try restarting watch app if not updating
- Verify phone and watch are connected
## Troubleshooting
### Widget Not Updating
**iOS:** Wait up to 30 minutes, then remove and re-add
**Android:** Tap widget to force refresh, verify ID in settings
**watchOS:** Restart watch app, wait a few minutes
### Widget Shows Error
- Verify ServerBox Monitor is running
- Test URL in browser
- Check URL ends with `/status`
## Security
- **Always use HTTPS** when possible
- **Local IPs only** on trusted networks

View File

@@ -0,0 +1,124 @@
---
title: Appearance
description: Customize the look and feel
---
Flutter Server Box offers extensive appearance customization.
## Themes
### Light Theme
Clean, bright interface for daytime use.
### Dark Theme
Easy on the eyes for low-light environments.
### AMOLED Dark
Pure black background for OLED screens, saves battery.
### System Theme
Automatically switches between light and dark based on system settings.
Set in: **Settings > Appearance > Theme**
## Terminal Appearance
### Customization Options
- **Font Size**: Adjust text size in terminal
- **Font Family**: Choose from available fonts
- **Text Color**: Customize text color
- **Background Color**: Set terminal background
- **Background Opacity**: Adjust transparency
- **Blur Effect**: Enable background blur
### Terminal Themes
Create terminal color themes:
1. Go to Settings > Terminal > Themes
2. Create new theme or edit existing
3. Customize colors:
- Text color
- Background color
- Cursor color
- Selection color
## Server Cards
### Card Style
- **Compact**: Minimal information per card
- **Detailed**: Extended information per card
- **Custom**: Choose which metrics to show
### Card Order
1. Go to Settings > Server Card Order
2. Drag cards to reorder
3. Changes apply immediately
### Card Metrics
Enable/disable metrics:
- CPU
- Memory
- Disk
- Network
- GPU
- Temperature
## Charts and Graphs
### Chart Style
- **Line**: Continuous line chart
- **Area**: Filled area chart
- **Bar**: Bar chart visualization
### Chart Colors
Customize chart colors in:
**Settings > Charts > Colors**
### Refresh Rate
Adjust how often charts update:
**Settings > Charts > Refresh Rate**
- **Power Saving**: 5 seconds
- **Normal**: 2 seconds
- **High Performance**: 1 second
## Layout
### Navigation Style
- **Bottom Navigation**: Mobile-style bottom tabs
- **Side Navigation**: Desktop-style sidebar
- **Tabs**: Classic tab interface
### View Mode
- **List**: Vertical list view
- **Grid**: Grid layout for servers
- **Cards**: Card-based layout
## Icons and Symbols
Choose icon style:
- **Filled**: Solid icons
- **Outlined**: Line icons
- **Rounded**: Soft, rounded icons
## Animations
Control animation speed:
- **Off**: No animations
- **Reduced**: Minimal animations
- **Normal**: Standard animations
- **Enhanced**: Extra animations

View File

@@ -0,0 +1,80 @@
---
title: Backup & Restore
description: Backup and restore your app data
---
Protect your server configurations and settings with built-in backup functionality.
## What Gets Backed Up
- **Server Configurations**: All saved servers
- **SSH Keys**: Imported private keys (encrypted)
- **Snippets**: Saved command snippets
- **Settings**: App preferences
**Not included:** Passwords (for security)
## Creating Backups
### Manual Backup
1. Settings → Backup
2. Tap **Create Backup**
3. Choose location
4. Backup saved with timestamp
### Auto Backup
Settings → Backup → Auto Backup:
- Daily / Weekly / Monthly / Off
### Cloud Sync
- **iOS/macOS**: iCloud automatic backup
- **Android**: Google Drive integration
## Restoring
### From Local Backup
1. Settings → Backup → Restore Backup
2. Select backup file
3. Authenticate (biometric/password)
4. Confirm restore
### From Cloud
1. Sign in to same cloud account
2. Settings → Backup → Restore from Cloud
3. Select backup from list
4. Authenticate and confirm
## Important Notes
### Passwords Not Backed Up
After restore, you'll need to re-enter passwords for each server.
**Tip:** Use SSH keys instead - they ARE backed up.
### Cross-Platform
Backups work across all platforms (iOS ↔ Android ↔ Desktop).
## Best Practices
1. **Enable auto backup** for peace of mind
2. **Test restore** periodically to verify backups work
3. **Backup before** updating app or switching devices
4. **Use SSH keys** to avoid re-entering passwords
## Troubleshooting
**Restore failed:**
- Check backup file integrity
- Ensure sufficient storage
- Verify app version compatibility
**Missing data after restore:**
- Passwords are not backed up (re-enter them)
- Check selective restore settings

View File

@@ -0,0 +1,88 @@
---
title: Jump Server
description: Route connections through intermediate servers
---
Connect to servers behind firewalls or in private networks by routing through an intermediate jump server.
## What is Jump Server?
A jump server acts as a gateway to access other servers that:
- Are behind firewalls
- Don't have direct SSH access
- Are in private networks
- Require multi-hop connections
## Setup
### Step 1: Configure Jump Server
Add the jump server as a normal server first:
1. Add server with SSH credentials
2. Test connection to ensure it works
3. This server will be your jump host
### Step 2: Configure Target Servers
For each server you want to access via jump:
1. Add target server (credentials for target, not jump)
2. Server settings → Jump Server
3. Select your jump server from list
4. Save
### Step 3: Connect
Connect to target server normally. The app automatically:
1. Connects to jump server
2. Tunnels through to target server
3. Maintains connection
## Use Cases
### Private Network Access
```
Your Device → Jump Server (public IP) → Private Server (10.0.0.x)
```
### Behind Firewall
```
Your Device → Bastion Host → Internal Server
```
### Multi-Hop
You can chain multiple jump servers for complex networks.
## Requirements
- Jump server must be accessible from your device
- Jump server must be able to reach target servers
- SSH keys recommended for jump server (faster authentication)
## Tips
- **Use SSH keys** on jump server for faster connections
- **Test direct access** to jump server first
- **Check firewall rules** on both ends
- **Monitor connection** - issues could be on jump or target
## Troubleshooting
### Connection Times Out
- Verify jump server is accessible
- Check jump server can reach target
- Test manually: `ssh -J jump@jump-server user@target-server`
### Authentication Fails
- Verify credentials for target server (not jump)
- Check SSH keys if using key authentication
### Slow Connection
- Normal for jump connections (extra hop)
- Consider using SSH keys for faster auth
- Check network latency to jump server

View File

@@ -0,0 +1,93 @@
---
title: Localizations
description: Language and region settings
---
Flutter Server Box supports 12+ languages with full localization.
## Supported Languages
| Language | Status |
|----------|--------|
| English (en) | ✅ Native |
| 简体中文 (zh) | ✅ Native |
| 繁體中文 (zh-Hant) | ✅ Native |
| Deutsch (de) | ✅ Native |
| Français (fr) | ✅ Native |
| Español (es) | ✅ Native |
| Português (pt) | ✅ Native |
| Русский (ru) | ✅ Native |
| Türkçe (tr) | ✅ Native |
| Українська (uk) | ✅ Native |
| Bahasa Indonesia (id) | ✅ Native |
| Nederlands (nl) | ✅ Native |
| 日本語 (ja) | ✅ AI-translated |
## Changing Language
1. Go to **Settings > Language**
2. Select preferred language
3. App restarts to apply changes
## Number Formatting
Numbers are formatted according to locale:
- **Thousands separator**: Comma vs period
- **Decimal separator**: Period vs comma
- **Date format**: Locale-specific
## Time Format
Choose between:
- **24-hour**: 13:00, 14:30
- **12-hour**: 1:00 PM, 2:30 PM
Set in: **Settings > Time Format**
## Contributing Translations
We welcome community translations!
### Translation Files
Located in `lib/l10n/`:
- `app_en.arb` - English (reference)
- `app_zh.arb` - Simplified Chinese
- etc.
### How to Contribute
1. Fork the repository
2. Copy `app_en.arb` to `app_YOUR_LOCALE.arb`
3. Translate values (keep keys the same)
4. Test your translations
5. Submit pull request
### Translation Guidelines
- Keep technical terms consistent
- Use formal address for professional tone
- Maintain placeholder format: `{variable}`
- Test UI with translated strings
## Adding New Language
1. Create new ARB file: `app_xx.arb`
2. Copy all keys from `app_en.arb`
3. Translate all values
4. Add to `l10n.yaml` configuration
5. Run `flutter gen-l10n`
6. Test with new locale
## RTL Languages
Right-to-left languages (Arabic, Hebrew) are partially supported. Full RTL layout support is planned for future releases.
## Quality Notes
- Some languages are AI-translated and may contain errors
- Native speaker reviews are appreciated
- Report translation issues via GitHub

View File

@@ -0,0 +1,90 @@
---
title: Server Setup
description: Configure and manage server connections
---
## Adding a Server
1. Tap the **+** button on the main screen
2. Fill in connection details:
- **Name**: Friendly name for identification
- **Host**: IP address or domain name
- **Port**: SSH port (default: 22)
- **Username**: SSH login user
- **Authentication**: Password or SSH key
3. Configure optional settings:
- **Initial Directory**: Starting directory for terminal/SFTP
- **Environment**: Custom environment variables
- **Keep-alive Interval**: Connection keep-alive setting
4. Tap **Save**
## Connection Types
### Password Authentication
Simple username/password authentication:
- Enter password in the password field
- Password is stored securely (encrypted)
- Requires re-entry on app restart (unless saved)
### SSH Key Authentication
More secure, passwordless authentication:
1. Generate or import SSH key
2. Add key to server's `~/.ssh/authorized_keys`
3. Select key in app when adding server
See [SSH Keys](/configuration/ssh-keys/) for detailed setup.
## Server Groups
Organize servers into groups for easier management:
1. Go to Settings > Server Groups
2. Create a new group
3. Assign servers to groups
4. Groups appear as sections in main view
## Server Cards
Customize what information appears on server cards:
1. Go to Settings > Server Card Settings
2. Enable/disable metrics:
- CPU
- Memory
- Disk
- Network
3. Reorder cards by dragging
## Connection Profiles
Save connection profiles for different use cases:
- **Default Profile**: Standard settings
- **Low Bandwidth**: Reduced refresh rate
- **High Performance**: Maximum refresh rate
## Troubleshooting
### Connection Refused
- Check server is running
- Verify SSH port
- Check firewall rules
### Authentication Failed
- Verify username/password
- Check SSH key permissions
- Ensure SSH service is running
### Timeout
- Check network connectivity
- Increase timeout in settings
- Try different network

View File

@@ -0,0 +1,118 @@
---
title: SFTP File Browser
description: File transfer and management via SFTP
---
Browse, edit, and transfer files on your servers with a built-in SFTP client.
## Basic Usage
### Opening SFTP
1. Connect to server
2. Tap **Files** button on server page
3. Or from terminal: Tap **SFTP** button
### Navigation
- **Tap folder**: Enter directory
- **Tap file**: View/Edit/Download options
- **Back button**: Previous directory
- **Home button**: User's home directory
- **Goto button**: Jump to path with autocomplete
## File Operations
### Common Actions
| Action | How |
|--------|-----|
| **Download** | Long-press file → Download |
| **Upload** | Folder icon → Select file |
| **Rename** | Long-press → Rename |
| **Delete** | Long-press → Delete |
| **Copy/Move** | Long-press → Select → Choose destination |
| **Permissions** | Tap file info → Edit permissions |
### Permission Editor
Unix permissions editor:
- **3x3 Grid**: User/Group/Other × Read/Write/Execute
- **Numeric**: Direct input (755, 644, etc.)
- **Symbolic**: rwxr-xr-x format
### Edit Files
1. Tap file → Edit
2. Edit in built-in editor
3. Save → Upload back to server
**Size limit:** Files up to 1 MB. For larger files, use the terminal with vim/nano instead.
**Editor settings:** Settings → SFTP Editor
- Preferred editor (vim, nano, etc.)
- Close after save
- Soft wrap
- Syntax highlighting
## Display Settings
### Sort Order
Settings → Sort By:
- Name (alphabetical)
- Size (largest first)
- Time (newest first)
### Folders First
Show directories before files:
Settings → Folders First
### Hidden Files
Show dotfiles (`.git`, `.bashrc`, etc.):
Settings → Show Hidden Files
## Archive Support
Extract common archive formats directly on your server.
| Format | Variants | Command Required |
|--------|----------|------------------|
| .tar.gz | .tgz, .tar.Z | tar |
| .tar.bz2 | .tbz2, .tar.bz2 | tar |
| .tar.xz | .txz | tar |
| .zip | .zipx | unzip |
| .7z | - | 7z |
| .rar | - | unrar |
**Note:** The corresponding command (`tar`, `unzip`, `7z`, `unrar`) must be installed on your server. These tools handle many sub-formats not listed above.
## Quick Access
### From Terminal
Tap **SFTP** button to open current terminal directory in file browser.
### Remember Last Path
Automatically return to last visited directory:
Settings → SFTP Open Last Path
## Troubleshooting
### Permission Denied
- Check user has read access to directory
- Verify directory permissions: `ls -la`
- Ensure SFTP is enabled in sshd_config
### Slow Listing
Large directories (1000+ items) use pagination for performance.
### Can't Edit File
File larger than 1 MB? Use terminal with vim/nano instead.

View File

@@ -0,0 +1,127 @@
---
title: Terminal & SSH
description: SSH terminal setup and configuration
---
Complete SSH terminal access with full keyboard support and customizable interface.
## Basic Setup
### First Connection
1. Add server with SSH credentials
2. Tap server card to connect
3. Accept host key fingerprint (first time only)
4. Terminal opens automatically
### Virtual Keyboard (Mobile)
Customizable virtual keyboard for terminal access:
| Button | Function |
|--------|----------|
| **Ctrl, Alt, Shift** | Modifier keys (tap before other key) |
| **Esc, Tab** | Special characters |
| **Arrows** | Navigation |
| **F1-F12** | Function keys |
| **SFTP** | Open current directory in file browser |
| **Clipboard** | Copy selection / Paste clipboard |
| **Snippets** | Quick command execution |
**Customize keyboard:** Settings → SSH Virtual Keys
- Enable/disable keys
- Reorder layout
- Add/remove buttons
## Terminal Settings
### Appearance
**Font Size:** Settings → Terminal Font Size
- Affects all new sessions
- Typical range: 8-24 pixels
**Colors:** Settings → Terminal Color
- Text color
- Background color & opacity
- Blur effect (iOS/macOS)
- Cursor color
### Keyboard Type
If you can't input certain characters:
1. Settings → Keyboard Type
2. Switch to `visiblePassword`
3. Note: CJK input may not work after this change
## Connection Management
### Multi-Tab
- **Desktop**: Ctrl+T (new), Ctrl+W (close)
- **Mobile**: Tap + button
- Sessions persist between app launches
### Auto-Connect
Set server to auto-connect on app open:
1. Server settings → Auto-Connect
2. Enable toggle
### Jump Server
Route through intermediate server:
1. Add and configure jump server first
2. Target server settings → Select jump server
3. Connection routes through jump server automatically
## SSH Keys (Recommended)
More secure than passwords:
1. Generate key: Settings → Private Keys → Add
2. Upload public key to server: `ssh-copy-id -i pubkey user@server`
3. Server settings → Use key instead of password
## Common Issues
### Can't Connect
**Timeout/Refused:**
- Verify server is Unix-like (Linux, macOS, Android/Termux)
- Check firewall allows SSH port (default 22)
- Test manually: `ssh user@server -p port`
**Auth Failed:**
- Verify username and password
- Check SSH key is uploaded correctly
- Ensure account is not locked
### Terminal Disconnects
**Frequent disconnections:**
1. Check server keep-alive settings:
```bash
# /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3
```
2. Disable battery optimization:
- **MIUI**: Battery → "No limits"
- **Android**: Settings → Apps → Disable optimization
- **iOS**: Enable background refresh
### Can't Input Characters
Change keyboard type to `visiblePassword` in settings.
## Tips
- **Test connection** first with regular SSH client
- **Use SSH keys** instead of passwords for security
- **Save snippets** for frequently used commands
- **Pinch to zoom** for temporary font size change (mobile)

View File

@@ -0,0 +1,86 @@
---
title: Architecture
description: Architecture patterns and design decisions
---
Flutter Server Box follows clean architecture principles with clear separation between data, domain, and presentation layers.
## Layered Architecture
```
┌─────────────────────────────────────┐
│ Presentation Layer │
│ (lib/view/page/) │
│ - Pages, Widgets, Controllers │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Business Logic Layer │
│ (lib/data/provider/) │
│ - Riverpod Providers │
│ - State Management │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Data Layer │
│ (lib/data/model/, store/) │
│ - Models, Storage, Services │
└─────────────────────────────────────┘
```
## Key Patterns
### State Management: Riverpod
- **Code Generation**: Uses `riverpod_generator` for type-safe providers
- **State Notifiers**: For mutable state with business logic
- **Async Notifiers**: For loading and error states
- **Stream Providers**: For real-time data
### Immutable Models: Freezed
- All data models use Freezed for immutability
- Union types for state representation
- Built-in JSON serialization
- CopyWith extensions for updates
### Local Storage: Hive
- **hive_ce**: Community edition of Hive
- No manual `@HiveField` or `@HiveType` needed
- Type adapters auto-generated
- Persistent key-value storage
## Dependency Injection
Services and stores are injected via:
1. **Providers**: Expose dependencies to UI
2. **GetIt**: Service location (where applicable)
3. **Constructor Injection**: Explicit dependencies
## Data Flow
```
User Action → Widget → Provider → Service/Store → Model Update → UI Rebuild
```
1. User interacts with widget
2. Widget calls provider method
3. Provider updates state via service/store
3. State change triggers UI rebuild
4. New state reflected in widget
## Custom Dependencies
The project uses several custom forks to extend functionality:
- **dartssh2**: Enhanced SSH features
- **xterm**: Terminal emulator with mobile support
- **fl_lib**: Shared UI components and utilities
## Threading
- **Isolates**: Heavy computation off main thread
- **computer package**: Multi-threading utilities
- **Async/Await**: Non-blocking I/O operations

View File

@@ -0,0 +1,116 @@
---
title: Building
description: Build instructions for different platforms
---
Flutter Server Box uses a custom build system (`fl_build`) for cross-platform builds.
## Prerequisites
- Flutter SDK (stable channel)
- Platform-specific tools (Xcode for iOS, Android Studio for Android)
- Rust toolchain (for some native dependencies)
## Development Build
```bash
# Run in development mode
flutter run
# Run on specific device
flutter run -d <device-id>
```
## Production Build
The project uses `fl_build` for building:
```bash
# Build for specific platform
dart run fl_build -p <platform>
# Available platforms:
# - ios
# - android
# - macos
# - linux
# - windows
```
## Platform-Specific Builds
### iOS
```bash
dart run fl_build -p ios
```
Requires:
- macOS with Xcode
- CocoaPods
- Apple Developer account for signing
### Android
```bash
dart run fl_build -p android
```
Requires:
- Android SDK
- Java Development Kit
- Keystore for signing
### macOS
```bash
dart run fl_build -p macos
```
### Linux
```bash
dart run fl_build -p linux
```
### Windows
```bash
dart run fl_build -p windows
```
Requires Windows with Visual Studio.
## Pre/Post Build
The `make.dart` script handles:
- Metadata generation
- Version string updates
- Platform-specific configurations
## Troubleshooting
### Clean Build
```bash
flutter clean
dart run build_runner build --delete-conflicting-outputs
flutter pub get
```
### Version Mismatch
Ensure all dependencies are compatible:
```bash
flutter pub upgrade
```
## Release Checklist
1. Update version in `pubspec.yaml`
2. Run code generation
3. Run tests
4. Build for all target platforms
5. Test on physical devices
6. Create GitHub release

View File

@@ -0,0 +1,98 @@
---
title: Code Generation
description: Using build_runner for code generation
---
Flutter Server Box heavily uses code generation for models, state management, and serialization.
## When to Run Code Generation
Run after modifying:
- Models with `@freezed` annotation
- Classes with `@JsonSerializable`
- Hive models
- Providers with `@riverpod`
- Localizations (ARB files)
## Running Code Generation
```bash
# Generate all code
dart run build_runner build --delete-conflicting-outputs
# Clean and regenerate
dart run build_runner build --delete-conflicting-outputs --clean
```
## Generated Files
### Freezed (`*.freezed.dart`)
Immutable data models with union types:
```dart
@freezed
class ServerState with _$ServerState {
const factory ServerState.connected() = Connected;
const factory ServerState.disconnected() = Disconnected;
const factory ServerState.error(String message) = Error;
}
```
### JSON Serialization (`*.g.dart`)
Generated from `json_serializable`:
```dart
@JsonSerializable()
class Server {
final String id;
final String name;
final String host;
Server({required this.id, required this.name, required this.host});
factory Server.fromJson(Map<String, dynamic> json) =>
_$ServerFromJson(json);
Map<String, dynamic> toJson() => _$ServerToJson(this);
}
```
### Riverpod Providers (`*.g.dart`)
Generated from `@riverpod` annotation:
```dart
@riverpod
class MyNotifier extends _$MyNotifier {
@override
int build() => 0;
}
```
### Hive Adapters (`*.g.dart`)
Auto-generated for Hive models (hive_ce):
```dart
@HiveType(typeId: 0)
class ServerModel {
@HiveField(0)
final String id;
}
```
## Localization Generation
```bash
flutter gen-l10n
```
Generates `lib/generated/l10n/` from `lib/l10n/*.arb` files.
## Tips
- Use `--delete-conflicting-outputs` to avoid conflicts
- Add generated files to `.gitignore`
- Never manually edit generated files

View File

@@ -0,0 +1,115 @@
---
title: State Management
description: Riverpod-based state management patterns
---
Flutter Server Box uses Riverpod with code generation for state management.
## Provider Types
### StateProvider
Simple state that can be read and written:
```dart
@riverpod
class Settings extends _$Settings {
@override
SettingsModel build() {
return SettingsModel.defaults();
}
void update(SettingsModel newSettings) {
state = newSettings;
}
}
```
### AsyncNotifierProvider
State that loads asynchronously with loading/error states:
```dart
@riverpod
class ServerStatus extends _$ServerStatus {
@override
Future<StatusModel> build(Server server) async {
return fetchStatus(server);
}
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => fetchStatus(server));
}
}
```
### StreamProvider
Real-time data from streams:
```dart
@riverpod
Stream<CpuUsage> cpuUsage(CpuUsageRef ref, Server server) {
return cpuService.monitor(server);
}
```
## State Patterns
### Loading States
```dart
state.when(
data: (data) => DataWidget(data),
loading: () => LoadingWidget(),
error: (error, stack) => ErrorWidget(error),
)
```
### Family Providers
Parameterized providers:
```dart
@riverpod
List<Container> containers(ContainersRef ref, Server server) {
return containerService.list(server);
}
```
### Auto-Dispose
Providers that dispose when no longer referenced:
```dart
@Riverpod(keepAlive: false)
class TempState extends _$TempState {
// ...
}
```
## Best Practices
1. **Use code generation**: Always use `@riverpod` annotation
2. **Co-locate providers**: Place near consuming widgets
3. **Avoid singletons**: Use providers instead
4. **Layer correctly**: Keep UI logic separate from business logic
## Reading State in Widgets
```dart
class ServerWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final status = ref.watch(serverStatusProvider(server));
return status.when(...);
}
}
```
## Modifying State
```dart
ref.read(settingsProvider.notifier).update(newSettings);
```

View File

@@ -0,0 +1,96 @@
---
title: Project Structure
description: Understanding the Flutter Server Box codebase
---
The Flutter Server Box project follows a modular architecture with clear separation of concerns.
## Directory Structure
```
lib/
├── core/ # Core utilities and extensions
├── data/ # Data layer
│ ├── model/ # Data models by feature
│ ├── provider/ # Riverpod providers
│ └── store/ # Local storage (Hive)
├── view/ # UI layer
│ ├── page/ # Main pages
│ └── widget/ # Reusable widgets
├── generated/ # Generated localization
├── l10n/ # Localization ARB files
└── hive/ # Hive adapters
```
## Core Layer (`lib/core/`)
Contains utilities, extensions, and routing configuration:
- **Extensions**: Dart extensions for common types
- **Routes**: App routing configuration
- **Utils**: Shared utility functions
## Data Layer (`lib/data/`)
### Models (`lib/data/model/`)
Organized by feature:
- `server/` - Server connection and status models
- `container/` - Docker container models
- `ssh/` - SSH session models
- `sftp/` - SFTP file models
- `app/` - App-specific models
### Providers (`lib/data/provider/`)
Riverpod providers for dependency injection and state management:
- Server providers
- UI state providers
- Service providers
### Stores (`lib/data/store/`)
Hive-based local storage:
- Server storage
- Settings storage
- Cache storage
## View Layer (`lib/view/`)
### Pages (`lib/view/page/`)
Main application screens:
- `server/` - Server management pages
- `ssh/` - SSH terminal pages
- `container/` - Container pages
- `setting/` - Settings pages
- `storage/` - SFTP pages
- `snippet/` - Snippet pages
### Widgets (`lib/view/widget/`)
Reusable UI components:
- Server cards
- Status charts
- Input components
- Dialogs
## Generated Files
- `lib/generated/l10n/` - Auto-generated localization
- `*.g.dart` - Generated code (json_serializable, freezed, hive, riverpod)
- `*.freezed.dart` - Freezed immutable classes
## Packages Directory (`/packages/`)
Contains custom forks of dependencies:
- `dartssh2/` - SSH library
- `xterm/` - Terminal emulator
- `fl_lib/` - Shared utilities
- `fl_build/` - Build system

View File

@@ -0,0 +1,113 @@
---
title: Testing
description: Testing strategies and running tests
---
## Running Tests
```bash
# Run all tests
flutter test
# Run specific test file
flutter test test/battery_test.dart
# Run with coverage
flutter test --coverage
```
## Test Structure
Tests are located in the `test/` directory mirroring the lib structure:
```
test/
├── data/
│ ├── model/
│ └── provider/
├── view/
│ └── widget/
└── test_helpers.dart
```
## Unit Tests
Test business logic and data models:
```dart
test('should calculate CPU percentage', () {
final cpu = CpuModel(usage: 75.0);
expect(cpu.usagePercentage, '75%');
});
```
## Widget Tests
Test UI components:
```dart
testWidgets('ServerCard displays server name', (tester) async {
await tester.pumpWidget(
ProviderScope(
child: MaterialApp(
home: ServerCard(server: testServer),
),
),
);
expect(find.text('Test Server'), findsOneWidget);
});
```
## Provider Tests
Test Riverpod providers:
```dart
test('serverStatusProvider returns status', () async {
final container = ProviderContainer();
final status = await container.read(serverStatusProvider(testServer).future);
expect(status, isA<StatusModel>());
});
```
## Mocking
Use mocks for external dependencies:
```dart
class MockSshService extends Mock implements SshService {}
test('connects to server', () async {
final mockSsh = MockSshService();
when(mockSsh.connect(any)).thenAnswer((_) async => true);
// Test with mock
});
```
## Integration Tests
Test complete user flows (in `integration_test/`):
```dart
testWidgets('add server flow', (tester) async {
await tester.pumpWidget(MyApp());
// Tap add button
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
// Fill form
await tester.enterText(find.byKey(Key('name')), 'Test Server');
// ...
});
```
## Best Practices
1. **Arrange-Act-Assert**: Structure tests clearly
2. **Descriptive names**: Test names should describe behavior
3. **One assertion per test**: Keep tests focused
4. **Mock external deps**: Don't depend on real servers
5. **Test edge cases**: Empty lists, null values, etc.

View File

@@ -0,0 +1,55 @@
---
title: Docker Management
description: Monitor and manage Docker containers
---
Flutter Server Box provides an intuitive interface for managing Docker containers on your servers.
## Features
### Container List
- View all containers (running and stopped)
- Container ID and name display
- Image information
- Status indicators
- Creation time
### Container Actions
- **Start**: Launch stopped containers
- **Stop**: Gracefully stop running containers
- **Restart**: Restart containers
- **Remove**: Delete containers
- **View Logs**: Check container logs
- **Inspect**: View container details
### Container Details
- Environment variables
- Port mappings
- Volume mounts
- Network configuration
- Resource usage
## Requirements
- Docker must be installed on your server
- SSH user must have Docker permissions
- For non-root users, add to docker group:
```bash
sudo usermod -aG docker your_username
```
## Quick Actions
- Single tap: View container details
- Long press: Quick action menu
- Swipe: Quick start/stop
- Bulk select: Multiple container operations
## Tips
- Use **auto-refresh** to monitor container status changes
- Filter by running/stopped containers
- Search containers by name or ID

View File

@@ -0,0 +1,73 @@
---
title: Server Monitoring
description: Real-time server status monitoring with beautiful charts
---
Flutter Server Box provides comprehensive real-time monitoring of your server's health and performance.
## Status Cards
The server detail page displays configurable status cards for different system metrics. You can enable/disable cards in settings.
### CPU Monitoring
- Real-time CPU usage percentage
- Per-core CPU usage breakdown
- Historical usage charts
- CPU frequency information
### Memory Monitoring
- **RAM Usage**: Used vs total memory with percentage
- **Swap Usage**: Swap memory utilization
- Memory pressure indicators
- Historical memory trends
### Disk Monitoring
- Mount point usage with percentage
- Total, used, and free space
- I/O statistics
- Multiple disk support
### Network Monitoring
- Real-time upload/download speeds
- Bandwidth usage charts
- Network interface statistics
- Total data transferred
### Advanced Metrics
- **GPU Status**: NVIDIA and AMD GPU monitoring
- **Temperature**: CPU, GPU, and system temperatures
- **Sensors**: Fan speeds, voltages, and other sensor data
- **S.M.A.R.T**: Disk health monitoring
- **Battery**: UPS or battery status (if available)
## Customizing Display
### Reordering Cards
1. Go to Settings
2. Select Server Settings
3. Drag cards to reorder them on the server detail page
### Enabling/Disabling Cards
1. Open a server's detail page
2. Tap the edit/menu button
3. Toggle individual cards on or off
## Auto-Refresh
- Status cards automatically refresh
- Refresh interval is configurable in settings
- Manual refresh available with pull-to-refresh gesture
## Charts and Visualizations
- **Line Charts**: Historical data trends
- **Gauge Charts**: Current usage percentage
- **Color Coding**: Visual indicators for status levels
- **Zoom**: Pinch to zoom on charts for detailed views

View File

@@ -0,0 +1,67 @@
---
title: Network Tools
description: Network testing and diagnostic tools
---
Flutter Server Box includes several network tools for testing and diagnostics.
## iPerf
Perform network speed tests between your device and server.
### Features
- **Upload/Download Speed**: Test bandwidth
- **Server Mode**: Use server as iPerf server
- **Client Mode**: Connect to iPerf servers
- **Custom Parameters**: Duration, parallel streams, etc.
### Usage
1. Open a server
2. Tap **iPerf**
3. Choose server or client mode
4. Configure parameters
5. Start test
## Ping
Test network connectivity and latency.
### Features
- **ICMP Ping**: Standard ping tool
- **Packet Count**: Specify number of packets
- **Packet Size**: Custom packet size
- **Interval**: Time between pings
### Usage
1. Open a server
2. Tap **Ping**
3. Enter target host
4. Configure parameters
5. Start pinging
## Wake on LAN
Wake up remote servers via magic packet.
### Features
- **MAC Address**: Target device MAC
- **Broadcast**: Send broadcast magic packet
- **Saved Profiles**: Store WoL configurations
### Requirements
- Target device must support Wake-on-LAN
- WoL must be enabled in BIOS/UEFI
- Device must be in sleep/soft-off state
- Device must be on the same network or reachable via broadcast
## Tips
- Use iPerf to diagnose network bottlenecks
- Ping multiple hosts to compare latency
- Save WoL profiles for frequently woken devices

View File

@@ -0,0 +1,56 @@
---
title: Process & Services
description: Monitor processes and manage systemd services
---
## Process Management
View and manage running processes on your servers.
### Process List
- All running processes with details
- PID (Process ID)
- CPU and memory usage
- User ownership
- Process command
### Process Actions
- **Kill**: Terminate processes
- **Filter**: By name or user
- **Sort**: By CPU, memory, or PID
- **Search**: Find specific processes
## Systemd Services
Manage systemd services for service control.
### Service List
- All systemd services
- Active/inactive status
- Enabled/disabled state
- Service description
### Service Actions
- **Start**: Launch a stopped service
- **Stop**: Stop a running service
- **Restart**: Restart a service
- **Enable**: Enable auto-start on boot
- **Disable**: Disable auto-start
- **View Status**: Check service status and logs
- **Reload**: Reload service configuration
## Requirements
- SSH user must have appropriate permissions
- For service management: `sudo` access may be required
- Process viewing: Standard user permissions usually sufficient
## Tips
- Use process list to identify resource hogs
- Check service logs for troubleshooting
- Monitor critical services with auto-refresh

View File

@@ -0,0 +1,105 @@
---
title: Proxmox (PVE)
description: Proxmox Virtual Environment management
---
Flutter Server Box includes support for managing Proxmox VE virtualization platform.
## Features
### VM Management
- **List VMs**: View all virtual machines
- **VM Status**: Check running/stopped states
- **VM Actions**: Start, stop, restart VMs
- **VM Details**: View configuration and resources
### Container (LXC) Management
- **List Containers**: View all LXC containers
- **Container Status**: Monitor container states
- **Container Actions**: Start, stop, restart containers
- **Console Access**: Terminal access to containers
### Node Monitoring
- **Resource Usage**: CPU, memory, disk, network
- **Node Status**: Check node health
- **Cluster View**: Multi-node cluster overview
## Setup
### Adding PVE Server
1. Add server as normal SSH connection
2. Ensure user has PVE permissions
3. Access PVE features from server detail page
### Permissions Required
PVE user needs:
- **VM.Audit**: View VM status
- **VM.PowerMgmt**: Start/stop VMs
- **VM.Console**: Console access
Example permissions setup:
```bash
pveum useradd myuser -password mypass
pveum aclmod /vms -user myuser@pve -role VMAdmin
```
## Usage
### VM Management
1. Open server with PVE
2. Tap **PVE** button
3. View VM list
4. Tap VM for details
5. Use action buttons for management
### Container Management
1. Open server with PVE
2. Tap **PVE** button
3. Switch to Containers tab
4. View and manage LXC containers
### Monitoring
- Real-time resource usage
- Historical data charts
- Multiple node support
## Features by Status
### Implemented
- VM listing and status
- Container listing and status
- Basic VM operations (start/stop/restart)
- Resource monitoring
### Planned
- VM creation from templates
- Snapshot management
- Console access
- Storage management
- Network configuration
## Requirements
- **PVE Version**: 6.x or 7.x
- **Access**: SSH access to PVE host
- **Permissions**: Appropriate PVE user roles
- **Network**: Connectivity to PVE API (via SSH)
## Tips
- Use **dedicated PVE user** with limited permissions
- Monitor **resource usage** for optimal performance
- Check **VM status** before maintenance
- Use **snapshots** before major changes

View File

@@ -0,0 +1,60 @@
---
title: Snippets
description: Save and execute custom shell commands
---
Snippets allow you to save frequently used shell commands for quick execution.
## Creating Snippets
1. Go to the **Snippets** tab
2. Tap the **+** button
3. Fill in snippet details:
- **Name**: Friendly name for the snippet
- **Command**: The shell command to execute
- **Description**: Optional notes
4. Save the snippet
## Using Snippets
1. Open a server
2. Tap the **Snippet** button
3. Select a snippet to execute
4. View output in the terminal
## Snippet Features
- **Quick Execute**: One-tap command execution
- **Variables**: Use server-specific variables
- **Organization**: Group related snippets
- **Import/Export**: Share snippets between devices
- **Sync**: Optional cloud sync
## Example Snippets
### System Update
```bash
sudo apt update && sudo apt upgrade -y
```
### Disk Cleanup
```bash
sudo apt autoremove -y && sudo apt clean
```
### Docker Cleanup
```bash
docker system prune -a
```
### View System Logs
```bash
journalctl -n 50 -f
```
## Tips
- Use **descriptive names** for easy identification
- Add **comments** for complex commands
- Test commands before saving as snippets
- Organize snippets by category or server type

View File

@@ -0,0 +1,46 @@
---
title: Flutter Server Box
description: A comprehensive cross-platform server management application
hero:
tagline: Manage your Linux servers from anywhere
actions:
- text: Get Started
link: /introduction/
icon: right-arrow
variant: primary
- text: View on GitHub
link: https://github.com/lollipopkit/flutter_server_box
icon: github
variant: minimal
---
import { Card, CardGrid } from '@astrojs/starlight/components';
## Features
<CardGrid stagger>
<Card title="Real-time Monitoring" icon="chart">
Monitor CPU, memory, disk, network, GPU, and temperature with beautiful real-time charts.
</Card>
<Card title="SSH Terminal" icon="terminal">
Full-featured SSH terminal with multi-tab support and virtual keyboard for mobile devices.
</Card>
<Card title="SFTP File Browser" icon="folder">
Manage files on your servers with the built-in SFTP client and local file browser.
</Card>
<Card title="Docker Management" icon="box">
Start, stop, and monitor Docker containers with an intuitive interface.
</Card>
<Card title="Cross-Platform" icon="device-mobile">
Available on iOS, Android, macOS, Linux, Windows, and watchOS.
</Card>
<Card title="12+ Languages" icon="globe">
Full localization support including English, Chinese, German, French, and more.
</Card>
</CardGrid>
## Quick Links
- **Download**: Available on [App Store](https://apps.apple.com/app/flutter-server-box), [Google Play](https://play.google.com/store/apps/details), [GitHub](https://github.com/lollipopkit/flutter_server_box/releases), and [F-Droid](https://f-droid.org/)
- **Documentation**: Explore the guides to get started with Flutter Server Box
- **Support**: Join our community on GitHub for discussions and issues

View File

@@ -0,0 +1,52 @@
---
title: Installation
description: Download and install Flutter Server Box on your device
---
Flutter Server Box is available on multiple platforms. Choose your preferred method of installation.
## Mobile Apps
### iOS
Download from the **[App Store](https://apps.apple.com/app/flutter-server-box)**.
### Android
Choose your preferred source:
- **[Google Play](https://play.google.com/store/apps/details)** - Recommended for most users
- **[F-Droid](https://f-droid.org/)** - For users who prefer FOSS-only sources
- **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)** - For the latest version directly from the source
## Desktop Apps
### macOS
Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**.
Features:
- Native menu bar integration
- Support for both Intel and Apple Silicon
### Linux
Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**.
Available as AppImage, deb, or tar.gz packages.
### Windows
Download from **[GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases)**.
## watchOS
Available on the **[App Store](https://apps.apple.com/app/flutter-server-box)** as part of the iOS app.
## Building from Source
To build Flutter Server Box from source, see the [Building](/development/building) section in the Development documentation.
## Version Information
Check the [GitHub Releases](https://github.com/lollipopkit/flutter_server_box/releases) page for the latest version and changelog.

View File

@@ -0,0 +1,33 @@
---
title: Introduction
description: Learn what Flutter Server Box is and what it can do
---
Flutter Server Box is a comprehensive cross-platform server management application built with Flutter. It allows you to monitor, manage, and control your Linux, Unix, and Windows servers from anywhere.
## What is Flutter Server Box?
Flutter Server Box provides a unified interface for server administration tasks through SSH connections. Whether you're a system administrator, developer, or hobbyist running home servers, this app puts powerful server management tools in your pocket.
## Key Capabilities
- **Real-time Monitoring**: Track CPU, memory, disk usage, network speed, GPU status, and system temperatures
- **SSH Terminal**: Full terminal access with multi-tab support and customizable appearance
- **SFTP Client**: Browse and manage files on your servers
- **Docker Management**: Control containers with ease
- **Process Management**: View and manage system processes
- **Systemd Services**: Start, stop, and monitor systemd services
- **Network Tools**: iPerf testing, ping, and Wake-on-LAN
- **Snippets**: Save and execute custom shell commands
## Supported Platforms
Flutter Server Box is truly cross-platform:
- **Mobile**: iOS and Android
- **Desktop**: macOS, Linux, and Windows
- **Wearable**: watchOS (Apple Watch)
## License
This project is licensed under AGPL v3. Source code is available on [GitHub](https://github.com/lollipopkit/flutter_server_box).

View File

@@ -0,0 +1,80 @@
---
title: Desktop Features
description: macOS, Linux, and Windows specific features
---
Flutter Server Box on desktop platforms provides additional productivity features.
## macOS
### Menu Bar Integration
- Quick server status in menu bar
- One-click server access
- Compact mode for minimal distraction
- Native macOS menu bar styling
### Window State Persistence
- Remembers window position and size
- Restore previous session on launch
- Multiple monitor support
### Native Features
- **Title Bar**: Custom or system title bar option
- **Full Screen Mode**: Dedicated server monitoring
- **Keyboard Shortcuts**: macOS-native shortcuts
- **Touch Bar** (supported devices): Quick actions
## Linux
### Native Integration
- System tray support
- Desktop notification integration
- File picker integration
### Window Management
- X11 and Wayland support
- Tiling window manager friendly
- Custom window decorations option
## Windows
### Features
- System tray integration
- Jump List quick actions
- Native window controls
- Auto-start on boot option
## Cross-Platform Desktop Features
### Keyboard Shortcuts
- **Cmd/Ctrl + N**: New server
- **Cmd/Ctrl + W**: Close tab
- **Cmd/Ctrl + T**: New terminal tab
- **Cmd/Ctrl + ,**: Settings
### Themes
- Light theme
- Dark theme
- AMOLED theme (pure black)
- System theme (follows OS)
### Multiple Windows
- Open multiple servers in separate windows
- Drag tabs to new window
- Compare server stats side-by-side
### Advantages Over Mobile
- Larger screen for monitoring
- Full keyboard for terminal
- Faster file operations
- Better multitasking

View File

@@ -0,0 +1,77 @@
---
title: Mobile Features
description: iOS and Android specific features
---
Flutter Server Box provides several mobile-specific features for iOS and Android devices.
## Biometric Authentication
Secure your servers with biometric authentication:
- **iOS**: Face ID or Touch ID
- **Android**: Fingerprint authentication
Enable in Settings > Security > Biometric Authentication
## Home Screen Widgets
Add server status widgets to your home screen for quick monitoring.
### iOS
- Long press on home screen
- Tap **+** to add widget
- Search for "Flutter Server Box"
- Choose widget size:
- Small: Single server status
- Medium: Multiple servers
- Large: Detailed info
### Android
- Long press on home screen
- Tap **Widgets**
- Find "Flutter Server Box"
- Select widget type
## Background Running
### Android
Keep connections alive in the background:
- Enable in Settings > Advanced > Background Running
- Requires battery optimization exclusion
- Persistent notifications for active connections
### iOS
Background limitations apply:
- Connections may pause in background
- Quick reconnect on return to app
- Background refresh support
## Push Notifications
Receive notifications for:
- Server offline alerts
- High resource usage warnings
- Task completion alerts
Configure in Settings > Notifications
## Mobile UI Features
- **Pull to Refresh**: Update server status
- **Swipe Actions**: Quick server operations
- **Landscape Mode**: Better terminal experience
- **Virtual Keyboard**: Terminal shortcuts
## File Integration
- **Files App (iOS)**: Direct SFTP access from Files
- **Storage Access Framework (Android)**: Share files with other apps
- **Document Picker**: Easy file selection

View File

@@ -0,0 +1,55 @@
---
title: watchOS App
description: Apple Watch companion app
---
Flutter Server Box includes a companion app for Apple Watch, providing quick server monitoring on your wrist.
## Features
### Server Status at a Glance
- View server online/offline status
- Quick CPU and memory stats
- One-tap server connectivity check
### Complications
Add server information to your watch face:
- **Modular**: Server status icon
- **Infograph**: Small complication
- **Extra Large**: Large complication
### Quick Actions
- Ping servers
- Wake on LAN
- Quick terminal command
## Requirements
- Apple Watch Series 3 or later
- watchOS 8.0 or later
- Paired iPhone with Flutter Server Box installed
- iPhone and Watch on same Wi-Fi
## Setup
1. Install Flutter Server Box on iPhone
2. Open the Watch app on iPhone
3. Find Flutter Server Box under "Available Apps"
4. Toggle "Show App on Apple Watch"
## Limitations
- No full terminal access
- Reduced SFTP functionality
- Dependent on iPhone connection
- Simplified server management
## Tips
- Use complications for persistent status
- Quick actions for emergency checks
- Sync servers from iPhone app

View File

@@ -0,0 +1,214 @@
---
title: Architecture Overview
description: High-level application architecture
---
Flutter Server Box follows a layered architecture with clear separation of concerns.
## Architecture Layers
```
┌─────────────────────────────────────────────────┐
│ Presentation Layer (UI) │
│ lib/view/page/, lib/view/widget/ │
│ - Pages, Widgets, Controllers │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Business Logic Layer │
│ lib/data/provider/ │
│ - Riverpod Providers, State Notifiers │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Data Access Layer │
│ lib/data/store/, lib/data/model/ │
│ - Hive Stores, Data Models │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ External Integration Layer │
│ - SSH (dartssh2), Terminal (xterm), SFTP │
│ - Platform-specific code (iOS, Android, etc.) │
└─────────────────────────────────────────────────┘
```
## Application Foundation
### Main Entry Point
`lib/main.dart` initializes the app:
```dart
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
```
### Root Widget
`MyApp` provides:
- **Theme Management**: Light/dark theme switching
- **Routing Configuration**: Navigation structure
- **Provider Scope**: Dependency injection root
### Home Page
`HomePage` serves as navigation hub:
- **Tabbed Interface**: Server, Snippet, Container, SSH
- **State Management**: Per-tab state
- **Navigation**: Feature access
## Core Systems
### State Management: Riverpod
**Why Riverpod?**
- Compile-time safety
- Easy testing
- No Build context dependency
- Works across platforms
**Provider Types Used:**
- `StateProvider`: Simple mutable state
- `AsyncNotifierProvider`: Loading/error/data states
- `StreamProvider`: Real-time data streams
- Future providers: One-time async operations
### Data Persistence: Hive CE
**Why Hive CE?**
- No native code dependencies
- Fast key-value storage
- Type-safe with code generation
- No manual field annotations needed
**Stores:**
- `SettingStore`: App preferences
- `ServerStore`: Server configurations
- `SnippetStore`: Command snippets
- `KeyStore`: SSH keys
### Immutable Models: Freezed
**Benefits:**
- Compile-time immutability
- Union types for state
- Built-in JSON serialization
- CopyWith extensions
## Cross-Platform Strategy
### Plugin System
Flutter plugins provide platform integration:
| Platform | Integration Method |
|----------|-------------------|
| iOS | CocoaPods, Swift/Obj-C |
| Android | Gradle, Kotlin/Java |
| macOS | CocoaPods, Swift |
| Linux | CMake, C++ |
| Windows | CMake, C# |
### Platform-Specific Features
**iOS Only:**
- Home screen widgets
- Live Activities
- Apple Watch companion
**Android Only:**
- Background service
- Push notifications
- File system access
**Desktop Only:**
- Menu bar integration
- Multiple windows
- Custom title bar
## Custom Dependencies
### dartssh2 Fork
Enhanced SSH client with:
- Better mobile support
- Enhanced error handling
- Performance optimizations
### xterm.dart Fork
Terminal emulator with:
- Mobile-optimized rendering
- Touch gesture support
- Virtual keyboard integration
### fl_lib
Shared utilities package with:
- Common widgets
- Extensions
- Helper functions
## Build System
### fl_build Package
Custom build system for:
- Multi-platform builds
- Code signing
- Asset bundling
- Version management
### Build Process
```
make.dart (version) → fl_build (build) → Platform output
```
1. **Pre-build**: Calculate version from Git
2. **Build**: Compile for target platform
3. **Post-build**: Package and sign
## Data Flow Example
### Server Status Update
```
1. Timer triggers →
2. Provider calls service →
3. Service executes SSH command →
4. Response parsed to model →
5. State updated →
6. UI rebuilds with new data
```
### User Action Flow
```
1. User taps button →
2. Widget calls provider method →
3. Provider updates state →
4. State change triggers rebuild →
5. New state reflected in UI
```
## Security Architecture
### Data Protection
- **Passwords**: Encrypted with flutter_secure_storage
- **SSH Keys**: Encrypted at rest
- **Host Fingerprints**: Stored securely
- **Session Data**: Not persisted
### Connection Security
- **Host Key Verification**: MITM detection
- **Encryption**: Standard SSH encryption
- **No Plain Text**: Sensitive data never stored plain

View File

@@ -0,0 +1,490 @@
---
title: SFTP System
description: How the SFTP file browser works
---
The SFTP system provides file management capabilities over SSH.
## Architecture
```
┌─────────────────────────────────────────────┐
│ SFTP UI Layer │
│ - File browser (remote) │
│ - File browser (local) │
│ - Transfer queue │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ SFTP State Management │
│ - sftpProvider │
│ - Path management │
│ - Operation queue │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ SFTP Protocol Layer │
│ - SSH subsystem │
│ - File operations │
│ - Directory listing │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ SSH Transport │
│ - Secure channel │
│ - Data streaming │
└─────────────────────────────────────────────┘
```
## Connection Establishment
### SFTP Client Creation
```dart
Future<SftpClient> createSftpClient(Spi spi) async {
// 1. Get SSH client (reuse if available)
final sshClient = await genClient(spi);
// 2. Open SFTP subsystem
final sftp = await sshClient.openSftp();
return sftp;
}
```
### Connection Reuse
SFTP reuses existing SSH connections:
```dart
class ServerProvider {
SSHClient? _sshClient;
SftpClient? _sftpClient;
Future<SftpClient> getSftpClient(String spiId) async {
_sftpClient ??= await _sshClient!.openSftp();
return _sftpClient!;
}
}
```
## File System Operations
### Directory Listing
```dart
Future<List<SftpFile>> listDirectory(String path) async {
final sftp = await getSftpClient(spiId);
// List directory
final files = await sftp.listDir(path);
// Sort based on settings
files.sort((a, b) {
switch (sortOption) {
case SortOption.name:
return a.name.toLowerCase().compareTo(b.name.toLowerCase());
case SortOption.size:
return a.size.compareTo(b.size);
case SortOption.time:
return a.modified.compareTo(b.modified);
}
});
// Folders first if enabled
if (showFoldersFirst) {
final dirs = files.where((f) => f.isDirectory);
final regular = files.where((f) => !f.isDirectory);
return [...dirs, ...regular];
}
return files;
}
```
### File Metadata
```dart
class SftpFile {
final String name;
final String path;
final int size; // Bytes
final int modified; // Unix timestamp
final String permissions; // e.g., "rwxr-xr-x"
final String owner;
final String group;
final bool isDirectory;
final bool isSymlink;
String get sizeFormatted => formatBytes(size);
String get modifiedFormatted => formatDate(modified);
}
```
## File Operations
### Upload
```dart
Future<void> uploadFile(
String localPath,
String remotePath,
) async {
final sftp = await getSftpClient(spiId);
// Create request
final req = SftpReq(
spi: spi,
remotePath: remotePath,
localPath: localPath,
type: SftpReqType.upload,
);
// Add to queue
_transferQueue.add(req);
// Execute transfer with progress
final file = File(localPath);
final size = await file.length();
final stream = file.openRead();
await sftp.upload(
stream: stream,
toPath: remotePath,
onProgress: (transferred) {
_updateProgress(req, transferred, size);
},
);
// Complete
_transferQueue.remove(req);
}
```
### Download
```dart
Future<void> downloadFile(
String remotePath,
String localPath,
) async {
final sftp = await getSftpClient(spiId);
// Create local file
final file = File(localPath);
final sink = file.openWrite();
// Download with progress
final stat = await sftp.stat(remotePath);
await sftp.download(
fromPath: remotePath,
toSink: sink,
onProgress: (transferred) {
_updateProgress(
SftpReq(...),
transferred,
stat.size,
);
},
);
await sink.close();
}
```
### Permission Editing
```dart
Future<void> setPermissions(
String path,
String permissions,
) async {
final sftp = await getSftpClient(spiId);
// Parse permissions (e.g., "rwxr-xr-x" or "755")
final mode = parsePermissions(permissions);
// Set via SSH command (more reliable than SFTP)
final ssh = await getSshClient(spiId);
await ssh.exec('chmod $mode "$path"');
}
```
## Path Management
### Path Structure
```dart
class PathWithPrefix {
final String prefix; // e.g., "/home/user"
final String path; // Relative or absolute
String get fullPath {
if (path.startsWith('/')) {
return path; // Absolute path
}
return '$prefix/$path'; // Relative path
}
PathWithPrefix cd(String subPath) {
return PathWithPrefix(
prefix: fullPath,
path: subPath,
);
}
}
```
### Navigation History
```dart
class PathHistory {
final List<String> _history = [];
int _index = -1;
void push(String path) {
// Remove forward history
_history.removeRange(_index + 1, _history.length);
_history.add(path);
_index = _history.length - 1;
}
String? back() {
if (_index > 0) {
_index--;
return _history[_index];
}
return null;
}
String? forward() {
if (_index < _history.length - 1) {
_index++;
return _history[_index];
}
return null;
}
}
```
## Transfer System
### Transfer Request
```dart
class SftpReq {
final Spi spi;
final String remotePath;
final String localPath;
final SftpReqType type;
final DateTime createdAt;
int? totalBytes;
int? transferredBytes;
String? error;
}
```
### Progress Tracking
```dart
class TransferProgress {
final SftpReq request;
final int total;
final int transferred;
final DateTime startTime;
double get percentage => (transferred / total) * 100;
Duration get elapsed => DateTime.now().difference(startTime);
String get speedFormatted {
final bytesPerSecond = transferred / elapsed.inSeconds;
return formatSpeed(bytesPerSecond);
}
}
```
### Queue Management
```dart
class TransferQueue {
final List<SftpReq> _queue = [];
final Map<String, TransferProgress> _progress = {};
int _concurrent = 3; // Max concurrent transfers
Future<void> process() async {
final active = _progress.values.where((p) => p.isInProgress);
if (active.length >= _concurrent) return;
final pending = _queue.where((r) => !_progress.containsKey(r.id));
for (final req in pending.take(_concurrent - active.length)) {
_executeTransfer(req);
}
}
Future<void> _executeTransfer(SftpReq req) async {
try {
_progress[req.id] = TransferProgress.inProgress(req);
if (req.type == SftpReqType.upload) {
await uploadFile(req.localPath, req.remotePath);
} else {
await downloadFile(req.remotePath, req.localPath);
}
_progress[req.id] = TransferProgress.completed(req);
} catch (e) {
_progress[req.id] = TransferProgress.failed(req, e);
}
}
}
```
## Local Storage Pattern
### Download Cache
Downloaded files stored at:
```dart
String getLocalDownloadPath(String spiId, String remotePath) {
final normalized = remotePath.replaceAll('/', '_');
return 'Paths.file/$spiId/$normalized';
}
```
Example:
- Remote: `/var/log/nginx/access.log`
- spiId: `server-123`
- Local: `Paths.file/server-123/_var_log_nginx_access.log`
## File Editing
### Edit Workflow
```dart
Future<void> editFile(String path) async {
final sftp = await getSftpClient(spiId);
// 1. Check size
final stat = await sftp.stat(path);
if (stat.size > editorMaxSize) {
showWarning('File too large for built-in editor');
return;
}
// 2. Download to temp
final temp = await downloadToTemp(path);
// 3. Open in editor
final content = await openEditor(temp.path);
// 4. Upload back
await uploadFile(temp.path, path);
// 5. Cleanup
await temp.delete();
}
```
### External Editor Integration
```dart
Future<void> editInExternalEditor(String path) async {
final ssh = await getSshClient(spiId);
// Open terminal with editor
final editor = getSetting('sftpEditor', 'vim');
await ssh.exec('$editor "$path"');
// User edits in terminal
// After save, refresh SFTP view
}
```
## Error Handling
### Permission Errors
```dart
try {
await sftp.upload(...);
} on SftpPermissionException {
showError('Permission denied: ${stat.path}');
showHint('Check file permissions and ownership');
}
```
### Connection Errors
```dart
try {
await sftp.listDir(path);
} on SftpConnectionException {
showError('Connection lost');
await reconnect();
}
```
### Space Errors
```dart
try {
await sftp.upload(...);
} on SftpNoSpaceException {
showError('Disk full on remote server');
}
```
## Performance Optimizations
### Directory Caching
```dart
class DirectoryCache {
final Map<String, CachedDirectory> _cache = {};
final Duration ttl = Duration(minutes: 5);
Future<List<SftpFile>> list(String path) async {
final cached = _cache[path];
if (cached != null && !cached.isExpired) {
return cached.files;
}
final files = await sftp.listDir(path);
_cache[path] = CachedDirectory(files);
return files;
}
}
```
### Lazy Loading
For large directories (>1000 items):
```dart
List<SftpFile> loadPage(String path, int page, int pageSize) {
final all = cache[path] ?? [];
final start = page * pageSize;
final end = start + pageSize;
return all.sublist(start, end.clamp(0, all.length));
}
```
### Pagination
```dart
class PaginatedDirectory {
static const pageSize = 100;
Future<List<SftpFile>> getPage(int page) async {
final offset = page * pageSize;
return await sftp.listDir(
path,
offset: offset,
limit: pageSize,
);
}
}
```

View File

@@ -0,0 +1,299 @@
---
title: SSH Connection
description: How SSH connections are established and managed
---
Understanding SSH connections in Flutter Server Box.
## Connection Flow
```
User Input → Spi Config → genClient() → SSH Client → Session
```
### Step 1: Configuration
The `Spi` (Server Parameter Info) model contains:
```dart
class Spi {
String name; // Server name
String ip; // IP address
int port; // SSH port (default 22)
String user; // Username
String? pwd; // Password (encrypted)
String? keyId; // SSH key ID
String? jumpId; // Jump server ID
String? alterUrl; // Alternative URL
}
```
### Step 2: Client Generation
`genClient(spi)` creates SSH client:
```dart
Future<SSHClient> genClient(Spi spi) async {
// 1. Establish socket
final socket = await connect(spi.ip, spi.port);
// 2. Try alternative URL if failed
if (socket == null && spi.alterUrl != null) {
socket = await connect(spi.alterUrl, spi.port);
}
// 3. Authenticate
final client = SSHClient(
socket: socket,
username: spi.user,
onPasswordRequest: () => spi.pwd,
onIdentityRequest: () => loadKey(spi.keyId),
);
// 4. Verify host key
await verifyHostKey(client, spi);
return client;
}
```
### Step 3: Jump Server (if configured)
For jump servers, recursive connection:
```dart
if (spi.jumpId != null) {
final jumpClient = await genClient(getJumpSpi(spi.jumpId));
final forwarded = await jumpClient.forwardLocal(
spi.ip,
spi.port,
);
// Connect through forwarded socket
}
```
## Authentication Methods
### Password Authentication
```dart
onPasswordRequest: () => spi.pwd
```
- Password stored encrypted in Hive
- Decrypted on connection
- Sent to server for verification
### Private Key Authentication
```dart
onIdentityRequest: () async {
final key = await KeyStore.get(spi.keyId);
return decyptPem(key.pem, key.password);
}
```
**Key Loading Process:**
1. Retrieve encrypted key from `KeyStore`
2. Decrypt password (biometric/prompt)
3. Parse PEM format
4. Standardize line endings (LF)
5. Return for authentication
### Keyboard-Interactive
```dart
onUserInfoRequest: (instructions) async {
// Handle challenge-response
return responses;
}
```
Supports:
- Password authentication
- OTP tokens
- Two-factor authentication
## Host Key Verification
### Why Verify Host Keys?
Prevents **Man-in-the-Middle (MITM)** attacks by ensuring you're connecting to the same server.
### Storage Format
```
{spi.id}::{keyType}
```
Example:
```
my-server::ssh-ed25519
my-server::ecdsa-sha2-nistp256
```
### Fingerprint Formats
**MD5 Hex:**
```
aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99
```
**Base64:**
```
SHA256:AbCdEf1234567890...=
```
### Verification Flow
```dart
Future<void> verifyHostKey(SSHClient client, Spi spi) async {
final key = await client.hostKey;
final fingerprint = md5Hex(key); // or base64
final stored = SettingStore.sshKnownHostsFingerprints
['$keyId::$keyType'];
if (stored == null) {
// New host - prompt user
final trust = await promptUser(
'Unknown host',
'Fingerprint: $fingerprint',
);
if (trust) {
SettingStore.sshKnownHostsFingerprints
['$keyId::$keyType'] = fingerprint;
}
} else if (stored != fingerprint) {
// Changed - warn user
await warnUser(
'Host key changed!',
'Possible MITM attack',
);
}
}
```
## Session Management
### Connection Pooling
Active clients maintained in `ServerProvider`:
```dart
class ServerProvider {
final Map<String, SSHClient> _clients = {};
SSHClient getClient(String spiId) {
return _clients[spiId] ??= connect(spiId);
}
}
```
### Keep-Alive
Maintain connection during inactivity:
```dart
Timer.periodic(
Duration(seconds: 30),
(_) => client.sendKeepAlive(),
);
```
### Auto-Reconnect
On connection loss:
```dart
client.onError.listen((error) async {
await Future.delayed(Duration(seconds: 5));
reconnect();
});
```
## Connection Lifecycle
```
┌─────────────┐
│ Initial │
└──────┬──────┘
│ connect()
┌─────────────┐
│ Connecting │ ←──┐
└──────┬──────┘ │
│ success │
↓ │ fail (retry)
┌─────────────┐ │
│ Connected │───┘
└──────┬──────┘
┌─────────────┐
│ Active │ ──→ Send commands
└──────┬──────┘
↓ (error/disconnect)
┌─────────────┐
│ Disconnected│
└─────────────┘
```
## Error Handling
### Connection Timeout
```dart
try {
await client.connect().timeout(
Duration(seconds: 30),
);
} on TimeoutException {
throw ConnectionException('Connection timeout');
}
```
### Authentication Failure
```dart
onAuthFail: (error) {
if (error.contains('password')) {
return 'Invalid password';
} else if (error.contains('key')) {
return 'Invalid SSH key';
}
return 'Authentication failed';
}
```
### Host Key Mismatch
```dart
onHostKeyMismatch: (stored, current) {
showSecurityWarning(
'Host key has changed!',
'Possible MITM attack',
);
}
```
## Performance Considerations
### Connection Reuse
- Reuse clients across features
- Don't disconnect/reconnect unnecessarily
- Pool connections for concurrent operations
### Optimal Settings
- **Timeout**: 30 seconds (adjustable)
- **Keep-alive**: Every 30 seconds
- **Retry delay**: 5 seconds
### Network Efficiency
- Single connection for multiple operations
- Pipeline commands when possible
- Avoid opening multiple connections

View File

@@ -0,0 +1,405 @@
---
title: State Management
description: How state is managed with Riverpod
---
Understanding the state management architecture in Flutter Server Box.
## Why Riverpod?
**Key Benefits:**
- **Compile-time safety**: Catch errors at compile time
- **No BuildContext needed**: Access state anywhere
- **Easy testing**: Simple to test providers in isolation
- **Code generation**: Less boilerplate, type-safe
## Provider Architecture
```
┌─────────────────────────────────────────────┐
│ UI Layer (Widgets) │
│ - ConsumerWidget / ConsumerStatefulWidget │
│ - ref.watch() / ref.read() │
└─────────────────────────────────────────────┘
↓ watches
┌─────────────────────────────────────────────┐
│ Provider Layer │
│ - @riverpod annotations │
│ - Generated *.g.dart files │
└─────────────────────────────────────────────┘
↓ uses
┌─────────────────────────────────────────────┐
│ Service / Store Layer │
│ - Business logic │
│ - Data access │
└─────────────────────────────────────────────┘
```
## Provider Types Used
### 1. StateProvider (Simple State)
For simple, observable state:
```dart
@riverpod
class ThemeNotifier extends _$ThemeNotifier {
@override
ThemeMode build() {
// Load from settings
return SettingStore.themeMode;
}
void setTheme(ThemeMode mode) {
state = mode;
SettingStore.themeMode = mode; // Persist
}
}
```
**Usage:**
```dart
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = ref.watch(themeNotifierProvider);
return Text('Theme: $theme');
}
}
```
### 2. AsyncNotifierProvider (Async State)
For data that loads asynchronously:
```dart
@riverpod
class ServerStatus extends _$ServerStatus {
@override
Future<StatusModel> build(Server server) async {
// Initial load
return await fetchStatus(server);
}
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return await fetchStatus(server);
});
}
}
```
**Usage:**
```dart
final status = ref.watch(serverStatusProvider(server));
status.when(
data: (data) => StatusWidget(data),
loading: () => LoadingWidget(),
error: (error, stack) => ErrorWidget(error),
)
```
### 3. StreamProvider (Real-time Data)
For continuous data streams:
```dart
@riverpod
Stream<CpuUsage> cpuUsage(CpuUsageRef ref, Server server) {
final client = ref.watch(sshClientProvider(server));
final stream = client.monitorCpu();
// Auto-dispose when not watched
ref.onDispose(() {
client.stopMonitoring();
});
return stream;
}
```
**Usage:**
```dart
final cpu = ref.watch(cpuUsageProvider(server));
cpu.when(
data: (usage) => CpuChart(usage),
loading: () => CircularProgressIndicator(),
error: (error, stack) => ErrorWidget(error),
)
```
### 4. Family Providers (Parameterized)
Providers that accept parameters:
```dart
@riverpod
Future<List<Container>> containers(ContainersRef ref, Server server) async {
final client = await ref.watch(sshClientProvider(server).future);
return await client.listContainers();
}
```
**Usage:**
```dart
final containers = ref.watch(containersProvider(server));
// Different servers = different cached states
final containers2 = ref.watch(containersProvider(server2));
```
## State Update Patterns
### Direct State Update
```dart
ref.read(settingsProvider.notifier).updateTheme(darkMode);
```
### Computed State
```dart
@riverpod
int totalServers(TotalServersRef ref) {
final servers = ref.watch(serversProvider);
return servers.length;
}
```
### Derived State
```dart
@riverpod
List<Server> onlineServers(OnlineServersRef ref) {
final all = ref.watch(serversProvider);
return all.where((s) => s.isOnline).toList();
}
```
## Server-Specific State
### Per-Server Providers
Each server has isolated state:
```dart
@riverpod
class ServerProvider extends _$ServerProvider {
@override
ServerState build(Server server) {
return ServerState.disconnected();
}
Future<void> connect() async {
state = ServerState.connecting();
try {
final client = await genClient(server.spi);
state = ServerState.connected(client);
} catch (e) {
state = ServerState.error(e.toString());
}
}
}
```
### Provider Keys
```dart
// Unique provider per server
@riverpod
ServerStatus serverStatus(ServerStatusRef ref, Server server) {
// server.id used as key
}
```
## Reactive Patterns
### Auto-Refresh
```dart
@riverpod
class AutoRefreshServerStatus extends _$AutoRefreshServerStatus {
Timer? _timer;
@override
Future<StatusModel> build(Server server) async {
// Start timer
_timer = Timer.periodic(Duration(seconds: 5), (_) {
refresh();
});
ref.onDispose(() {
_timer?.cancel();
});
return await fetchStatus(server);
}
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => fetchStatus(server));
}
}
```
### Multi-Provider Dependencies
```dart
@riverpod
Future<SystemInfo> systemInfo(SystemInfoRef ref, Server server) async {
// Wait for SSH client first
final client = await ref.watch(sshClientProvider(server).future);
// Then fetch system info
return await client.getSystemInfo();
}
```
## State Persistence
### Hive Integration
```dart
@riverpod
class ServerStoreNotifier extends _$ServerStoreNotifier {
@override
List<Server> build() {
// Load from Hive
return Hive.box<Server>('servers').values.toList();
}
void addServer(Server server) {
state = [...state, server];
// Persist to Hive
Hive.box<Server>('servers').put(server.id, server);
}
void removeServer(String id) {
state = state.where((s) => s.id != id).toList();
// Remove from Hive
Hive.box<Server>('servers').delete(id);
}
}
```
## Error Handling
### Error States
```dart
@riverpod
class ConnectionManager extends _$ConnectionManager {
@override
ConnectionState build() {
return ConnectionState.idle();
}
Future<void> connect(Server server) async {
state = ConnectionState.connecting();
try {
final client = await genClient(server.spi);
state = ConnectionState.connected(client);
} on SocketException catch (e) {
state = ConnectionState.error('Network error: $e');
} on AuthenticationException catch (e) {
state = ConnectionState.error('Auth failed: $e');
} catch (e) {
state = ConnectionState.error('Unknown error: $e');
}
}
}
```
### Error Recovery
```dart
@riverpod
class ResilientFetcher extends _$ResilientFetcher {
int _retryCount = 0;
@override
Future<Data> build(Server server) async {
return await _fetchWithRetry();
}
Future<Data> _fetchWithRetry() async {
try {
return await fetchData(server);
} catch (e) {
if (_retryCount < 3) {
_retryCount++;
await Future.delayed(Duration(seconds: 2));
return await _fetchWithRetry();
}
rethrow;
}
}
}
```
## Performance Optimizations
### Provider Keep-Alive
```dart
@Riverpod(keepAlive: true) // Don't dispose when no listeners
class GlobalSettings extends _$GlobalSettings {
@override
Settings build() {
return Settings.defaults();
}
}
```
### Selective Watching
```dart
// Watch only specific part of state
final name = ref.watch(serverProvider.select((s) => s.name));
```
### Provider Caching
Family providers cache results per parameter:
```dart
// Cached per server ID
final status1 = ref.watch(serverStatusProvider(server1));
final status2 = ref.watch(serverStatusProvider(server2));
// Different states, both cached
```
## Testing with Riverpod
### Provider Container
```dart
test('fetch server status', () async {
final container = ProviderContainer();
addTearDown(container.dispose);
// Override provider
container.overrideFactory(
sshClientProvider,
(ref, server) => MockSshClient(),
);
final status = await container.read(
serverStatusProvider(testServer).future,
);
expect(status, isA<StatusModel>());
});
```
## Best Practices
1. **Co-locate providers**: Place near consuming widgets
2. **Use code generation**: Always use `@riverpod`
3. **Keep providers focused**: Single responsibility
4. **Handle loading states**: Always handle AsyncValue states
5. **Dispose resources**: Use `ref.onDispose()` for cleanup
6. **Avoid deep provider trees**: Keep provider graph flat

View File

@@ -0,0 +1,343 @@
---
title: Terminal Implementation
description: How the SSH terminal works internally
---
The SSH terminal is one of the most complex features, built on a custom xterm.dart fork.
## Architecture Overview
```
┌─────────────────────────────────────────────┐
│ Terminal UI Layer │
│ - Tab management │
│ - Virtual keyboard │
│ - Text selection │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ xterm.dart Emulator │
│ - PTY (Pseudo Terminal) │
│ - VT100/ANSI emulation │
│ - Rendering engine │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ SSH Client Layer │
│ - SSH session │
│ - Channel management │
│ - Data streaming │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Remote Server │
│ - Shell process │
│ - Command execution │
└─────────────────────────────────────────────┘
```
## Terminal Session Lifecycle
### 1. Session Creation
```dart
Future<TerminalSession> createSession(Spi spi) async {
// 1. Get SSH client
final client = await genClient(spi);
// 2. Create PTY
final pty = await client.openPty(
term: 'xterm-256color',
cols: 80,
rows: 24,
);
// 3. Initialize terminal emulator
final terminal = Terminal(
backend: PtyBackend(pty),
);
// 4. Setup resize handler
terminal.onResize.listen((size) {
pty.resize(size.cols, size.rows);
});
return TerminalSession(
terminal: terminal,
pty: pty,
client: client,
);
}
```
### 2. Terminal Emulation
The xterm.dart fork provides:
**VT100/ANSI Emulation:**
- Cursor movement
- Colors (256-color support)
- Text attributes (bold, underline, etc.)
- Scrolling regions
- Alternate screen buffer
**Rendering:**
- Line-based rendering
- Bidirectional text support
- Unicode/emoji support
- Optimized redraws
### 3. Data Flow
```
User Input
Virtual Keyboard / Physical Keyboard
Terminal Emulator (key → escape sequence)
SSH Channel (send)
Remote PTY
Remote Shell
Command Output
SSH Channel (receive)
Terminal Emulator (parse ANSI codes)
Render to Screen
```
## Multi-Tab System
### Tab Management
```dart
class TerminalTabs {
final Map<String, TabData> _tabs = {};
String? _activeTabId;
void createTab(Server server) {
final id = _generateTabId(server);
_tabs[id] = TabData(
id: id,
name: _generateTabName(server),
session: createSession(server),
);
_activeTabId = id;
}
String _generateTabName(Server server) {
final count = _tabs.values
.where((t) => t.name.startsWith(server.name))
.length;
return count == 0 ? server.name : '${server.name}($count)';
}
}
```
### Session Persistence
Tabs maintain state across navigation:
- SSH connection kept alive
- Terminal state preserved
- Scroll buffer maintained
- Input history retained
## Virtual Keyboard
### Platform-Specific Implementation
**iOS:**
- UIView-based custom keyboard
- Toggleable with keyboard button
- Auto-show/hide based on focus
**Android:**
- Custom input method
- Integrated with system keyboard
- Quick action buttons
### Keyboard Buttons
| Button | Action |
|--------|--------|
| **Toggle** | Show/hide system keyboard |
| **Ctrl** | Send Ctrl modifier |
| **Alt** | Send Alt modifier |
| **SFTP** | Open current directory |
| **Clipboard** | Copy/Paste context-aware |
| **Snippets** | Execute snippet |
### Key Encoding
```dart
String encodeKey(Key key) {
switch (key) {
case Key.enter:
return '\r';
case Key.tab:
return '\t';
case Key.escape:
return '\x1b';
case Key.ctrlC:
return '\x03';
// ... more keys
}
}
```
## Text Selection
### Selection Mode
1. **Long press**: Enter selection mode
2. **Drag**: Extend selection
3. **Release**: Copy to clipboard
### Selection Storage
```dart
class TextSelection {
final BufferRange range;
final String text;
void copyToClipboard() {
Clipboard.setData(ClipboardData(text: text));
}
}
```
## Font and Dimensions
### Size Calculation
```dart
class TerminalDimensions {
static Size calculate(double fontSize, Size screenSize) {
final charWidth = fontSize * 0.6; // Monospace aspect ratio
final charHeight = fontSize * 1.2;
final cols = (screenSize.width / charWidth).floor();
final rows = (screenSize.height / charHeight).floor();
return Size(cols.toDouble(), rows.toDouble());
}
}
```
### Pinch-to-Zoom
```dart
GestureDetector(
onScaleStart: () => _baseFontSize = currentFontSize,
onScaleUpdate: (details) {
final newFontSize = _baseFontSize * details.scale;
resize(newFontSize);
},
)
```
## Color Scheme
### ANSI Color Mapping
```dart
const colorMap = {
0: Color(0x000000), // Black
1: Color(0x800000), // Red
2: Color(0x008000), // Green
3: Color(0x808000), // Yellow
4: Color(0x000080), // Blue
5: Color(0x800080), // Magenta
6: Color(0x008080), // Cyan
7: Color(0xC0C0C0), // White
// ... 256-color palette
};
```
### Theme Support
- **Light**: Light background, dark text
- **Dark**: Dark background, light text
- **AMOLED**: Pure black background
## Performance Optimizations
### Rendering Optimizations
- **Dirty rectangle**: Only redraw changed regions
- **Line caching**: Cache rendered lines
- **Lazy scrolling**: Virtual scrolling for long buffers
### Data Optimizations
- **Batch updates**: Coalesce multiple writes
- **Compression**: Compress scroll buffer
- **Debouncing**: Debounce rapid inputs
## Clipboard Integration
### Copy Selection
```dart
void copySelection() {
final selected = terminal.getSelection();
Clipboard.setData(ClipboardData(text: selected));
}
```
### Paste Clipboard
```dart
Future<void> pasteClipboard() async {
final data = await Clipboard.getData('text/plain');
if (data?.text != null) {
terminal.paste(data!.text!);
}
}
```
### Context-Aware Button
- **Has selection**: Show "Copy"
- **Has clipboard**: Show "Paste"
- **Both**: Show primary action
## Special Features
### Snippet Execution
```dart
void executeSnippet(Snippet snippet) {
final formatted = formatSnippet(snippet);
terminal.paste(formatted);
terminal.paste('\r'); // Execute
}
```
### SFTP Quick Access
```dart
void openSftp() async {
final cwd = await terminal.getCurrentWorkingDirectory();
Navigator.push(
context,
SftpPage(initialPath: cwd),
);
}
```
### Keep-Alive
```dart
Timer.periodic(Duration(seconds: 30), (_) {
if (terminal.isActive) {
terminal.send('\x00'); // NUL - no-op keep-alive
}
});
```

View File

@@ -0,0 +1,51 @@
---
title: Quick Start
description: Get up and running with Flutter Server Box in minutes
---
Follow this quick start guide to connect to your first server and start monitoring.
## Step 1: Add a Server
1. Open Flutter Server Box
2. Tap the **+** button to add a new server
3. Fill in the server information:
- **Name**: A friendly name for your server
- **Host**: IP address or domain name
- **Port**: SSH port (default: 22)
- **User**: SSH username
- **Password or Key**: Authentication method
4. Tap **Save** to add the server
## Step 2: Connect and Monitor
1. Tap on your server card to connect
2. The app will establish an SSH connection
3. You'll see real-time status for:
- CPU usage
- Memory (RAM) and Swap
- Disk usage
- Network speed
## Step 3: Explore Features
Once connected, you can:
- **Open Terminal**: Tap the terminal button for full SSH access
- **Browse Files**: Use SFTP to manage files
- **Manage Containers**: View and control Docker containers
- **View Processes**: Check running processes
- **Run Snippets**: Execute saved commands
## Tips
- **Biometric Authentication**: Enable Face ID / Touch ID / Fingerprint for quick access (mobile)
- **Home Screen Widgets**: Add server status widgets to your home screen (iOS/Android)
- **Background Running**: Keep connections alive in the background (Android)
## Next Steps
- Explore the [Features](/features/) section for detailed guides
- Configure [SSH Keys](/configuration/ssh-keys/) for passwordless authentication
- Customize your experience in [Settings](/configuration/appearance/)

View File

@@ -0,0 +1,7 @@
/* Flutter Server Box Custom Styles */
:root {
--sl-color-accent: #02569b;
--sl-color-accent-low: #02569b15;
--starlight-cards--border: var(--sl-color-accent-low);
}