diff --git a/i18n/en.json b/i18n/en.json index 3741722585..d699d1bf4a 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -566,6 +566,8 @@ "app_icon_midnight": "Midnight", "app_icon_neon": "Neon", "app_icon_ocean": "Ocean", + "app_icon_retro": "Retro", + "app_icon_scenic": "Scenic", "app_icon_subtitle": "Choose the icon shown on your home screen", "app_icon_sunset": "Sunset", "app_icon_title": "App Icon", diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml index be413a113a..4f78cedcd9 100644 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -142,6 +142,20 @@ + + + + + + + + + + + + diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/appicon/AppIconApiImpl.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/appicon/AppIconApiImpl.kt index 27d45f3136..834d13bdc0 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/appicon/AppIconApiImpl.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/appicon/AppIconApiImpl.kt @@ -15,7 +15,7 @@ class AppIconApiImpl(context: Context) : AppIconApi { companion object { private const val DEFAULT_ICON = "classic" private val ICONS = - listOf("classic", "midnight", "ocean", "sunset", "forest", "blossom", "ink", "neon", "gold") + listOf("classic", "retro", "scenic", "midnight", "ocean", "sunset", "forest", "blossom", "ink", "neon", "gold") } private fun componentFor(iconId: String): ComponentName { diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_bg_blossom.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_blossom.xml new file mode 100644 index 0000000000..efe1ee2462 --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_blossom.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_bg_gold.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_gold.xml new file mode 100644 index 0000000000..0dd707ea9a --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_gold.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_bg_midnight.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_midnight.xml new file mode 100644 index 0000000000..5d4171f5b4 --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_midnight.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_bg_neon.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_neon.xml new file mode 100644 index 0000000000..5df0d886b7 --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_neon.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_bg_sunset.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_sunset.xml new file mode 100644 index 0000000000..3370ce8adf --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_bg_sunset.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_blossom.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_blossom.xml deleted file mode 100644 index 0f3c7dec53..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_blossom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_forest.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_forest.xml deleted file mode 100644 index e8c8e1fc36..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_forest.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_gold.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_gold.xml deleted file mode 100644 index ef94097c42..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_gold.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ink.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ink.xml deleted file mode 100644 index 4f93f9822b..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ink.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_midnight.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_midnight.xml deleted file mode 100644 index d14fce37ea..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_midnight.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_neon.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_neon.xml deleted file mode 100644 index 088605e0d7..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_neon.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ocean.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ocean.xml deleted file mode 100644 index fe02311ab8..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_ocean.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_sunset.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_sunset.xml deleted file mode 100644 index 8cd24718c4..0000000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_foreground_sunset.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blossom.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blossom.xml index 53f5ea4ea6..5d9a411d19 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blossom.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_blossom.xml @@ -1,6 +1,6 @@ - - + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_forest.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_forest.xml index e1bfcac7c9..a9bfee6b20 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_forest.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_forest.xml @@ -1,6 +1,6 @@ - + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_gold.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_gold.xml index 0af836cba0..61e5c2c8d1 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_gold.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_gold.xml @@ -1,6 +1,6 @@ - - + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ink.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ink.xml index e93e5ab90f..7d62e091e1 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ink.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ink.xml @@ -1,6 +1,6 @@ - + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_midnight.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_midnight.xml index 7093707247..0b08fc128b 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_midnight.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_midnight.xml @@ -1,6 +1,6 @@ - - + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_neon.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_neon.xml index 119a62ba97..fcb501577c 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_neon.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_neon.xml @@ -1,6 +1,6 @@ - - + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ocean.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ocean.xml index 8d237e8439..680cde8574 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ocean.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_ocean.xml @@ -1,6 +1,6 @@ - + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_retro.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_retro.xml new file mode 100644 index 0000000000..8da663641b --- /dev/null +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_retro.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_scenic.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_scenic.xml new file mode 100644 index 0000000000..3a7239791b --- /dev/null +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_scenic.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sunset.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sunset.xml index 834347457b..d6a8d61b74 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sunset.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_sunset.xml @@ -1,6 +1,6 @@ - - + + diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_blossom.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_blossom.png new file mode 100644 index 0000000000..5f065a43f5 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_blossom.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_forest.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_forest.png new file mode 100644 index 0000000000..e2168cdd79 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_forest.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_gold.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_gold.png new file mode 100644 index 0000000000..7c7e530e49 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_gold.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ink.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ink.png new file mode 100644 index 0000000000..799f8f7f0b Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ink.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_midnight.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_midnight.png new file mode 100644 index 0000000000..10f4913a4c Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_midnight.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_neon.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_neon.png new file mode 100644 index 0000000000..39eb0c0d76 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_neon.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ocean.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ocean.png new file mode 100644 index 0000000000..24826a2587 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_ocean.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_retro.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_retro.png new file mode 100644 index 0000000000..8026106488 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_retro.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_scenic.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_scenic.png new file mode 100644 index 0000000000..b4ac8c645d Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_scenic.png differ diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_sunset.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_sunset.png new file mode 100644 index 0000000000..b30c52f66c Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground_sunset.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_blossom.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_blossom.png new file mode 100644 index 0000000000..477775c4a7 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_blossom.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_forest.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_forest.png new file mode 100644 index 0000000000..fd68c828e4 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_forest.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_gold.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_gold.png new file mode 100644 index 0000000000..40b46e7a80 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_gold.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ink.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ink.png new file mode 100644 index 0000000000..8b5a01d3b2 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ink.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_midnight.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_midnight.png new file mode 100644 index 0000000000..ecb5d20042 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_midnight.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_neon.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_neon.png new file mode 100644 index 0000000000..9d59c1f18a Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_neon.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ocean.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ocean.png new file mode 100644 index 0000000000..9e01273147 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_ocean.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_retro.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_retro.png new file mode 100644 index 0000000000..1937510289 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_retro.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_scenic.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_scenic.png new file mode 100644 index 0000000000..e7125b7841 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_scenic.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_sunset.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_sunset.png new file mode 100644 index 0000000000..2dcc7b4087 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground_sunset.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_blossom.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_blossom.png new file mode 100644 index 0000000000..2e8ff3cd2b Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_blossom.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_forest.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_forest.png new file mode 100644 index 0000000000..0589ed1074 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_forest.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_gold.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_gold.png new file mode 100644 index 0000000000..9b19d62dae Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_gold.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ink.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ink.png new file mode 100644 index 0000000000..eaeb520f23 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ink.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_midnight.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_midnight.png new file mode 100644 index 0000000000..2306dedbae Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_midnight.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_neon.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_neon.png new file mode 100644 index 0000000000..4df11eebc6 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_neon.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ocean.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ocean.png new file mode 100644 index 0000000000..c8dbfc2268 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_ocean.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_retro.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_retro.png new file mode 100644 index 0000000000..5d5df05002 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_retro.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_scenic.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_scenic.png new file mode 100644 index 0000000000..f4d5a29fd6 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_scenic.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sunset.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sunset.png new file mode 100644 index 0000000000..59da4da3d8 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground_sunset.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_blossom.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_blossom.png new file mode 100644 index 0000000000..a51e3a1633 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_blossom.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_forest.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_forest.png new file mode 100644 index 0000000000..3b07fd267d Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_forest.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_gold.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_gold.png new file mode 100644 index 0000000000..e1fccb25dc Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_gold.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ink.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ink.png new file mode 100644 index 0000000000..854f9da310 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ink.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_midnight.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_midnight.png new file mode 100644 index 0000000000..eae6ece5fa Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_midnight.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_neon.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_neon.png new file mode 100644 index 0000000000..3e71232a9d Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_neon.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ocean.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ocean.png new file mode 100644 index 0000000000..d86e2ad5d9 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_ocean.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_retro.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_retro.png new file mode 100644 index 0000000000..5e5e9b3d2b Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_retro.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_scenic.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_scenic.png new file mode 100644 index 0000000000..fb3d05f895 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_scenic.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sunset.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sunset.png new file mode 100644 index 0000000000..30a691a81d Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_sunset.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_blossom.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_blossom.png new file mode 100644 index 0000000000..4b97104fad Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_blossom.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_forest.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_forest.png new file mode 100644 index 0000000000..953ac078f3 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_forest.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_gold.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_gold.png new file mode 100644 index 0000000000..4cbc320038 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_gold.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ink.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ink.png new file mode 100644 index 0000000000..75b2e90983 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ink.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_midnight.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_midnight.png new file mode 100644 index 0000000000..be19d6313b Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_midnight.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_neon.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_neon.png new file mode 100644 index 0000000000..f5a0c34557 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_neon.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ocean.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ocean.png new file mode 100644 index 0000000000..ba18f83d01 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_ocean.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_retro.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_retro.png new file mode 100644 index 0000000000..ce2ba91940 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_retro.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_scenic.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_scenic.png new file mode 100644 index 0000000000..5c83fd0135 Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_scenic.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sunset.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sunset.png new file mode 100644 index 0000000000..088fd93f1f Binary files /dev/null and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground_sunset.png differ diff --git a/mobile/android/app/src/main/res/values/app_icon_colors.xml b/mobile/android/app/src/main/res/values/app_icon_colors.xml index 5de795bb4a..6b6f6fdf6b 100644 --- a/mobile/android/app/src/main/res/values/app_icon_colors.xml +++ b/mobile/android/app/src/main/res/values/app_icon_colors.xml @@ -1,11 +1,8 @@ - #0F172A + #FFFFFF + #FFFFFF #FFFFFF - #1E1B4B #FFFFFF - #FFF1F2 #FFFFFF - #0A0A12 - #1C1917 diff --git a/mobile/assets/app-icons/app-icon-blossom.png b/mobile/assets/app-icons/app-icon-blossom.png new file mode 100644 index 0000000000..78c9cb7015 Binary files /dev/null and b/mobile/assets/app-icons/app-icon-blossom.png differ diff --git a/mobile/assets/app-icons/app-icon-blossom.svg b/mobile/assets/app-icons/app-icon-blossom.svg deleted file mode 100644 index 430bf7ae40..0000000000 --- a/mobile/assets/app-icons/app-icon-blossom.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-classic.png b/mobile/assets/app-icons/app-icon-classic.png new file mode 100644 index 0000000000..adc4d0e40c Binary files /dev/null and b/mobile/assets/app-icons/app-icon-classic.png differ diff --git a/mobile/assets/app-icons/app-icon-classic.svg b/mobile/assets/app-icons/app-icon-classic.svg deleted file mode 100644 index 1522e1f348..0000000000 --- a/mobile/assets/app-icons/app-icon-classic.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-forest.png b/mobile/assets/app-icons/app-icon-forest.png new file mode 100644 index 0000000000..4114f7d8ef Binary files /dev/null and b/mobile/assets/app-icons/app-icon-forest.png differ diff --git a/mobile/assets/app-icons/app-icon-forest.svg b/mobile/assets/app-icons/app-icon-forest.svg deleted file mode 100644 index 9ba3659d1c..0000000000 --- a/mobile/assets/app-icons/app-icon-forest.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-gold.png b/mobile/assets/app-icons/app-icon-gold.png new file mode 100644 index 0000000000..1c34cb361f Binary files /dev/null and b/mobile/assets/app-icons/app-icon-gold.png differ diff --git a/mobile/assets/app-icons/app-icon-gold.svg b/mobile/assets/app-icons/app-icon-gold.svg deleted file mode 100644 index 58b297d0d6..0000000000 --- a/mobile/assets/app-icons/app-icon-gold.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-ink.png b/mobile/assets/app-icons/app-icon-ink.png new file mode 100644 index 0000000000..1b0af961e7 Binary files /dev/null and b/mobile/assets/app-icons/app-icon-ink.png differ diff --git a/mobile/assets/app-icons/app-icon-ink.svg b/mobile/assets/app-icons/app-icon-ink.svg deleted file mode 100644 index e25b71fed6..0000000000 --- a/mobile/assets/app-icons/app-icon-ink.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-midnight.png b/mobile/assets/app-icons/app-icon-midnight.png new file mode 100644 index 0000000000..da7f1fc4b9 Binary files /dev/null and b/mobile/assets/app-icons/app-icon-midnight.png differ diff --git a/mobile/assets/app-icons/app-icon-midnight.svg b/mobile/assets/app-icons/app-icon-midnight.svg deleted file mode 100644 index 32477fabc9..0000000000 --- a/mobile/assets/app-icons/app-icon-midnight.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-neon.png b/mobile/assets/app-icons/app-icon-neon.png new file mode 100644 index 0000000000..56cff75181 Binary files /dev/null and b/mobile/assets/app-icons/app-icon-neon.png differ diff --git a/mobile/assets/app-icons/app-icon-neon.svg b/mobile/assets/app-icons/app-icon-neon.svg deleted file mode 100644 index 5515def8b4..0000000000 --- a/mobile/assets/app-icons/app-icon-neon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-ocean.png b/mobile/assets/app-icons/app-icon-ocean.png new file mode 100644 index 0000000000..f76ddb92d4 Binary files /dev/null and b/mobile/assets/app-icons/app-icon-ocean.png differ diff --git a/mobile/assets/app-icons/app-icon-ocean.svg b/mobile/assets/app-icons/app-icon-ocean.svg deleted file mode 100644 index 53967c027e..0000000000 --- a/mobile/assets/app-icons/app-icon-ocean.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/assets/app-icons/app-icon-retro.png b/mobile/assets/app-icons/app-icon-retro.png new file mode 100644 index 0000000000..836ec5396d Binary files /dev/null and b/mobile/assets/app-icons/app-icon-retro.png differ diff --git a/mobile/assets/app-icons/app-icon-scenic.png b/mobile/assets/app-icons/app-icon-scenic.png new file mode 100644 index 0000000000..e37f190eee Binary files /dev/null and b/mobile/assets/app-icons/app-icon-scenic.png differ diff --git a/mobile/assets/app-icons/app-icon-sunset.png b/mobile/assets/app-icons/app-icon-sunset.png new file mode 100644 index 0000000000..a2d7ea111a Binary files /dev/null and b/mobile/assets/app-icons/app-icon-sunset.png differ diff --git a/mobile/assets/app-icons/app-icon-sunset.svg b/mobile/assets/app-icons/app-icon-sunset.svg deleted file mode 100644 index 08af89d78d..0000000000 --- a/mobile/assets/app-icons/app-icon-sunset.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconBlossom.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconBlossom.appiconset/1024.png index 3284a462ed..f714530ffd 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconBlossom.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconBlossom.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconForest.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconForest.appiconset/1024.png index 14a58f905a..0458043638 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconForest.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconForest.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconGold.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconGold.appiconset/1024.png index 77f3d92f01..e281e0dfd1 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconGold.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconGold.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconInk.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconInk.appiconset/1024.png index fb5326fc00..940288ae4d 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconInk.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconInk.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconMidnight.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconMidnight.appiconset/1024.png index 39898a6751..b7a738edaf 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconMidnight.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconMidnight.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconNeon.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconNeon.appiconset/1024.png index e1468ee621..7e8a79463a 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconNeon.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconNeon.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconOcean.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconOcean.appiconset/1024.png index 6f46bafb40..56662fad60 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconOcean.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconOcean.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/1024.png new file mode 100644 index 0000000000..15be678ffc Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/Contents.json new file mode 100644 index 0000000000..7afd6df765 --- /dev/null +++ b/mobile/ios/Runner/Assets.xcassets/AppIconRetro.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images": [ + { + "filename": "1024.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/1024.png new file mode 100644 index 0000000000..c0e068fac7 Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/Contents.json new file mode 100644 index 0000000000..7afd6df765 --- /dev/null +++ b/mobile/ios/Runner/Assets.xcassets/AppIconScenic.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images": [ + { + "filename": "1024.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/mobile/ios/Runner/Assets.xcassets/AppIconSunset.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIconSunset.appiconset/1024.png index 07cc6dc417..80c74391dc 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIconSunset.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIconSunset.appiconset/1024.png differ diff --git a/mobile/lib/constants/app_icons.dart b/mobile/lib/constants/app_icons.dart index 8d10664167..4df1e555ff 100644 --- a/mobile/lib/constants/app_icons.dart +++ b/mobile/lib/constants/app_icons.dart @@ -3,6 +3,8 @@ /// alternate icon asset names), so renaming a value is a breaking change. enum AppIconVariant { classic, + retro, + scenic, midnight, ocean, sunset, @@ -12,7 +14,7 @@ enum AppIconVariant { neon, gold; - String get assetPath => 'assets/app-icons/app-icon-$name.svg'; + String get assetPath => 'assets/app-icons/app-icon-$name.png'; String get translationKey => 'app_icon_$name'; diff --git a/mobile/lib/widgets/settings/preference_settings/app_icon_setting.dart b/mobile/lib/widgets/settings/preference_settings/app_icon_setting.dart index 55f6e3b62a..01f9c84f9f 100644 --- a/mobile/lib/widgets/settings/preference_settings/app_icon_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/app_icon_setting.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/app_icons.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; @@ -108,7 +107,7 @@ class _AppIconTile extends StatelessWidget { ), child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(13)), - child: SvgPicture.asset(variant.assetPath, width: 64, height: 64), + child: Image.asset(variant.assetPath, width: 64, height: 64), ), ), if (isSelected) diff --git a/mobile/scripts/generate_app_icons.py b/mobile/scripts/generate_app_icons.py index f8cd8f46d7..b24e391280 100644 --- a/mobile/scripts/generate_app_icons.py +++ b/mobile/scripts/generate_app_icons.py @@ -1,14 +1,28 @@ #!/usr/bin/env python3 """Generates the alternate app icon assets for Android and iOS. -Recolors the five petals of the Immich logo for each icon variant and emits: - - assets/app-icons/app-icon-.svg (in-app previews) - - android res: drawable/ic_launcher_foreground_.xml, - mipmap-anydpi-v26/ic_launcher_.xml, - values/app_icon_colors.xml +Variant families: + - gradient: the five petals of the Immich logo dressed in a center-out + radial gradient (bright cores fading to deep tips on light grounds, dark + bases flaring to glowing tips on dark grounds) with a soft drop shadow + under every petal, over a flat or gradient background. + - retro: a pixel-art take on the flower, after the "Retro Magnet" from + immich.store (jagged pixel petals with darker pixel outlines). + - scenic: a tiny landscape painted inside each petal, after the + "Landscape Logo Magnet" from immich.store (sunset mountains, dusk + skyline, desert dunes, moonlit ocean, misty pines). + +Because neither Android vector drawables nor flutter_svg can render blur +filters, everything the shadows touch ships as rendered PNGs. Emits: + + - assets/app-icons/app-icon-.png (in-app previews) + - android res: mipmap-/ic_launcher_foreground_.png, + drawable/ic_launcher_bg_.xml (gradient grounds), + values/app_icon_colors.xml (flat grounds), + mipmap-anydpi-v26/ic_launcher_.xml - ios: Assets.xcassets/AppIcon.appiconset/{Contents.json,1024.png} -The iOS PNGs are rendered with macOS `qlmanage`, so this script must run on +The PNGs are rendered with macOS `qlmanage`, so this script must run on macOS. Run it from anywhere: `python3 mobile/scripts/generate_app_icons.py`. """ @@ -28,90 +42,158 @@ MOBILE = Path(__file__).resolve().parent.parent # top (red), upper-left (pink), upper-right (yellow), # lower-left (blue), lower-right (green) BASE_PETALS = ["#FA2921", "#ED79B5", "#FFB400", "#1E83F7", "#18C249"] -BASE_BACKGROUND = "#FFFFFF" -# id -> (asset suffix, background, petal colors in BASE_PETALS order). -# "classic" is the default icon and only gets a preview SVG; its native -# assets are the stock ic_launcher / AppIcon. +# The flower fills the logo's 192-unit viewBox; icons inset it to 78% (the +# padding of the original iOS icon) and the Android 108dp adaptive +# foreground to 27.55% (the geometry of the stock ic_launcher_foreground). +LOGO = 192 +ICON_SCALE = 0.78 +DROID_CANVAS = 108 +DROID_SCALE = 0.2755 + +# Petal pixels only exist beyond the flower's hollow core, so the first +# radial stop sits partway out to keep the visible ramp full-range. +INNER_STOP = 0.18 +SHADOW = '' + +# Adaptive icon foreground densities (108dp layer). +DENSITIES = {"mdpi": 108, "hdpi": 162, "xhdpi": 216, "xxhdpi": 324, "xxxhdpi": 432} + +# Backgrounds: ("solid", color) | ("linear", start, end) diagonal top-left -> +# bottom-right | ("vertical", top, bottom) | ("radial", center, edge). +# Petals: five (inner, outer) gradient stop pairs in BASE_PETALS order. VARIANTS = { - "classic": (BASE_BACKGROUND, BASE_PETALS), - "midnight": ("#0F172A", BASE_PETALS), - "ocean": ("#FFFFFF", ["#0284C7", "#38BDF8", "#1D4ED8", "#0891B2", "#14B8A6"]), - "sunset": ("#1E1B4B", ["#F97316", "#7C3AED", "#FACC15", "#C026D3", "#F43F5E"]), - "forest": ("#FFFFFF", ["#16A34A", "#84CC16", "#4ADE80", "#15803D", "#65A30D"]), - "blossom": ("#FFF1F2", ["#E11D48", "#FB7185", "#F472B6", "#BE185D", "#F9A8D4"]), - "ink": ("#FFFFFF", ["#111827", "#6B7280", "#374151", "#9CA3AF", "#4B5563"]), - "neon": ("#0A0A12", ["#FF2D95", "#00E5FF", "#FFD600", "#7C4DFF", "#00FF9D"]), - "gold": ("#1C1917", ["#FBBF24", "#FDE68A", "#F59E0B", "#D97706", "#FCD34D"]), + "classic": { + "bg": ("solid", "#FFFFFF"), + "petals": [(c, c) for c in BASE_PETALS], # the untouched default + "shadow": 0, + }, + "retro": {"bg": ("solid", "#FFFFFF"), "kind": "retro", "shadow": 0}, + "scenic": {"bg": ("solid", "#FFFFFF"), "kind": "scenic", "shadow": 0.22}, + "midnight": { + "bg": ("linear", "#1B2A4A", "#0A0F1E"), + "petals": [ + ("#B3170A", "#FF6A4D"), + ("#C2408D", "#FF9DD6"), + ("#C77F00", "#FFD54D"), + ("#0F5BD1", "#5CB2FF"), + ("#0E8A33", "#4DE87A"), + ], + }, + "ocean": { + "bg": ("solid", "#FFFFFF"), + "petals": [ + ("#7DD3FC", "#0369A1"), + ("#A5F3FC", "#0891B2"), + ("#93C5FD", "#1D4ED8"), + ("#67E8F9", "#155E75"), + ("#5EEAD4", "#0F766E"), + ], + }, + "sunset": { + "bg": ("vertical", "#3B1D6E", "#150A38"), + "petals": [ + ("#C2410C", "#FDBA74"), + ("#6D28D9", "#C4B5FD"), + ("#A16207", "#FDE047"), + ("#A21CAF", "#F0ABFC"), + ("#BE123C", "#FDA4AF"), + ], + }, + "forest": { + "bg": ("solid", "#FFFFFF"), + "petals": [ + ("#86EFAC", "#15803D"), + ("#D9F99D", "#4D7C0F"), + ("#6EE7B7", "#047857"), + ("#BBF7D0", "#166534"), + ("#BEF264", "#3F6212"), + ], + }, + "blossom": { + "bg": ("vertical", "#FFF1F2", "#FECDD3"), + "petals": [ + ("#FDA4AF", "#BE123C"), + ("#FBCFE8", "#DB2777"), + ("#F9A8D4", "#9D174D"), + ("#FECDD3", "#E11D48"), + ("#F5D0FE", "#A21CAF"), + ], + }, + "ink": { + "bg": ("solid", "#FFFFFF"), + "petals": [ + ("#94A3B8", "#0F172A"), + ("#CBD5E1", "#475569"), + ("#B0BCCC", "#1E293B"), + ("#E2E8F0", "#64748B"), + ("#9AA6B8", "#334155"), + ], + }, + "neon": { + "bg": ("radial", "#1A1033", "#050208"), + "petals": [ + ("#B3005E", "#FF4DA6"), + ("#0090B3", "#33F0FF"), + ("#B39B00", "#FFF04D"), + ("#6600CC", "#B266FF"), + ("#00B36B", "#4DFFB8"), + ], + }, + "gold": { + "bg": ("linear", "#2B2118", "#141009"), + "petals": [ + ("#92600A", "#FFD966"), + ("#B8860B", "#FFF0B3"), + ("#A5680A", "#FFC933"), + ("#7A4E06", "#E6A817"), + ("#9C6F0C", "#FFE080"), + ], + }, } -def recolor(text: str, petals: list[str]) -> str: - for base, new in zip(BASE_PETALS, petals): - pattern = re.compile(re.escape(base), re.IGNORECASE) - text = pattern.sub(new, text) - return text +def is_dark(color: str) -> bool: + r, g, b = (int(color[i : i + 2], 16) for i in (1, 3, 5)) + return 0.299 * r + 0.587 * g + 0.114 * b < 128 -def petal_paths() -> str: +def darken(color: str, factor: float) -> str: + r, g, b = (int(color[i : i + 2], 16) for i in (1, 3, 5)) + return f"#{int(r * factor):02X}{int(g * factor):02X}{int(b * factor):02X}" + + +def petal_path_data() -> list[str]: svg = (MOBILE / "assets" / "immich-logo.svg").read_text() - return "\n".join(re.findall(r"]*/>", svg)) + return re.findall(r' str: - # The flower spans the full 192px viewBox; scale it down so the icon - # keeps the same padding as the original iOS app icon. - scale = 0.78 - offset = 192 * (1 - scale) / 2 - paths = recolor(petal_paths(), petals) - return f""" - - -{paths} - - -""" +# --------------------------------------------------------------------------- +# PNG helpers (qlmanage rendering + minimal decode/encode) +# --------------------------------------------------------------------------- -def write_previews() -> None: - out = MOBILE / "assets" / "app-icons" - out.mkdir(exist_ok=True) - for variant, (background, petals) in VARIANTS.items(): - (out / f"app-icon-{variant}.svg").write_text(icon_svg(background, petals, 192)) - print(f"previews: {out}") - - -def write_android() -> None: - res = MOBILE / "android" / "app" / "src" / "main" / "res" - foreground = (res / "drawable" / "ic_launcher_foreground.xml").read_text() - - colors = ['', ""] - for variant, (background, petals) in VARIANTS.items(): - if variant == "classic": - continue - (res / "drawable" / f"ic_launcher_foreground_{variant}.xml").write_text( - recolor(foreground, petals) +def render_svg(svg_text: str, size: int) -> bytes: + """Renders an SVG (whose root width/height should equal size) to PNG.""" + with tempfile.TemporaryDirectory() as tmp_dir: + svg = Path(tmp_dir) / "render.svg" + svg.write_text(svg_text) + subprocess.run( + ["qlmanage", "-t", "-s", str(size), "-o", tmp_dir, str(svg)], + check=True, + capture_output=True, ) - colors.append(f' {background}') - (res / "mipmap-anydpi-v26" / f"ic_launcher_{variant}.xml").write_text( - f""" - - - - - -""" - ) - colors.append("") - (res / "values" / "app_icon_colors.xml").write_text("\n".join(colors) + "\n") - print(f"android res: {res}") + rendered = Path(tmp_dir) / "render.svg.png" + if not rendered.exists(): + sys.exit("qlmanage failed to render SVG") + return rendered.read_bytes() -def strip_alpha(png: bytes) -> bytes: - """Re-encodes an RGBA PNG as opaque RGB (required for app icons).""" +def decode_png(png: bytes) -> tuple[int, int, list[bytearray]]: + """Decodes an 8-bit RGB(A) PNG into rows of RGBA bytes.""" assert png[:8] == b"\x89PNG\r\n\x1a\n" - pos, chunks, idat = 8, [], b"" - width = height = bit_depth = color_type = None + pos, idat = 8, b"" + width = height = color_type = None while pos < len(png): (length,) = struct.unpack(">I", png[pos : pos + 4]) kind = png[pos + 4 : pos + 8] @@ -119,25 +201,22 @@ def strip_alpha(png: bytes) -> bytes: pos += 12 + length if kind == b"IHDR": width, height, bit_depth, color_type = struct.unpack(">IIBB", data[:10]) + assert bit_depth == 8 and color_type in (2, 6), "expected 8-bit RGB(A)" if kind == b"IDAT": idat += data - else: - chunks.append((kind, data)) - if color_type != 6 or bit_depth != 8: - return png # already opaque - + channels = 4 if color_type == 6 else 3 raw = zlib.decompress(idat) - stride = width * 4 - rgb = bytearray() - previous = bytearray(width * 4) + stride = width * channels + rows = [] + previous = bytearray(stride) for y in range(height): row_start = y * (stride + 1) filter_type = raw[row_start] row = bytearray(raw[row_start + 1 : row_start + 1 + stride]) for x in range(stride): - a = row[x - 4] if x >= 4 else 0 + a = row[x - channels] if x >= channels else 0 b = previous[x] - c = previous[x - 4] if x >= 4 else 0 + c = previous[x - channels] if x >= channels else 0 if filter_type == 1: row[x] = (row[x] + a) & 0xFF elif filter_type == 2: @@ -150,10 +229,20 @@ def strip_alpha(png: bytes) -> bytes: pred = a if pa <= pb and pa <= pc else b if pb <= pc else c row[x] = (row[x] + pred) & 0xFF previous = row + if channels == 3: + rows.append(bytearray(b"".join(row[x * 3 : x * 3 + 3] + b"\xff" for x in range(width)))) + else: + rows.append(row) + return width, height, rows + + +def encode_png_rgb(width: int, height: int, rows: list[bytearray]) -> bytes: + """Encodes RGBA rows as an opaque RGB PNG (app icons must have no alpha).""" + rgb = bytearray() + for row in rows: rgb.append(0) for x in range(width): rgb += row[x * 4 : x * 4 + 3] - out = bytearray(b"\x89PNG\r\n\x1a\n") def chunk(kind: bytes, data: bytes) -> None: @@ -168,45 +257,336 @@ def strip_alpha(png: bytes) -> bytes: return bytes(out) +def strip_alpha(png: bytes) -> bytes: + width, height, rows = decode_png(png) + return encode_png_rgb(width, height, rows) + + +# --------------------------------------------------------------------------- +# Flower bodies (drawn in the logo's 192-unit space) +# --------------------------------------------------------------------------- + + +def gradient_body(variant: dict) -> tuple[str, str]: + """Returns (defs, body) for a gradient/flat petal flower.""" + defs, paths = [], [] + shadow = variant.get("shadow", 0.28 if not is_dark(variant["bg"][1]) else 0.5) + if shadow: + defs.append(SHADOW.format(opacity=shadow)) + shadow_attr = ' filter="url(#ps)"' if shadow else "" + for index, (data, (inner, outer)) in enumerate(zip(petal_path_data(), variant["petals"])): + if inner == outer: + fill = inner + else: + fill = f"url(#p{index})" + defs.append( + f'' + f'' + f'' + f"" + ) + paths.append(f'') + return "".join(defs), "\n".join(paths) + + +def retro_body(grid: int = 30) -> tuple[str, str]: + """Pixel-art flower: sample the logo on a coarse grid, outline the edges.""" + scale = 10 + # Render over a magenta chroma key: qlmanage does not reliably preserve + # alpha, so background cells are detected by color instead. + key = "#FF00FF" + paths = "\n".join(f'' for d, c in zip(petal_path_data(), BASE_PETALS)) + svg = ( + f'' + f'{paths}' + ) + width, height, rows = decode_png(render_svg(svg, grid * scale)) + assert width == height == grid * scale + + targets = [tuple(int(c[i : i + 2], 16) for i in (1, 3, 5)) for c in BASE_PETALS + [key]] + + def classify(gx: int, gy: int) -> int | None: + px = (gx * scale + scale // 2) * 4 + row = rows[gy * scale + scale // 2] + r, g, b, a = row[px : px + 4] + if a < 128: + return None + distances = [(r - t[0]) ** 2 + (g - t[1]) ** 2 + (b - t[2]) ** 2 for t in targets] + nearest = distances.index(min(distances)) + # Anti-aliased blends between petals match nothing well; drop them so + # the petals stay separated like the magnet art. + if nearest == 5 or distances[nearest] > 4000: + return None + return nearest + + cells = [[classify(x, y) for x in range(grid)] for y in range(grid)] + cell_size = LOGO / grid + + def cell_color(x: int, y: int) -> str | None: + petal = cells[y][x] + if petal is None: + return None + edge = any( + nx < 0 or ny < 0 or nx >= grid or ny >= grid or cells[ny][nx] != petal + for nx, ny in ((x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)) + ) + return darken(BASE_PETALS[petal], 0.6) if edge else BASE_PETALS[petal] + + # Merge horizontal runs of the same color into one rect (with a slight + # vertical overlap) so no hairline seams show between cells. + rects = [] + for y in range(grid): + x = 0 + while x < grid: + color = cell_color(x, y) + if color is None: + x += 1 + continue + run = x + while run < grid and cell_color(run, y) == color: + run += 1 + rects.append( + f'' + ) + x = run + return "", "\n".join(rects) + + +def scenic_body(shadow: float) -> tuple[str, str]: + """A miniature landscape clipped inside each petal, after the store magnet.""" + + def sky(name: str, top: str, bottom: str, y1: float, y2: float) -> str: + return ( + f'' + f'' + ) + + defs = [SHADOW.format(opacity=shadow) if shadow else ""] + defs += [ + sky("sky-peak", "#FFB35C", "#E8402B", 3, 93), + sky("sky-city", "#F7C9DE", "#D9679F", 34, 120), + sky("sky-dune", "#FFE99A", "#F0AE3C", 33, 123), + sky("sky-sea", "#4A6DB5", "#1D3160", 77, 190), + sky("sky-pine", "#A8D8B4", "#1F5C3D", 119, 190), + ] + for index, data in enumerate(petal_path_data()): + defs.append(f'') + + scenes = [ + # top petal: sunset over mountains + """ + + +""", + # upper-left petal: city skyline at dusk + """ + + +""", + # upper-right petal: desert dunes + """ + + +""", + # lower-left petal: moonlit sea + """ + + + +""", + # lower-right petal: misty pines + """ + + +""", + ] + + shadow_attr = ' filter="url(#ps)"' if shadow else "" + body = [] + for index, scene in enumerate(scenes): + body.append(f'\n{scene}\n') + return "".join(defs), "\n".join(body) + + +def flower_body(variant: dict) -> tuple[str, str]: + kind = variant.get("kind", "gradient") + if kind == "retro": + return retro_body() + if kind == "scenic": + return scenic_body(variant.get("shadow", 0.22)) + return gradient_body(variant) + + +# --------------------------------------------------------------------------- +# Canvas assembly +# --------------------------------------------------------------------------- + + +def bg_svg(bg: tuple) -> tuple[str, str]: + """Returns (defs snippet, fill ref) for the icon background.""" + kind = bg[0] + if kind == "solid": + return "", bg[1] + if kind == "radial": + defs = ( + f'' + f'' + f"" + ) + else: + x2, y2 = ("192", "192") if kind == "linear" else ("0", "192") + defs = ( + f'' + f'' + f"" + ) + return defs, "url(#bg)" + + +def icon_svg(variant: dict, size: int) -> str: + """Full square icon: background + inset flower.""" + offset = LOGO * (1 - ICON_SCALE) / 2 + bg_defs, bg_fill = bg_svg(variant["bg"]) + defs, body = flower_body(variant) + return f""" +{bg_defs}{defs} + + +{body} + + +""" + + +def foreground_svg(variant: dict, size: int) -> str: + """Android adaptive-icon foreground layer (transparent, 108dp geometry).""" + offset = (DROID_CANVAS - LOGO * DROID_SCALE) / 2 + defs, body = flower_body(variant) + return f""" +{defs} + +{body} + + +""" + + +# --------------------------------------------------------------------------- +# Outputs +# --------------------------------------------------------------------------- + + +def write_previews() -> None: + out = MOBILE / "assets" / "app-icons" + out.mkdir(exist_ok=True) + for stale in out.glob("app-icon-*.svg"): + stale.unlink() + for variant_id, variant in VARIANTS.items(): + (out / f"app-icon-{variant_id}.png").write_bytes(render_svg(icon_svg(variant, 384), 384)) + print(f"previews: {out}") + + +def android_bg_gradient(bg: tuple) -> str: + if bg[0] == "radial": + geometry = 'android:type="radial" android:centerX="54" android:centerY="54" android:gradientRadius="77"' + elif bg[0] == "vertical": + geometry = 'android:type="linear" android:startX="0" android:startY="0" android:endX="0" android:endY="108"' + else: + geometry = 'android:type="linear" android:startX="0" android:startY="0" android:endX="108" android:endY="108"' + return f""" + + + + + + + + + + +""" + + +def write_android() -> None: + res = MOBILE / "android" / "app" / "src" / "main" / "res" + for stale in (res / "drawable").glob("ic_launcher_foreground_*.xml"): + stale.unlink() + colors = ['', ""] + for variant_id, variant in VARIANTS.items(): + if variant_id == "classic": + continue + + base = render_svg(foreground_svg(variant, DENSITIES["xxxhdpi"]), DENSITIES["xxxhdpi"]) + with tempfile.TemporaryDirectory() as tmp_dir: + base_png = Path(tmp_dir) / "fg.png" + base_png.write_bytes(base) + for density, pixels in DENSITIES.items(): + target = res / f"mipmap-{density}" / f"ic_launcher_foreground_{variant_id}.png" + if pixels == DENSITIES["xxxhdpi"]: + target.write_bytes(base) + else: + subprocess.run( + ["sips", "-z", str(pixels), str(pixels), str(base_png), "--out", str(target)], + check=True, + capture_output=True, + ) + + bg = variant["bg"] + if bg[0] == "solid": + colors.append(f' {bg[1]}') + background_ref = f"@color/ic_launcher_background_{variant_id}" + (res / "drawable" / f"ic_launcher_bg_{variant_id}.xml").unlink(missing_ok=True) + else: + (res / "drawable" / f"ic_launcher_bg_{variant_id}.xml").write_text(android_bg_gradient(bg)) + background_ref = f"@drawable/ic_launcher_bg_{variant_id}" + + (res / "mipmap-anydpi-v26" / f"ic_launcher_{variant_id}.xml").write_text( + f""" + + + + + +""" + ) + colors.append("") + (res / "values" / "app_icon_colors.xml").write_text("\n".join(colors) + "\n") + print(f"android res: {res}") + + def write_ios() -> None: xcassets = MOBILE / "ios" / "Runner" / "Assets.xcassets" - with tempfile.TemporaryDirectory() as tmp_dir: - tmp = Path(tmp_dir) - for variant, (background, petals) in VARIANTS.items(): - if variant == "classic": - continue - svg = tmp / f"{variant}.svg" - svg.write_text(icon_svg(background, petals, 1024)) - subprocess.run( - ["qlmanage", "-t", "-s", "1024", "-o", tmp_dir, str(svg)], - check=True, - capture_output=True, - ) - rendered = tmp / f"{variant}.svg.png" - if not rendered.exists(): - sys.exit(f"qlmanage failed to render {svg}") - - iconset = xcassets / f"AppIcon{variant.capitalize()}.appiconset" - shutil.rmtree(iconset, ignore_errors=True) - iconset.mkdir() - (iconset / "1024.png").write_bytes(strip_alpha(rendered.read_bytes())) - (iconset / "Contents.json").write_text( - json.dumps( - { - "images": [ - { - "filename": "1024.png", - "idiom": "universal", - "platform": "ios", - "size": "1024x1024", - } - ], - "info": {"author": "xcode", "version": 1}, - }, - indent=2, - ) - + "\n" + for variant_id, variant in VARIANTS.items(): + if variant_id == "classic": + continue + iconset = xcassets / f"AppIcon{variant_id.capitalize()}.appiconset" + shutil.rmtree(iconset, ignore_errors=True) + iconset.mkdir() + (iconset / "1024.png").write_bytes(strip_alpha(render_svg(icon_svg(variant, 1024), 1024))) + (iconset / "Contents.json").write_text( + json.dumps( + { + "images": [ + { + "filename": "1024.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024", + } + ], + "info": {"author": "xcode", "version": 1}, + }, + indent=2, ) + + "\n" + ) print(f"ios appiconsets: {xcassets}")