diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 0247c54..0000000 --- a/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/android/app/src/main/res/drawable/ic_launcher_foreground.xml b/android/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 5fb7b02..0000000 --- a/android/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index bca081d..31092ba 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,7 +1,9 @@ + density-bucket PNG fallbacks are needed. The foreground is the full circular + app icon (ic_launcher_foreground.png); the launcher mask crops the disc to + its shape, and the solid gruvbox background fills the transparent corners. --> - - + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 6b78462..af8535f 100644 --- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..e9c95b1 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt index cb3bf7a..c78249e 100644 --- a/desktop/CMakeLists.txt +++ b/desktop/CMakeLists.txt @@ -4,6 +4,7 @@ project(photogallery_uploader LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) find_package(Qt6 REQUIRED COMPONENTS Widgets Network Concurrent) find_package(Qt6Keychain REQUIRED) @@ -15,6 +16,7 @@ add_executable(uploader settings.cpp uploadclient.cpp imageprep.cpp + app.qrc ) target_link_libraries(uploader PRIVATE @@ -23,3 +25,14 @@ target_link_libraries(uploader PRIVATE Qt6::Concurrent Qt6Keychain::Qt6Keychain ) + +# Installation — the binary, a desktop entry, and the app icon in the hicolor +# theme, so `nix profile install ./desktop` puts "Photog" in the app menu. +include(GNUInstallDirs) +install(TARGETS uploader RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(FILES photog.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) +foreach(sz 32 128 256 512) + install(FILES icons/app-${sz}.png + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/${sz}x${sz}/apps + RENAME photog.png) +endforeach() diff --git a/desktop/app.qrc b/desktop/app.qrc new file mode 100644 index 0000000..ea4e298 --- /dev/null +++ b/desktop/app.qrc @@ -0,0 +1,9 @@ + + + + icons/app-32.png + icons/app-128.png + icons/app-256.png + icons/app-512.png + + diff --git a/desktop/flake.nix b/desktop/flake.nix index 2a27e5f..7e9b1f3 100644 --- a/desktop/flake.nix +++ b/desktop/flake.nix @@ -17,6 +17,28 @@ pkgs.qt6.qtimageformats ]; in { + # Installable build: `nix profile install ./desktop` drops "Photog" into + # the application menu with its icon. wrapQtAppsHook wraps the binary so + # it finds the Qt platform (xcb + wayland) and image-format plugins on + # its own, without the dev shell. + packages.default = pkgs.stdenv.mkDerivation { + pname = "photog"; + version = "0.1.0"; + src = ./.; + nativeBuildInputs = with pkgs; [ + cmake + ninja + pkg-config + qt6.wrapQtAppsHook + ]; + buildInputs = with pkgs; [ + qt6.qtbase + qt6.qtwayland + qt6.qtimageformats + qt6Packages.qtkeychain + ]; + }; + devShells.default = pkgs.mkShell { packages = with pkgs; [ cmake diff --git a/desktop/icons/app-128.png b/desktop/icons/app-128.png new file mode 100644 index 0000000..35493a8 Binary files /dev/null and b/desktop/icons/app-128.png differ diff --git a/desktop/icons/app-256.png b/desktop/icons/app-256.png new file mode 100644 index 0000000..6d0c67c Binary files /dev/null and b/desktop/icons/app-256.png differ diff --git a/desktop/icons/app-32.png b/desktop/icons/app-32.png new file mode 100644 index 0000000..1de4612 Binary files /dev/null and b/desktop/icons/app-32.png differ diff --git a/desktop/icons/app-512.png b/desktop/icons/app-512.png new file mode 100644 index 0000000..8fd0b36 Binary files /dev/null and b/desktop/icons/app-512.png differ diff --git a/desktop/main.cpp b/desktop/main.cpp index dd2280c..cdce43b 100644 --- a/desktop/main.cpp +++ b/desktop/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "mainwindow.h" @@ -8,6 +9,15 @@ int main(int argc, char **argv) app.setApplicationName(QStringLiteral("photogallery-uploader")); app.setOrganizationName(QStringLiteral("inflo.ws")); + // Window / taskbar / alt-tab icon, embedded via app.qrc. Several sizes so + // the small titlebar rendering stays crisp rather than downscaling 512px. + QIcon icon; + icon.addFile(QStringLiteral(":/icons/app-32.png")); + icon.addFile(QStringLiteral(":/icons/app-128.png")); + icon.addFile(QStringLiteral(":/icons/app-256.png")); + icon.addFile(QStringLiteral(":/icons/app-512.png")); + app.setWindowIcon(icon); + MainWindow window; window.resize(440, 680); window.show(); diff --git a/desktop/photog.desktop b/desktop/photog.desktop new file mode 100644 index 0000000..4c61052 --- /dev/null +++ b/desktop/photog.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=Photog +GenericName=Photo Uploader +Comment=Upload photos to your gallery +Exec=uploader +Icon=photog +Terminal=false +Categories=Graphics;Photography;Network; diff --git a/generator.go b/generator.go index ceb3c09..57db661 100644 --- a/generator.go +++ b/generator.go @@ -713,6 +713,14 @@ func (g *Generator) copyStatic() error { if err := os.WriteFile(dst, data, 0644); err != nil { return err } + + // Also serve the favicon from the site root, where browsers and + // crawlers request /favicon.ico by default without a tag. + if e.Name() == "favicon.ico" { + if err := os.WriteFile(filepath.Join(g.outputDir, e.Name()), data, 0644); err != nil { + return err + } + } } return nil } diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..1ae8fe5 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/web-16.png b/static/web-16.png new file mode 100644 index 0000000..62e4270 Binary files /dev/null and b/static/web-16.png differ diff --git a/static/web-192.png b/static/web-192.png new file mode 100644 index 0000000..d94b94e Binary files /dev/null and b/static/web-192.png differ diff --git a/static/web-32.png b/static/web-32.png new file mode 100644 index 0000000..307e1ba Binary files /dev/null and b/static/web-32.png differ diff --git a/static/web-48.png b/static/web-48.png new file mode 100644 index 0000000..589fe37 Binary files /dev/null and b/static/web-48.png differ diff --git a/static/web-512.png b/static/web-512.png new file mode 100644 index 0000000..bfb911b Binary files /dev/null and b/static/web-512.png differ diff --git a/templates/day.html b/templates/day.html index fe9dfa5..1089d06 100644 --- a/templates/day.html +++ b/templates/day.html @@ -6,6 +6,9 @@ {{.Date}} · Photo Gallery + + + diff --git a/templates/grid.html b/templates/grid.html index a081a40..5cba5e8 100644 --- a/templates/grid.html +++ b/templates/grid.html @@ -6,6 +6,9 @@ Photo Gallery + + + diff --git a/templates/photo.html b/templates/photo.html index 55dde89..f6b9d87 100644 --- a/templates/photo.html +++ b/templates/photo.html @@ -25,6 +25,9 @@ + + + {{if .Newer}} diff --git a/templates/timeline.html b/templates/timeline.html index 04559f4..89f9242 100644 --- a/templates/timeline.html +++ b/templates/timeline.html @@ -6,6 +6,9 @@ Photo Gallery + + + diff --git a/templates/upload.html b/templates/upload.html index 54dc5ab..c1e1c05 100644 --- a/templates/upload.html +++ b/templates/upload.html @@ -6,6 +6,9 @@ Upload — Photo Gallery + + +