Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ jobs:
shell: bash
run: flutter build ${{ matrix.build_target }} --release

- name: Check macOS file associations
if: matrix.target == 'macos'
shell: bash
run: |
swiftc macos/Runner/FileAssociations.swift tool/macos_file_association_check.swift -o "$RUNNER_TEMP/rawviewer-association-check"
"$RUNNER_TEMP/rawviewer-association-check"

- name: Upload build artifact
uses: actions/upload-artifact@v6
with:
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Raw Viewer allows photographers and enthusiasts to seamlessly view, browse, and
- **EXIF Metadata:** Reads and displays true image capture timestamps directly from EXIF data.
- **Smooth Interaction:** Fast page scroll, smooth pinch-to-zoom (touch), and scroll-to-zoom (mouse) functionality.
- **Windows Context Menu:** Lets you install an “Open in RawView” Explorer entry for the current user, supporting files, multi-file selection, folders, and folder background opening.
- **Default File Associations:** Registers supported image formats on Windows and macOS. Windows uses the system Default Apps settings and displays effective associations; macOS provides per-format switches.
- **Single-File Open:** Opening one image jumps directly to its preview; neighboring files are loaded only when requested from the preview toolbar or when returning to the gallery.
- **Cross-Platform:** Built for desktop (Windows, macOS) and mobile (Android) natively.

## Screenshots
Expand Down
2 changes: 2 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Raw Viewer 旨在为摄影师和摄影爱好者提供一个轻量、流畅的工
- **EXIF 元数据:** 自动读取并显示 EXIF 中的真实拍摄时间。
- **流畅交互:** 支持顺滑的快速翻页,并适配了触屏的捏合缩放(Pinch-to-zoom)与鼠标滚轮缩放。
- **Windows 右键菜单:** 可在设置页一键将“在RawView中打开”安装到当前用户的资源管理器右键菜单,支持文件、多个文件、文件夹,以及文件夹空白处右键打开当前目录。
- **默认打开格式:** Windows 通过系统默认应用设置选择关联,并显示实际生效的状态;macOS 在设置页提供按格式切换的开关。
- **单图打开:** 直接打开单张图片时立即进入预览;相邻文件只会在预览顶栏主动加载目录或返回图库时加载。
- **跨平台支持:** 原生支持桌面端 (Windows, macOS) 与移动端 (Android)。

## 界面截图
Expand Down
58 changes: 58 additions & 0 deletions innosetup/rawviewer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Compression=lzma
SolidCompression=yes
WizardStyle=modern
UninstallDisplayIcon={app}\{#MyAppExeName}
ChangesAssociations=yes

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Expand All @@ -43,5 +44,62 @@ Source: "..\build\windows\packaged\*"; DestDir: "{app}"; Flags: ignoreversion re
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Registry]
Root: HKCU; Subkey: "Software\RegisteredApplications"; ValueType: string; ValueName: "RawViewer"; ValueData: "Software\RawViewer\Capabilities"; Flags: uninsdeletevalue
Root: HKCU; Subkey: "Software\RawViewer\Capabilities"; ValueType: string; ValueName: "ApplicationName"; ValueData: "Raw Viewer"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities"; ValueType: string; ValueName: "ApplicationDescription"; ValueData: "RAW and standard image viewer"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".arw"; ValueData: "RawViewer.arw"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".cr2"; ValueData: "RawViewer.cr2"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".cr3"; ValueData: "RawViewer.cr3"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".dng"; ValueData: "RawViewer.dng"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".nef"; ValueData: "RawViewer.nef"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".orf"; ValueData: "RawViewer.orf"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".raf"; ValueData: "RawViewer.raf"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".rw2"; ValueData: "RawViewer.rw2"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".srw"; ValueData: "RawViewer.srw"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".jpg"; ValueData: "RawViewer.jpg"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".jpeg"; ValueData: "RawViewer.jpeg"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".png"; ValueData: "RawViewer.png"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\RawViewer\Capabilities\FileAssociations"; ValueType: string; ValueName: ".webp"; ValueData: "RawViewer.webp"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.arw"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr2"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr3"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.dng"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.nef"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.orf"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.raf"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.rw2"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.srw"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpg"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpeg"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.png"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.webp"; ValueType: string; ValueName: ""; ValueData: "Raw Viewer image"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.arw\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr2\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr3\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.dng\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.nef\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.orf\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.raf\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.rw2\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.srw\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpg\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpeg\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.png\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.webp\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.arw\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr2\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.cr3\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.dng\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.nef\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.orf\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.raf\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.rw2\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.srw\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpg\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.jpeg\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.png\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\RawViewer.webp\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "Launch {#MyAppName}"; Flags: nowait postinstall skipifsilent
4 changes: 4 additions & 0 deletions lib/core/platform_channels.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'package:flutter/services.dart';

const MethodChannel desktopOpenChannel = MethodChannel('rawviewer/open_paths');
const MethodChannel macOSDirectoryAccessChannel =
MethodChannel('rawviewer/macos_directory_access');
const MethodChannel windowsShellChannel =
MethodChannel('rawviewer/windows_shell');
const MethodChannel fileAssociationChannel =
MethodChannel('rawviewer/file_associations');
1 change: 0 additions & 1 deletion lib/gallery/widgets/desktop_command_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,3 @@ class ThumbnailSizeControls extends StatelessWidget {
);
}
}

1 change: 0 additions & 1 deletion lib/gallery/widgets/gallery_chrome.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,3 @@ class GalleryStatusBar extends StatelessWidget {
);
}
}

1 change: 0 additions & 1 deletion lib/gallery/widgets/media_thumbnail_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,3 @@ class _MediaThumbnailTileState extends State<MediaThumbnailTile> {
return Hero(tag: widget.filePath, child: image);
}
}

Loading