diff --git a/.github/workflows/linux-packages.yml b/.github/workflows/linux-packages.yml index 1fa6f28..ec30fbc 100644 --- a/.github/workflows/linux-packages.yml +++ b/.github/workflows/linux-packages.yml @@ -69,6 +69,8 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 + with: + gradle-home-cache-strict-match: true - name: Set up Rust 1.91 uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1 @@ -172,6 +174,8 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 + with: + gradle-home-cache-strict-match: true - name: Set up Rust 1.91 uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1 diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_add.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_add.xml new file mode 100644 index 0000000..61b2c48 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_add.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_arrow_back.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_arrow_back.xml new file mode 100644 index 0000000..c10a4c8 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_arrow_back.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_bell.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_bell.xml new file mode 100644 index 0000000..1cba642 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_bell.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_bug.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_bug.xml new file mode 100644 index 0000000..e060d64 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_bug.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_check.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_check.xml new file mode 100644 index 0000000..e1f16f1 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_check.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_chevron_right.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_chevron_right.xml new file mode 100644 index 0000000..04eca79 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_chevron_right.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_close.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_close.xml new file mode 100644 index 0000000..22e27a4 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_close.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_cloud_off.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_cloud_off.xml new file mode 100644 index 0000000..b824bc6 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_cloud_off.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_code.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_code.xml new file mode 100644 index 0000000..dcaff89 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_code.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_delete.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_delete.xml new file mode 100644 index 0000000..b1c5e2d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_delete.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_document.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_document.xml new file mode 100644 index 0000000..c736b25 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_document.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_download.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_download.xml new file mode 100644 index 0000000..8562fe6 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_download.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_file.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_file.xml new file mode 100644 index 0000000..c736b25 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_file.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_folder.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_folder.xml new file mode 100644 index 0000000..fa1259b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_folder.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_globe.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_globe.xml new file mode 100644 index 0000000..bcac5e0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_globe.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_hand.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_hand.xml new file mode 100644 index 0000000..e3fd4dc --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_hand.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_info.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_info.xml new file mode 100644 index 0000000..9b956e0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_info.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_lock.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_lock.xml new file mode 100644 index 0000000..091b21a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_lock.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_megaphone.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_megaphone.xml new file mode 100644 index 0000000..4dac2e2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_megaphone.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_moon.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_moon.xml new file mode 100644 index 0000000..1cca55f --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_moon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_nfc.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_nfc.xml new file mode 100644 index 0000000..ae9b0d5 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_nfc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_qr_code.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_qr_code.xml new file mode 100644 index 0000000..9b46d9f --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_qr_code.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_radio.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_radio.xml new file mode 100644 index 0000000..9ac616d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_radio.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_scan.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_scan.xml new file mode 100644 index 0000000..c92ee7e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_scan.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_send.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_send.xml new file mode 100644 index 0000000..769733a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_send.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_settings.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_settings.xml new file mode 100644 index 0000000..f8fd090 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_settings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_shield.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_shield.xml new file mode 100644 index 0000000..ca3fbc0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_shield.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_shield_check.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_shield_check.xml new file mode 100644 index 0000000..3c32152 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_shield_check.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_storage.xml new file mode 100644 index 0000000..23ba7a7 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_storage.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_sun.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_sun.xml new file mode 100644 index 0000000..1cca505 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_sun.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_sync.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_sync.xml new file mode 100644 index 0000000..1b90650 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_sync.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_system_theme.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_system_theme.xml new file mode 100644 index 0000000..d209553 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_system_theme.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_temporary.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_temporary.xml new file mode 100644 index 0000000..44dd937 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_temporary.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_total_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_total_storage.xml new file mode 100644 index 0000000..ecf52bf --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_total_storage.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_transfer_data.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_transfer_data.xml new file mode 100644 index 0000000..addbb87 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_transfer_data.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_user.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_user.xml new file mode 100644 index 0000000..5b39e0b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_user.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_fluent_user_off.xml b/shared/src/commonMain/composeResources/drawable/icon_fluent_user_off.xml new file mode 100644 index 0000000..317e5b0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_fluent_user_off.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_add.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_add.xml new file mode 100644 index 0000000..0c6f7be --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_add.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_arrow_back.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_arrow_back.xml new file mode 100644 index 0000000..1dd2b59 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_arrow_back.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_bell.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_bell.xml new file mode 100644 index 0000000..89d76b2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_bell.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_bug.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_bug.xml new file mode 100644 index 0000000..e2c2f2e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_bug.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_check.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_check.xml new file mode 100644 index 0000000..707183b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_check.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_chevron_right.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_chevron_right.xml new file mode 100644 index 0000000..a724d1a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_chevron_right.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_close.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_close.xml new file mode 100644 index 0000000..1ab69a9 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_close.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_cloud_off.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_cloud_off.xml new file mode 100644 index 0000000..457645b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_cloud_off.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_code.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_code.xml new file mode 100644 index 0000000..833b065 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_code.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_delete.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_delete.xml new file mode 100644 index 0000000..6f1b771 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_delete.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_document.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_document.xml new file mode 100644 index 0000000..84663f2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_document.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_download.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_download.xml new file mode 100644 index 0000000..f71a77a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_download.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_file.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_file.xml new file mode 100644 index 0000000..67685f8 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_file.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_folder.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_folder.xml new file mode 100644 index 0000000..810dfe9 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_folder.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_globe.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_globe.xml new file mode 100644 index 0000000..24dd351 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_globe.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_hand.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_hand.xml new file mode 100644 index 0000000..c293104 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_hand.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_info.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_info.xml new file mode 100644 index 0000000..1451d17 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_info.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_lock.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_lock.xml new file mode 100644 index 0000000..081de7a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_lock.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_megaphone.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_megaphone.xml new file mode 100644 index 0000000..9a20c21 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_megaphone.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_moon.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_moon.xml new file mode 100644 index 0000000..6c65c9f --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_moon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_nfc.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_nfc.xml new file mode 100644 index 0000000..143c12b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_nfc.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_qr_code.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_qr_code.xml new file mode 100644 index 0000000..8eea8d5 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_qr_code.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_radio.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_radio.xml new file mode 100644 index 0000000..538476b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_radio.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_scan.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_scan.xml new file mode 100644 index 0000000..b9f760c --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_scan.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_send.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_send.xml new file mode 100644 index 0000000..ef14e75 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_send.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_settings.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_settings.xml new file mode 100644 index 0000000..6c8c431 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_settings.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_shield.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_shield.xml new file mode 100644 index 0000000..f526199 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_shield.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_shield_check.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_shield_check.xml new file mode 100644 index 0000000..c232a16 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_shield_check.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_storage.xml new file mode 100644 index 0000000..eaf4c2c --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_storage.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_sun.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_sun.xml new file mode 100644 index 0000000..a5604c2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_sun.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_sync.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_sync.xml new file mode 100644 index 0000000..30f8c32 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_sync.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_system_theme.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_system_theme.xml new file mode 100644 index 0000000..ea91232 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_system_theme.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_temporary.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_temporary.xml new file mode 100644 index 0000000..27dfac7 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_temporary.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_total_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_total_storage.xml new file mode 100644 index 0000000..181b977 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_total_storage.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_transfer_data.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_transfer_data.xml new file mode 100644 index 0000000..da03d38 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_transfer_data.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_user.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_user.xml new file mode 100644 index 0000000..a27914e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_user.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_lucide_user_off.xml b/shared/src/commonMain/composeResources/drawable/icon_lucide_user_off.xml new file mode 100644 index 0000000..014683d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_lucide_user_off.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_add.xml b/shared/src/commonMain/composeResources/drawable/icon_material_add.xml new file mode 100644 index 0000000..8ca5093 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_add.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_arrow_back.xml b/shared/src/commonMain/composeResources/drawable/icon_material_arrow_back.xml new file mode 100644 index 0000000..59d0467 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_arrow_back.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_bell.xml b/shared/src/commonMain/composeResources/drawable/icon_material_bell.xml new file mode 100644 index 0000000..5b216f3 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_bell.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_bug.xml b/shared/src/commonMain/composeResources/drawable/icon_material_bug.xml new file mode 100644 index 0000000..335943b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_bug.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_check.xml b/shared/src/commonMain/composeResources/drawable/icon_material_check.xml new file mode 100644 index 0000000..c2778d2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_check.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_chevron_right.xml b/shared/src/commonMain/composeResources/drawable/icon_material_chevron_right.xml new file mode 100644 index 0000000..9d207e1 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_chevron_right.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_close.xml b/shared/src/commonMain/composeResources/drawable/icon_material_close.xml new file mode 100644 index 0000000..186a472 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_close.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_cloud_off.xml b/shared/src/commonMain/composeResources/drawable/icon_material_cloud_off.xml new file mode 100644 index 0000000..7192332 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_cloud_off.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_code.xml b/shared/src/commonMain/composeResources/drawable/icon_material_code.xml new file mode 100644 index 0000000..a96a122 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_code.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_delete.xml b/shared/src/commonMain/composeResources/drawable/icon_material_delete.xml new file mode 100644 index 0000000..81d832d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_delete.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_document.xml b/shared/src/commonMain/composeResources/drawable/icon_material_document.xml new file mode 100644 index 0000000..f6ad658 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_document.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_download.xml b/shared/src/commonMain/composeResources/drawable/icon_material_download.xml new file mode 100644 index 0000000..4f3c7e2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_download.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_file.xml b/shared/src/commonMain/composeResources/drawable/icon_material_file.xml new file mode 100644 index 0000000..4e8c130 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_file.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_folder.xml b/shared/src/commonMain/composeResources/drawable/icon_material_folder.xml new file mode 100644 index 0000000..93f6cd0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_folder.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_globe.xml b/shared/src/commonMain/composeResources/drawable/icon_material_globe.xml new file mode 100644 index 0000000..6b82b9e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_globe.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_hand.xml b/shared/src/commonMain/composeResources/drawable/icon_material_hand.xml new file mode 100644 index 0000000..85ec083 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_hand.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_info.xml b/shared/src/commonMain/composeResources/drawable/icon_material_info.xml new file mode 100644 index 0000000..f1ed433 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_info.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_lock.xml b/shared/src/commonMain/composeResources/drawable/icon_material_lock.xml new file mode 100644 index 0000000..98bc921 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_lock.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_megaphone.xml b/shared/src/commonMain/composeResources/drawable/icon_material_megaphone.xml new file mode 100644 index 0000000..b795f50 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_megaphone.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_moon.xml b/shared/src/commonMain/composeResources/drawable/icon_material_moon.xml new file mode 100644 index 0000000..aa9e4bd --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_moon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_nfc.xml b/shared/src/commonMain/composeResources/drawable/icon_material_nfc.xml new file mode 100644 index 0000000..a5325e0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_nfc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_qr_code.xml b/shared/src/commonMain/composeResources/drawable/icon_material_qr_code.xml new file mode 100644 index 0000000..402a891 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_qr_code.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_radio.xml b/shared/src/commonMain/composeResources/drawable/icon_material_radio.xml new file mode 100644 index 0000000..e97dd63 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_radio.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_scan.xml b/shared/src/commonMain/composeResources/drawable/icon_material_scan.xml new file mode 100644 index 0000000..e6a56dd --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_scan.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_send.xml b/shared/src/commonMain/composeResources/drawable/icon_material_send.xml new file mode 100644 index 0000000..4ece80a --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_send.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_settings.xml b/shared/src/commonMain/composeResources/drawable/icon_material_settings.xml new file mode 100644 index 0000000..0165abd --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_settings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_shield.xml b/shared/src/commonMain/composeResources/drawable/icon_material_shield.xml new file mode 100644 index 0000000..bece701 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_shield.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_shield_check.xml b/shared/src/commonMain/composeResources/drawable/icon_material_shield_check.xml new file mode 100644 index 0000000..0a4fb51 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_shield_check.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_material_storage.xml new file mode 100644 index 0000000..22211dd --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_storage.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_sun.xml b/shared/src/commonMain/composeResources/drawable/icon_material_sun.xml new file mode 100644 index 0000000..0d05059 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_sun.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_sync.xml b/shared/src/commonMain/composeResources/drawable/icon_material_sync.xml new file mode 100644 index 0000000..046806b --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_sync.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_system_theme.xml b/shared/src/commonMain/composeResources/drawable/icon_material_system_theme.xml new file mode 100644 index 0000000..f75f2f0 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_system_theme.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_temporary.xml b/shared/src/commonMain/composeResources/drawable/icon_material_temporary.xml new file mode 100644 index 0000000..b0b6785 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_temporary.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_total_storage.xml b/shared/src/commonMain/composeResources/drawable/icon_material_total_storage.xml new file mode 100644 index 0000000..0eb972e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_total_storage.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_transfer_data.xml b/shared/src/commonMain/composeResources/drawable/icon_material_transfer_data.xml new file mode 100644 index 0000000..fc32254 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_transfer_data.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_user.xml b/shared/src/commonMain/composeResources/drawable/icon_material_user.xml new file mode 100644 index 0000000..e5dfa98 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_user.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/icon_material_user_off.xml b/shared/src/commonMain/composeResources/drawable/icon_material_user_off.xml new file mode 100644 index 0000000..34bca1f --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/icon_material_user_off.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/files/icon-licenses/fluent-system-icons-mit.txt b/shared/src/commonMain/composeResources/files/icon-licenses/fluent-system-icons-mit.txt new file mode 100644 index 0000000..bc9c36b --- /dev/null +++ b/shared/src/commonMain/composeResources/files/icon-licenses/fluent-system-icons-mit.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/shared/src/commonMain/composeResources/files/icon-licenses/lucide-isc.txt b/shared/src/commonMain/composeResources/files/icon-licenses/lucide-isc.txt new file mode 100644 index 0000000..718bb3f --- /dev/null +++ b/shared/src/commonMain/composeResources/files/icon-licenses/lucide-isc.txt @@ -0,0 +1,43 @@ +ISC License + +Copyright (c) 2026 Lucide Icons and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +--- + +The following Lucide icons are derived from the Feather project: + +airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out + +The MIT License (MIT) (for the icons listed above) + +Copyright (c) 2013-present Cole Bemis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/shared/src/commonMain/composeResources/files/icon-licenses/material-symbols-apache-2.0.txt b/shared/src/commonMain/composeResources/files/icon-licenses/material-symbols-apache-2.0.txt new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/shared/src/commonMain/composeResources/files/icon-licenses/material-symbols-apache-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/approvals/ApprovalModalHost.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/approvals/ApprovalModalHost.kt index 4d097f1..182e7e5 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/approvals/ApprovalModalHost.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/approvals/ApprovalModalHost.kt @@ -12,21 +12,20 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.path import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.SecondaryButton +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -66,8 +65,8 @@ fun ApprovalModalHost( ) { Column(Modifier.padding(24.dp), verticalArrangement = Arrangement.spacedBy(14.dp)) { Surface(shape = RoundedCornerShape(14.dp), color = colors.backgroundSelection) { - Icon( - ApprovalIcon, + PlatformIcon( + AppIcon.ShieldCheck, contentDescription = null, tint = colors.brandLink, modifier = Modifier.padding(11.dp).size(24.dp), @@ -116,18 +115,3 @@ fun ApprovalModalHost( } } } - -private val ApprovalIcon: ImageVector = ImageVector.Builder( - name = "Approval", - defaultWidth = 24.dp, - defaultHeight = 24.dp, - viewportWidth = 24f, - viewportHeight = 24f, -).apply { - path { - moveTo(12f, 2f); lineTo(20f, 5.5f); verticalLineTo(11f) - curveTo(20f, 16.1f, 16.6f, 20.7f, 12f, 22f) - curveTo(7.4f, 20.7f, 4f, 16.1f, 4f, 11f); verticalLineTo(5.5f); close() - moveTo(8.2f, 11.8f); lineTo(10.7f, 14.3f); lineTo(15.9f, 9.1f) - } -}.build() diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/receive/ReceiveScreen.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/receive/ReceiveScreen.kt index dd82fb5..e7f7dc0 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/receive/ReceiveScreen.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/receive/ReceiveScreen.kt @@ -21,7 +21,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -30,13 +29,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.StrokeJoin -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.PathBuilder -import androidx.compose.ui.graphics.vector.path import androidx.compose.ui.platform.testTag import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -55,9 +47,10 @@ import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.ProgressRow import com.vnidrop.app.ui.components.SecondaryButton import com.vnidrop.app.ui.feedback.UiText +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.platform.LocalUiPlatform import com.vnidrop.app.ui.platform.usesMobilePresentation -import com.vnidrop.app.ui.navigation.VniDropIcons import com.vnidrop.app.ui.state.WindowClass import com.vnidrop.app.ui.state.displayNameForStatus import com.vnidrop.app.ui.state.formatBytes @@ -73,7 +66,7 @@ fun ReceiveFloatingAction(onClick: () -> Unit, modifier: Modifier = Modifier) { modifier = modifier, containerColor = LocalVniDropColors.current.brandButton, contentColor = Color.White, - ) { Icon(ReceiveIcons.Download, stringResource(Res.string.button_receive_files)) } + ) { PlatformIcon(AppIcon.Download, stringResource(Res.string.button_receive_files)) } } @Composable @@ -180,8 +173,8 @@ private fun ReceiveEmptyState(onOpen: () -> Unit) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Icon( - imageVector = VniDropIcons.Receive, + PlatformIcon( + icon = AppIcon.Download, contentDescription = null, tint = colors.brandLink, modifier = Modifier @@ -210,15 +203,15 @@ private fun ReceiveMethodPanel( Text(stringResource(Res.string.receive_choose_method_title), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold) Text(stringResource(Res.string.receive_choose_method_body), color = LocalVniDropColors.current.foregroundLighter) ReceiveMethodRow( - ReceiveIcons.File, stringResource(Res.string.receive_method_file), stringResource(Res.string.receive_method_file_description), + AppIcon.File, stringResource(Res.string.receive_method_file), stringResource(Res.string.receive_method_file_description), actions.fileAvailability, ) { actions.pickInvitation { onResult(ReceiveMethod.InvitationFile, it) } } if (actions.qrAvailability != ReceiveMethodAvailability.Hidden) ReceiveMethodRow( - ReceiveIcons.Scan, stringResource(Res.string.receive_method_scan), stringResource(Res.string.receive_method_scan_description), + AppIcon.Scan, stringResource(Res.string.receive_method_scan), stringResource(Res.string.receive_method_scan_description), actions.qrAvailability, ) { actions.scanQrCode { onResult(ReceiveMethod.QrCode, it) } } if (actions.nfcAvailability != ReceiveMethodAvailability.Hidden) ReceiveMethodRow( - ReceiveIcons.Nfc, + AppIcon.Nfc, if (isWaitingForNfc) stringResource(Res.string.receive_nfc_waiting) else stringResource(Res.string.receive_method_nfc), stringResource(Res.string.receive_method_nfc_description), if (isWaitingForNfc) ReceiveMethodAvailability.Unavailable else actions.nfcAvailability, @@ -230,7 +223,7 @@ private fun ReceiveMethodPanel( } @Composable -private fun ReceiveMethodRow(icon: ImageVector, title: String, description: String, availability: ReceiveMethodAvailability, onClick: () -> Unit) { +private fun ReceiveMethodRow(icon: AppIcon, title: String, description: String, availability: ReceiveMethodAvailability, onClick: () -> Unit) { val enabled = availability == ReceiveMethodAvailability.Available Surface( modifier = Modifier.fillMaxWidth().clickable(enabled = enabled, onClick = onClick), @@ -238,7 +231,7 @@ private fun ReceiveMethodRow(icon: ImageVector, title: String, description: Stri color = LocalVniDropColors.current.backgroundSurface200, ) { Row(Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically) { - Icon(icon, null, tint = if (enabled) LocalVniDropColors.current.brandLink else LocalVniDropColors.current.foregroundLighter, modifier = Modifier.size(24.dp)) + PlatformIcon(icon, null, tint = if (enabled) LocalVniDropColors.current.brandLink else LocalVniDropColors.current.foregroundLighter, modifier = Modifier.size(24.dp)) Spacer(Modifier.width(14.dp)) Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) { Text(title, fontWeight = FontWeight.SemiBold) @@ -320,7 +313,7 @@ private fun ReceiveTransferRow( Surface(Modifier.fillMaxWidth(), shape = RoundedCornerShape(14.dp), color = LocalVniDropColors.current.backgroundSurface200) { Row(Modifier.padding(14.dp), verticalAlignment = Alignment.CenterVertically) { Box(Modifier.size(44.dp).background(LocalVniDropColors.current.backgroundSurface300, RoundedCornerShape(10.dp)), contentAlignment = Alignment.Center) { - Icon(ReceiveIcons.File, null, tint = LocalVniDropColors.current.foregroundLighter) + PlatformIcon(AppIcon.File, null, tint = LocalVniDropColors.current.foregroundLighter) } Spacer(Modifier.width(12.dp)) Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) { @@ -332,7 +325,7 @@ private fun ReceiveTransferRow( } if (transfer.status.isTerminalReceiveHistory()) { IconButton(onClick = onDelete) { - Icon(ReceiveIcons.Trash, stringResource(Res.string.receive_delete_history_item), tint = LocalVniDropColors.current.destructiveDefault) + PlatformIcon(AppIcon.Delete, stringResource(Res.string.receive_delete_history_item), tint = LocalVniDropColors.current.destructiveDefault) } } } @@ -369,15 +362,3 @@ private fun ReceiveHistoryDeletePanel( } } } - -private object ReceiveIcons { - val Download = lineIcon("Download") { moveTo(12f, 3f); lineTo(12f, 15f); moveTo(7f, 10f); lineTo(12f, 15f); lineTo(17f, 10f); moveTo(4f, 20f); lineTo(20f, 20f) } - val File = lineIcon("File") { moveTo(14f, 2f); lineTo(6f, 2f); lineTo(6f, 22f); lineTo(18f, 22f); lineTo(18f, 6f); close(); moveTo(14f, 2f); lineTo(14f, 6f); lineTo(18f, 6f) } - val Scan = lineIcon("Scan") { moveTo(3f, 8f); lineTo(3f, 3f); lineTo(8f, 3f); moveTo(16f, 3f); lineTo(21f, 3f); lineTo(21f, 8f); moveTo(21f, 16f); lineTo(21f, 21f); lineTo(16f, 21f); moveTo(8f, 21f); lineTo(3f, 21f); lineTo(3f, 16f); moveTo(7f, 12f); lineTo(17f, 12f) } - val Nfc = lineIcon("Nfc") { moveTo(6f, 8f); curveTo(10f, 12f, 10f, 12f, 6f, 16f); moveTo(10f, 5f); curveTo(17f, 12f, 17f, 12f, 10f, 19f); moveTo(14f, 2f); curveTo(24f, 12f, 24f, 12f, 14f, 22f) } - val Trash = lineIcon("Delete") { moveTo(4f, 7f); lineTo(20f, 7f); moveTo(9f, 3f); lineTo(15f, 3f); lineTo(16f, 7f); moveTo(7f, 7f); lineTo(8f, 21f); lineTo(16f, 21f); lineTo(17f, 7f); moveTo(10f, 11f); lineTo(10f, 17f); moveTo(14f, 11f); lineTo(14f, 17f) } -} - -private fun lineIcon(name: String, block: PathBuilder.() -> Unit) = ImageVector.Builder(name, 24.dp, 24.dp, 24f, 24f).apply { - path(fill = SolidColor(Color.Transparent), stroke = SolidColor(Color.Black), strokeLineWidth = 2f, strokeLineCap = StrokeCap.Round, strokeLineJoin = StrokeJoin.Round, pathFillType = PathFillType.NonZero, pathBuilder = block) -}.build() diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendCatalog.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendCatalog.kt index 065d2c5..8a153a1 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendCatalog.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendCatalog.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.FloatingActionButton -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -42,9 +41,10 @@ import com.vnidrop.app.ui.components.PillTone import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.ProgressRow import com.vnidrop.app.ui.components.StatusPill +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.platform.LocalUiPlatform import com.vnidrop.app.ui.platform.usesMobilePresentation -import com.vnidrop.app.ui.navigation.VniDropIcons import com.vnidrop.app.ui.state.TransferProgress import com.vnidrop.app.ui.state.WindowClass import com.vnidrop.app.ui.state.activeSendProgress @@ -71,7 +71,7 @@ internal fun SendFloatingAction(onClick: () -> Unit, modifier: Modifier = Modifi containerColor = LocalVniDropColors.current.brandButton, contentColor = Color.White, ) { - Icon(SendIcons.Plus, contentDescription = stringResource(Res.string.send_new_transfer_description)) + PlatformIcon(AppIcon.Add, contentDescription = stringResource(Res.string.send_new_transfer_description)) } } @@ -144,8 +144,8 @@ private fun SendEmptyState(onOpenComposer: () -> Unit) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Icon( - imageVector = VniDropIcons.Send, + PlatformIcon( + icon = AppIcon.Send, contentDescription = null, tint = colors.brandLink, modifier = Modifier @@ -216,7 +216,7 @@ private fun TransferListItem( } } Spacer(Modifier.width(8.dp)) - Icon(SendIcons.ChevronRight, contentDescription = null, tint = colors.foregroundLighter, modifier = Modifier.size(18.dp)) + PlatformIcon(AppIcon.ChevronRight, contentDescription = null, tint = colors.foregroundLighter, modifier = Modifier.size(18.dp)) } } } @@ -233,7 +233,7 @@ internal fun FileArtwork(thumbnailBytes: ByteArray?, modifier: Modifier = Modifi ) } else { Box(modifier, contentAlignment = Alignment.Center) { - Icon(SendIcons.File, contentDescription = null, tint = LocalVniDropColors.current.foregroundLight, modifier = Modifier.size(22.dp)) + PlatformIcon(AppIcon.File, contentDescription = null, tint = LocalVniDropColors.current.foregroundLight, modifier = Modifier.size(22.dp)) } } } diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendIcons.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendIcons.kt deleted file mode 100644 index 89089a3..0000000 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/SendIcons.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.vnidrop.app.feature.send - -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.StrokeJoin -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.PathBuilder -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.unit.dp - -internal object SendIcons { - val Plus = lineIcon("Plus") { - moveTo(12f, 5f) - lineTo(12f, 19f) - moveTo(5f, 12f) - lineTo(19f, 12f) - } - val File = lineIcon("File") { - moveTo(14f, 2f) - lineTo(6f, 2f) - lineTo(6f, 22f) - lineTo(18f, 22f) - lineTo(18f, 6f) - close() - moveTo(14f, 2f) - lineTo(14f, 6f) - lineTo(18f, 6f) - } - val Back = lineIcon("Back") { - moveTo(19f, 12f) - lineTo(5f, 12f) - moveTo(12f, 19f) - lineTo(5f, 12f) - lineTo(12f, 5f) - } - val Delete = lineIcon("Delete") { - moveTo(4f, 7f); lineTo(20f, 7f) - moveTo(9f, 7f); lineTo(9f, 4f); lineTo(15f, 4f); lineTo(15f, 7f) - moveTo(6f, 7f); lineTo(7f, 21f); lineTo(17f, 21f); lineTo(18f, 7f) - moveTo(10f, 11f); lineTo(10f, 17f) - moveTo(14f, 11f); lineTo(14f, 17f) - } - val ChevronRight = lineIcon("ChevronRight") { - moveTo(9f, 18f) - lineTo(15f, 12f) - lineTo(9f, 6f) - } - val Shield = lineIcon("Shield") { - moveTo(12f, 2f) - lineTo(20f, 6f) - lineTo(20f, 12f) - arcTo(9f, 9f, 0f, false, true, 12f, 22f) - arcTo(9f, 9f, 0f, false, true, 4f, 12f) - lineTo(4f, 6f) - close() - } - val Globe = lineIcon("Globe") { - moveTo(21f, 12f) - arcTo(9f, 9f, 0f, true, true, 3f, 12f) - arcTo(9f, 9f, 0f, true, true, 21f, 12f) - moveTo(3f, 12f) - lineTo(21f, 12f) - moveTo(12f, 3f) - arcTo(14f, 14f, 0f, false, true, 12f, 21f) - arcTo(14f, 14f, 0f, false, true, 12f, 3f) - } -} - -private fun lineIcon(name: String, block: PathBuilder.() -> Unit): ImageVector = - ImageVector.Builder(name, 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = 2f, - strokeLineCap = StrokeCap.Round, - strokeLineJoin = StrokeJoin.Round, - pathFillType = PathFillType.NonZero, - pathBuilder = block, - ) - }.build() diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferComposer.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferComposer.kt index 5a3bedb..6ff956d 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferComposer.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferComposer.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton @@ -25,7 +24,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -35,6 +33,8 @@ import com.vnidrop.app.core.ShareAccessPolicy import com.vnidrop.app.ui.components.Field import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.QuietButton +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.state.WindowClass import com.vnidrop.app.ui.state.formatBytes import com.vnidrop.app.ui.theme.LocalVniDropColors @@ -114,7 +114,7 @@ private fun ChooseFileStep(onSelectFile: () -> Unit, onSelectFolder: () -> Unit) horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(14.dp), ) { - Icon(SendIcons.File, contentDescription = null, tint = LocalVniDropColors.current.brandLink, modifier = Modifier.size(32.dp)) + PlatformIcon(AppIcon.File, contentDescription = null, tint = LocalVniDropColors.current.brandLink, modifier = Modifier.size(32.dp)) PrimaryButton(stringResource(Res.string.button_choose_files), onClick = onSelectFile) QuietButton(stringResource(Res.string.button_choose_folder), onClick = onSelectFolder) } @@ -154,14 +154,14 @@ private fun ReviewFileStep( Field(state.senderName, onSenderNameChanged, stringResource(Res.string.field_sender_name)) Text(stringResource(Res.string.send_access_title), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold) PolicyOption( - icon = SendIcons.Shield, + icon = AppIcon.Shield, title = stringResource(Res.string.send_access_approval), description = stringResource(Res.string.send_access_approval_description), selected = state.accessPolicy == ShareAccessPolicy.RequireApproval, onClick = { onAccessPolicyChanged(ShareAccessPolicy.RequireApproval) }, ) PolicyOption( - icon = SendIcons.Globe, + icon = AppIcon.Globe, title = stringResource(Res.string.send_access_anyone), description = stringResource(Res.string.send_access_anyone_description), selected = state.accessPolicy == ShareAccessPolicy.AnyoneWithTransfer, @@ -226,7 +226,7 @@ private fun SelectedFileCard( } if (canRemove) { IconButton(onClick = onRemove) { - Icon(SendIcons.Delete, stringResource(Res.string.button_remove_file), tint = LocalVniDropColors.current.destructiveDefault) + PlatformIcon(AppIcon.Delete, stringResource(Res.string.button_remove_file), tint = LocalVniDropColors.current.destructiveDefault) } } } @@ -235,7 +235,7 @@ private fun SelectedFileCard( @Composable private fun PolicyOption( - icon: ImageVector, + icon: AppIcon, title: String, description: String, selected: Boolean, @@ -252,7 +252,7 @@ private fun PolicyOption( .padding(14.dp), verticalAlignment = Alignment.CenterVertically, ) { - Icon(icon, contentDescription = null, tint = if (selected) colors.brandLink else colors.foregroundLight, modifier = Modifier.size(22.dp)) + PlatformIcon(icon, contentDescription = null, tint = if (selected) colors.brandLink else colors.foregroundLight, modifier = Modifier.size(22.dp)) Spacer(Modifier.width(12.dp)) Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) { Text(title, fontWeight = FontWeight.SemiBold) diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferDetails.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferDetails.kt index 0d772b5..d6d3d75 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferDetails.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/send/TransferDetails.kt @@ -23,7 +23,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -52,6 +51,8 @@ import com.vnidrop.app.ui.components.DestructiveButton import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.ProgressRow import com.vnidrop.app.ui.components.SecondaryButton +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.state.TransferProgress import com.vnidrop.app.ui.state.displayNameForStatus import com.vnidrop.app.ui.state.formatBytes @@ -84,7 +85,7 @@ internal fun TransferDetails( ) { item { Row(verticalAlignment = Alignment.CenterVertically) { - IconButton(onClick = onBack) { Icon(SendIcons.Back, stringResource(Res.string.button_back)) } + IconButton(onClick = onBack) { PlatformIcon(AppIcon.ArrowBack, stringResource(Res.string.button_back)) } Text( stringResource(Res.string.send_transfer_details_title), modifier = Modifier.weight(1f), @@ -92,7 +93,7 @@ internal fun TransferDetails( fontWeight = FontWeight.Bold, ) IconButton(onClick = onDelete) { - Icon(SendIcons.Delete, stringResource(Res.string.button_delete_transfer), tint = LocalVniDropColors.current.destructiveDefault) + PlatformIcon(AppIcon.Delete, stringResource(Res.string.button_delete_transfer), tint = LocalVniDropColors.current.destructiveDefault) } } } @@ -156,7 +157,7 @@ private fun DetailDestination(title: String, description: String, count: Int? = Text(count.toString(), modifier = Modifier.background(LocalVniDropColors.current.backgroundSelection, RoundedCornerShape(20.dp)).padding(horizontal = 9.dp, vertical = 3.dp)) Spacer(Modifier.width(8.dp)) } - Icon(SendIcons.ChevronRight, null, tint = LocalVniDropColors.current.foregroundLighter, modifier = Modifier.size(18.dp)) + PlatformIcon(AppIcon.ChevronRight, null, tint = LocalVniDropColors.current.foregroundLighter, modifier = Modifier.size(18.dp)) } } diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AboutSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AboutSettings.kt index e2f3d65..3c4562a 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AboutSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AboutSettings.kt @@ -9,18 +9,18 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.vnidrop.app.diagnostics.DiagnosticsBuildConfig +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -87,28 +87,28 @@ internal fun AboutSettings( AboutSection( title = stringResource(Res.string.about_is_title), points = listOf( - SettingsIcons.PaperPlane to stringResource(Res.string.about_is_direct), - SettingsIcons.AccountOff to stringResource(Res.string.about_is_no_account), - SettingsIcons.ShieldCheck to stringResource(Res.string.about_is_in_control), - SettingsIcons.Lock to stringResource(Res.string.about_is_encrypted), - SettingsIcons.Code to stringResource(Res.string.about_is_open), + AppIcon.Send to stringResource(Res.string.about_is_direct), + AppIcon.UserOff to stringResource(Res.string.about_is_no_account), + AppIcon.ShieldCheck to stringResource(Res.string.about_is_in_control), + AppIcon.Lock to stringResource(Res.string.about_is_encrypted), + AppIcon.Code to stringResource(Res.string.about_is_open), ), ) AboutSection( title = stringResource(Res.string.about_isnt_title), points = listOf( - SettingsIcons.CloudOff to stringResource(Res.string.about_isnt_cloud), - SettingsIcons.Sync to stringResource(Res.string.about_isnt_sync), - SettingsIcons.Megaphone to stringResource(Res.string.about_isnt_public), + AppIcon.CloudOff to stringResource(Res.string.about_isnt_cloud), + AppIcon.Sync to stringResource(Res.string.about_isnt_sync), + AppIcon.Megaphone to stringResource(Res.string.about_isnt_public), ), ) AboutSection( title = stringResource(Res.string.about_privacy_title), points = listOf( - SettingsIcons.QrCode to stringResource(Res.string.about_privacy_capability), - SettingsIcons.Hand to stringResource(Res.string.about_privacy_deny), - SettingsIcons.Radio to stringResource(Res.string.about_privacy_relay), - SettingsIcons.Drive to stringResource(Res.string.about_privacy_local), + AppIcon.QrCode to stringResource(Res.string.about_privacy_capability), + AppIcon.Hand to stringResource(Res.string.about_privacy_deny), + AppIcon.Radio to stringResource(Res.string.about_privacy_relay), + AppIcon.Storage to stringResource(Res.string.about_privacy_local), ), ) @@ -122,7 +122,7 @@ internal fun AboutSettings( AboutInfoItem(stringResource(Res.string.about_license_label), "Apache 2.0") SettingsDivider() SettingsRow( - icon = SettingsIcons.Shield, + icon = AppIcon.Shield, title = stringResource(Res.string.about_privacy_policy_label), iconTone = SettingsIconTone.Brand, onClick = { uriHandler.openUri(PrivacyPolicyUrl) }, @@ -132,7 +132,7 @@ internal fun AboutSettings( SettingsGroup { if (DiagnosticsBuildConfig.INCLUDED) { SettingsToggleRow( - icon = SettingsIcons.Info, + icon = AppIcon.Info, title = stringResource(Res.string.diagnostics_title), description = stringResource(Res.string.diagnostics_description), checked = state.diagnosticsEnabled, @@ -142,7 +142,7 @@ internal fun AboutSettings( SettingsDivider() } SettingsRow( - icon = SettingsIcons.Bug, + icon = AppIcon.Bug, title = stringResource(Res.string.about_bug_report), iconTone = SettingsIconTone.Neutral, onClick = onReportBug, @@ -154,7 +154,7 @@ internal fun AboutSettings( @Composable private fun AboutSection( title: String, - points: List>, + points: List>, ) { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Text( @@ -173,7 +173,7 @@ private fun AboutSection( } @Composable -private fun AboutPoint(icon: ImageVector, text: String) { +private fun AboutPoint(icon: AppIcon, text: String) { val colors = LocalVniDropColors.current Row( modifier = Modifier @@ -182,7 +182,7 @@ private fun AboutPoint(icon: ImageVector, text: String) { .padding(horizontal = 16.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically, ) { - Icon(icon, contentDescription = null, tint = colors.brandLink, modifier = Modifier.size(24.dp)) + PlatformIcon(icon, contentDescription = null, tint = colors.brandLink, modifier = Modifier.size(24.dp)) Spacer(Modifier.width(16.dp)) Text( text, diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AppearanceSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AppearanceSettings.kt index 8144651..16fe354 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AppearanceSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/AppearanceSettings.kt @@ -3,15 +3,15 @@ package com.vnidrop.app.feature.settings import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import com.vnidrop.app.ui.theme.ThemeMode +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.theme.LocalVniDropColors +import com.vnidrop.app.ui.theme.ThemeMode import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res import vnidrop.shared.generated.resources.appearance_auto_description @@ -30,15 +30,15 @@ internal fun AppearanceSettings( Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { SettingsTopBar(stringResource(Res.string.appearance_title), onBack, showBack) SettingsGroup { - ThemeSettingsRow(SettingsIcons.Device, stringResource(Res.string.appearance_system_mode), mode == ThemeMode.System) { + ThemeSettingsRow(AppIcon.SystemTheme, stringResource(Res.string.appearance_system_mode), mode == ThemeMode.System) { onModeChanged(ThemeMode.System) } SettingsDivider() - ThemeSettingsRow(SettingsIcons.Moon, stringResource(Res.string.appearance_dark_mode), mode == ThemeMode.Dark) { + ThemeSettingsRow(AppIcon.Moon, stringResource(Res.string.appearance_dark_mode), mode == ThemeMode.Dark) { onModeChanged(ThemeMode.Dark) } SettingsDivider() - ThemeSettingsRow(SettingsIcons.Sun, stringResource(Res.string.appearance_light_mode), mode == ThemeMode.Light) { + ThemeSettingsRow(AppIcon.Sun, stringResource(Res.string.appearance_light_mode), mode == ThemeMode.Light) { onModeChanged(ThemeMode.Light) } } @@ -53,7 +53,7 @@ internal fun AppearanceSettings( } @Composable -private fun ThemeSettingsRow(icon: ImageVector, title: String, selected: Boolean, onClick: () -> Unit) { +private fun ThemeSettingsRow(icon: AppIcon, title: String, selected: Boolean, onClick: () -> Unit) { SettingsRow( icon = icon, title = title, @@ -62,8 +62,8 @@ private fun ThemeSettingsRow(icon: ImageVector, title: String, selected: Boolean showsDisclosure = false, trailing = if (selected) { { - Icon( - SettingsIcons.Check, + PlatformIcon( + AppIcon.Check, contentDescription = null, tint = LocalVniDropColors.current.brandLink, modifier = Modifier.size(20.dp), diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/BugReportSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/BugReportSettings.kt index 0e50b72..52c7402 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/BugReportSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/BugReportSettings.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vnidrop.app.ui.components.Field import com.vnidrop.app.ui.components.PrimaryButton +import com.vnidrop.app.ui.icons.AppIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -82,7 +83,7 @@ internal fun BugReportSettings( ) SettingsGroup { SettingsToggleRow( - icon = SettingsIcons.Document, + icon = AppIcon.Document, title = stringResource(Res.string.bug_report_include_logs), description = stringResource(Res.string.bug_report_include_logs_description), checked = state.bugIncludeLogs, diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/NotificationSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/NotificationSettings.kt index 8916d91..95bb9ff 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/NotificationSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/NotificationSettings.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.vnidrop.app.notifications.NotificationPermission import com.vnidrop.app.ui.components.SecondaryButton +import com.vnidrop.app.ui.icons.AppIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -32,7 +33,7 @@ internal fun NotificationSettings( SettingsTopBar(stringResource(Res.string.notifications_title), onBack, showBack) SettingsGroup { SettingsToggleRow( - icon = SettingsIcons.Bell, + icon = AppIcon.Bell, title = stringResource(Res.string.notifications_local_title), description = stringResource(Res.string.notifications_description), checked = state.notificationsEnabled, diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/PreferencesSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/PreferencesSettings.kt index 315d527..3f086a2 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/PreferencesSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/PreferencesSettings.kt @@ -9,6 +9,7 @@ import com.vnidrop.app.core.FolderAccessStatus import com.vnidrop.app.ui.components.Field import com.vnidrop.app.ui.components.PrimaryButton import com.vnidrop.app.ui.components.SecondaryButton +import com.vnidrop.app.ui.icons.AppIcon import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res import vnidrop.shared.generated.resources.button_choose_folder @@ -35,14 +36,14 @@ internal fun PreferencesSettings( Field(state.username, onUsernameChanged, stringResource(Res.string.field_username)) SettingsGroup { SettingsRow( - icon = SettingsIcons.Folder, + icon = AppIcon.Folder, title = stringResource(Res.string.preferences_receive_folder_title), value = state.receiveFolder?.displayName?.ifBlank { state.receiveFolder.value }, iconTone = SettingsIconTone.Neutral, ) SettingsDivider() SettingsRow( - icon = SettingsIcons.Check, + icon = AppIcon.Check, title = state.folderStatusLabel(), iconTone = SettingsIconTone.Neutral, ) diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsComponents.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsComponents.kt index 9b8b838..60d9ff6 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsComponents.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsComponents.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch @@ -30,12 +29,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -52,8 +52,8 @@ internal fun SettingsTopBar(title: String, onBack: () -> Unit, showBack: Boolean ) { if (showBack) { IconButton(onClick = onBack) { - Icon( - SettingsIcons.Back, + PlatformIcon( + AppIcon.ArrowBack, contentDescription = stringResource(Res.string.button_back), tint = LocalVniDropColors.current.foregroundDefault, ) @@ -78,7 +78,7 @@ internal fun SettingsGroup(content: @Composable ColumnScope.() -> Unit) { @Composable internal fun SettingsRow( - icon: ImageVector, + icon: AppIcon, title: String, value: String? = null, subtitle: String? = null, @@ -135,7 +135,7 @@ internal fun SettingsRow( } onClick != null && showsDisclosure -> { Spacer(Modifier.width(8.dp)) - Icon(SettingsIcons.ChevronRight, contentDescription = null, tint = colors.foregroundLighter, modifier = Modifier.size(18.dp)) + PlatformIcon(AppIcon.ChevronRight, contentDescription = null, tint = colors.foregroundLighter, modifier = Modifier.size(18.dp)) } } } @@ -143,7 +143,7 @@ internal fun SettingsRow( @Composable internal fun SettingsToggleRow( - icon: ImageVector, + icon: AppIcon, title: String, description: String, checked: Boolean, @@ -203,7 +203,7 @@ internal fun InfoItem(title: String, value: String) { } @Composable -private fun SettingsLeadingIcon(icon: ImageVector, tone: SettingsIconTone) { +private fun SettingsLeadingIcon(icon: AppIcon, tone: SettingsIconTone) { val colors = LocalVniDropColors.current val foreground = if (tone == SettingsIconTone.Brand) colors.brandLink else colors.foregroundLight val background = if (tone == SettingsIconTone.Brand) colors.brandLink.copy(alpha = 0.13f) else colors.backgroundSurface300 @@ -211,6 +211,6 @@ private fun SettingsLeadingIcon(icon: ImageVector, tone: SettingsIconTone) { modifier = Modifier.size(34.dp).background(background, RoundedCornerShape(10.dp)), contentAlignment = Alignment.Center, ) { - Icon(icon, contentDescription = null, tint = foreground, modifier = Modifier.size(19.dp)) + PlatformIcon(icon, contentDescription = null, tint = foreground, modifier = Modifier.size(19.dp)) } } diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsIcons.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsIcons.kt deleted file mode 100644 index 97cbe79..0000000 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsIcons.kt +++ /dev/null @@ -1,328 +0,0 @@ -package com.vnidrop.app.feature.settings - -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.StrokeJoin -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.PathBuilder -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.unit.dp - -internal object SettingsIcons { - val ChevronRight = lineIcon("ChevronRight") { - moveTo(9f, 18f) - lineTo(15f, 12f) - lineTo(9f, 6f) - } - val Back = lineIcon("Back") { - moveTo(19f, 12f) - lineTo(5f, 12f) - moveTo(12f, 19f) - lineTo(5f, 12f) - lineTo(12f, 5f) - } - val Check = lineIcon("Check") { - moveTo(20f, 6f) - lineTo(9f, 17f) - lineTo(4f, 12f) - } - val PaperPlane = lineIcon("PaperPlane") { - moveTo(22f, 2f) - lineTo(15f, 22f) - lineTo(11f, 13f) - lineTo(2f, 9f) - close() - moveTo(22f, 2f) - lineTo(11f, 13f) - } - val AccountOff = lineIcon("AccountOff") { - circle(9f, 8f, 4f) - moveTo(2f, 21f) - curveTo(2.8f, 16.8f, 5f, 15f, 9f, 15f) - curveTo(11.1f, 15f, 12.7f, 15.5f, 14f, 16.5f) - circle(18f, 18f, 4f) - moveTo(16.6f, 16.6f) - lineTo(19.4f, 19.4f) - moveTo(19.4f, 16.6f) - lineTo(16.6f, 19.4f) - } - val ShieldCheck = lineIcon("ShieldCheck") { - moveTo(12f, 22f) - curveTo(17f, 19.5f, 20f, 16.5f, 20f, 11f) - lineTo(20f, 5f) - lineTo(12f, 2f) - lineTo(4f, 5f) - lineTo(4f, 11f) - curveTo(4f, 16.5f, 7f, 19.5f, 12f, 22f) - moveTo(8f, 12f) - lineTo(11f, 15f) - lineTo(16f, 9f) - } - val Shield = lineIcon("Shield") { - moveTo(12f, 22f) - curveTo(17f, 19.5f, 20f, 16.5f, 20f, 11f) - lineTo(20f, 5f) - lineTo(12f, 2f) - lineTo(4f, 5f) - lineTo(4f, 11f) - curveTo(4f, 16.5f, 7f, 19.5f, 12f, 22f) - } - val Lock = lineIcon("Lock") { - roundRect(5f, 10f, 14f, 11f, 2f) - moveTo(8f, 10f) - lineTo(8f, 7f) - arcTo(4f, 4f, 0f, false, true, 16f, 7f) - lineTo(16f, 10f) - } - val Code = lineIcon("Code") { - moveTo(8f, 9f) - lineTo(3f, 14f) - lineTo(8f, 19f) - moveTo(16f, 9f) - lineTo(21f, 14f) - lineTo(16f, 19f) - moveTo(14f, 4f) - lineTo(10f, 22f) - } - val CloudOff = lineIcon("CloudOff") { - moveTo(5.5f, 5.5f) - lineTo(18.5f, 18.5f) - moveTo(7f, 18f) - lineTo(6f, 18f) - curveTo(2.7f, 18f, 1f, 16.2f, 1f, 13.5f) - curveTo(1f, 10.7f, 3.1f, 8.5f, 6f, 8.1f) - curveTo(7.5f, 4.9f, 10.1f, 3f, 13.5f, 3f) - curveTo(18f, 3f, 21f, 6.5f, 21f, 11f) - curveTo(22.3f, 12f, 23f, 13.4f, 23f, 15f) - curveTo(23f, 16.1f, 22.7f, 17f, 22f, 18f) - } - val Sync = lineIcon("Sync") { - moveTo(20f, 7f) - lineTo(20f, 3f) - lineTo(16f, 3f) - moveTo(20f, 3f) - curveTo(17.7f, 1.4f, 14.8f, 1f, 12f, 2f) - curveTo(9.6f, 2.8f, 7.7f, 4.6f, 7f, 7f) - moveTo(4f, 17f) - lineTo(4f, 21f) - lineTo(8f, 21f) - moveTo(4f, 21f) - curveTo(6.3f, 22.6f, 9.2f, 23f, 12f, 22f) - curveTo(14.4f, 21.2f, 16.3f, 19.4f, 17f, 17f) - } - val Megaphone = lineIcon("Megaphone") { - moveTo(3f, 11f) - lineTo(3f, 15f) - lineTo(7f, 15f) - lineTo(18f, 20f) - lineTo(18f, 6f) - lineTo(7f, 11f) - close() - moveTo(7f, 15f) - lineTo(9f, 21f) - lineTo(13f, 21f) - lineTo(11.5f, 17f) - moveTo(21f, 10f) - lineTo(21f, 16f) - } - val QrCode = lineIcon("QrCode") { - moveTo(3f, 9f) - lineTo(3f, 3f) - lineTo(9f, 3f) - moveTo(15f, 3f) - lineTo(21f, 3f) - lineTo(21f, 9f) - moveTo(3f, 15f) - lineTo(3f, 21f) - lineTo(9f, 21f) - moveTo(15f, 21f) - lineTo(15f, 15f) - lineTo(21f, 15f) - moveTo(7f, 7f) - lineTo(7.01f, 7f) - moveTo(17f, 7f) - lineTo(17.01f, 7f) - moveTo(7f, 17f) - lineTo(7.01f, 17f) - moveTo(20f, 20f) - lineTo(20.01f, 20f) - } - val Hand = lineIcon("Hand", strokeWidth = 1.6f) { - moveTo(4f, 14f) - lineTo(4f, 10f) - curveTo(4f, 8.9f, 4.9f, 8f, 6f, 8f) - curveTo(7.1f, 8f, 8f, 8.9f, 8f, 10f) - lineTo(8f, 12f) - lineTo(8.5f, 12f) - lineTo(8.5f, 6f) - curveTo(8.5f, 4.9f, 9.4f, 4f, 10.5f, 4f) - curveTo(11.6f, 4f, 12.5f, 4.9f, 12.5f, 6f) - lineTo(12.5f, 11f) - lineTo(13f, 11f) - lineTo(13f, 4f) - curveTo(13f, 2.9f, 13.9f, 2f, 15f, 2f) - curveTo(16.1f, 2f, 17f, 2.9f, 17f, 4f) - lineTo(17f, 12f) - lineTo(17.5f, 12f) - lineTo(17.5f, 7f) - curveTo(17.5f, 5.9f, 18.4f, 5f, 19.5f, 5f) - curveTo(20.6f, 5f, 21.5f, 5.9f, 21.5f, 7f) - lineTo(21.5f, 14f) - lineTo(22f, 13.5f) - curveTo(22.4f, 13.1f, 23f, 13.2f, 23.4f, 13.7f) - curveTo(23.9f, 14.4f, 23.7f, 15.3f, 23.1f, 16f) - lineTo(18.8f, 21f) - curveTo(17.7f, 22.3f, 16.1f, 23f, 14.3f, 23f) - lineTo(12f, 23f) - curveTo(7.6f, 23f, 4f, 19.4f, 4f, 15f) - close() - } - val Radio = lineIcon("Radio") { - moveTo(12f, 12f) - lineTo(12f, 22f) - moveTo(9f, 22f) - lineTo(15f, 22f) - moveTo(9f, 9f) - curveTo(7.5f, 10.7f, 7.5f, 13.3f, 9f, 15f) - moveTo(15f, 9f) - curveTo(16.5f, 10.7f, 16.5f, 13.3f, 15f, 15f) - moveTo(6f, 6f) - curveTo(2.7f, 9.3f, 2.7f, 14.7f, 6f, 18f) - moveTo(18f, 6f) - curveTo(21.3f, 9.3f, 21.3f, 14.7f, 18f, 18f) - circle(12f, 12f, 1f) - } - val Drive = lineIcon("Drive") { - roundRect(2f, 6f, 20f, 12f, 3f) - moveTo(2f, 14f) - lineTo(22f, 14f) - moveTo(17f, 16f) - lineTo(17.01f, 16f) - moveTo(20f, 16f) - lineTo(20.01f, 16f) - } - val Sun = lineIcon("Sun") { - moveTo(12f, 4f) - lineTo(12f, 2f) - moveTo(12f, 22f) - lineTo(12f, 20f) - moveTo(4.93f, 4.93f) - lineTo(6.34f, 6.34f) - moveTo(17.66f, 17.66f) - lineTo(19.07f, 19.07f) - moveTo(2f, 12f) - lineTo(4f, 12f) - moveTo(20f, 12f) - lineTo(22f, 12f) - moveTo(4.93f, 19.07f) - lineTo(6.34f, 17.66f) - moveTo(17.66f, 6.34f) - lineTo(19.07f, 4.93f) - moveTo(16f, 12f) - arcTo(4f, 4f, 0f, true, true, 8f, 12f) - arcTo(4f, 4f, 0f, true, true, 16f, 12f) - } - val Moon = lineIcon("Moon") { - moveTo(21f, 12.79f) - arcTo(9f, 9f, 0f, true, true, 11.21f, 3f) - arcTo(7f, 7f, 0f, false, false, 21f, 12.79f) - } - val Device = lineIcon("Device") { - roundRect(7f, 2f, 10f, 20f, 2.5f) - moveTo(11f, 18f) - lineTo(13f, 18f) - } - val Folder = lineIcon("Folder") { - moveTo(3f, 7f) - lineTo(9f, 7f) - lineTo(11f, 9f) - lineTo(21f, 9f) - lineTo(21f, 19f) - lineTo(3f, 19f) - close() - } - val Info = lineIcon("Info") { - moveTo(12f, 16f) - lineTo(12f, 12f) - moveTo(12f, 8f) - lineTo(12.01f, 8f) - moveTo(21f, 12f) - arcTo(9f, 9f, 0f, true, true, 3f, 12f) - arcTo(9f, 9f, 0f, true, true, 21f, 12f) - } - val Bell = lineIcon("Bell") { - moveTo(18f, 8f) - arcTo(6f, 6f, 0f, false, false, 6f, 8f) - lineTo(6f, 13f) - lineTo(4f, 17f) - lineTo(20f, 17f) - lineTo(18f, 13f) - close() - moveTo(10f, 21f) - arcTo(2f, 2f, 0f, false, false, 14f, 21f) - } - val Document = lineIcon("Document") { - moveTo(14f, 2f) - lineTo(6f, 2f) - arcTo(2f, 2f, 0f, false, false, 4f, 4f) - lineTo(4f, 20f) - arcTo(2f, 2f, 0f, false, false, 6f, 22f) - lineTo(18f, 22f) - arcTo(2f, 2f, 0f, false, false, 20f, 20f) - lineTo(20f, 8f) - lineTo(14f, 2f) - moveTo(14f, 2f) - lineTo(14f, 8f) - lineTo(20f, 8f) - } - val Bug = lineIcon("Bug") { - roundRect(7f, 6f, 10f, 14f, 5f) - moveTo(3f, 10f) - lineTo(7f, 10f) - moveTo(17f, 10f) - lineTo(21f, 10f) - moveTo(3f, 16f) - lineTo(7f, 16f) - moveTo(17f, 16f) - lineTo(21f, 16f) - moveTo(12f, 6f) - lineTo(12f, 20f) - } -} - -private fun lineIcon( - name: String, - strokeWidth: Float = 2f, - block: PathBuilder.() -> Unit, -): ImageVector = - ImageVector.Builder(name, 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = strokeWidth, - strokeLineCap = StrokeCap.Round, - strokeLineJoin = StrokeJoin.Round, - pathFillType = PathFillType.NonZero, - pathBuilder = block, - ) - }.build() - -private fun PathBuilder.roundRect(x: Float, y: Float, width: Float, height: Float, radius: Float) { - moveTo(x + radius, y) - lineTo(x + width - radius, y) - arcTo(radius, radius, 0f, false, true, x + width, y + radius) - lineTo(x + width, y + height - radius) - arcTo(radius, radius, 0f, false, true, x + width - radius, y + height) - lineTo(x + radius, y + height) - arcTo(radius, radius, 0f, false, true, x, y + height - radius) - lineTo(x, y + radius) - arcTo(radius, radius, 0f, false, true, x + radius, y) -} - -private fun PathBuilder.circle(centerX: Float, centerY: Float, radius: Float) { - moveTo(centerX + radius, centerY) - arcTo(radius, radius, 0f, true, true, centerX - radius, centerY) - arcTo(radius, radius, 0f, true, true, centerX + radius, centerY) -} diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsOverview.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsOverview.kt index 0f7ecbf..5d292c4 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsOverview.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/SettingsOverview.kt @@ -7,6 +7,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import com.vnidrop.app.ui.icons.AppIcon import com.vnidrop.app.ui.theme.ThemeMode import org.jetbrains.compose.resources.stringResource import vnidrop.shared.generated.resources.Res @@ -34,14 +35,14 @@ internal fun SettingsOverview( ) SettingsGroup { SettingsRow( - icon = SettingsIcons.Drive, + icon = AppIcon.Storage, title = stringResource(Res.string.storage_title), selected = state.selectedSection == SettingsSection.Storage, onClick = { onSectionSelected(SettingsSection.Storage) }, ) SettingsDivider() SettingsRow( - icon = SettingsIcons.Device, + icon = AppIcon.User, title = stringResource(Res.string.preferences_title), value = state.username, selected = state.selectedSection == SettingsSection.Preferences, @@ -49,7 +50,7 @@ internal fun SettingsOverview( ) SettingsDivider() SettingsRow( - icon = SettingsIcons.Sun, + icon = AppIcon.Sun, title = stringResource(Res.string.appearance_title), value = themeModeLabel(state.themeMode), selected = state.selectedSection == SettingsSection.Appearance, @@ -58,14 +59,14 @@ internal fun SettingsOverview( } SettingsGroup { SettingsRow( - icon = SettingsIcons.Bell, + icon = AppIcon.Bell, title = stringResource(Res.string.notifications_title), selected = state.selectedSection == SettingsSection.Notifications, onClick = { onSectionSelected(SettingsSection.Notifications) }, ) SettingsDivider() SettingsRow( - icon = SettingsIcons.Info, + icon = AppIcon.Info, title = stringResource(Res.string.about_title), selected = state.selectedSection == SettingsSection.About, iconTone = SettingsIconTone.Neutral, diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/StorageSettings.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/StorageSettings.kt index 07b1b48..f5c4c75 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/StorageSettings.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/feature/settings/StorageSettings.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.unit.dp +import com.vnidrop.app.ui.icons.AppIcon import com.vnidrop.app.ui.state.formatBytes import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.stringResource @@ -37,26 +38,26 @@ internal fun StorageSettings( if (storage == null || state.isCalculatingStorage) { SettingsGroup { SettingsRow( - icon = SettingsIcons.Drive, + icon = AppIcon.Storage, title = stringResource(Res.string.storage_calculating), trailing = { CircularProgressIndicator() }, ) } } else { SettingsGroup { - StorageRow(stringResource(Res.string.storage_transfer_data), storage.transferCacheBytes) + StorageRow(AppIcon.TransferData, stringResource(Res.string.storage_transfer_data), storage.transferCacheBytes) SettingsDivider() - StorageRow(stringResource(Res.string.storage_app_data), storage.appDataBytes) + StorageRow(AppIcon.Storage, stringResource(Res.string.storage_app_data), storage.appDataBytes) SettingsDivider() - StorageRow(stringResource(Res.string.storage_temporary), storage.temporaryBytes) + StorageRow(AppIcon.Temporary, stringResource(Res.string.storage_temporary), storage.temporaryBytes) SettingsDivider() SettingsRow( - icon = SettingsIcons.Folder, + icon = AppIcon.Folder, title = stringResource(Res.string.storage_received_files), value = formatBytes(storage.receivedBytes), ) SettingsDivider() - StorageRow(stringResource(Res.string.storage_total), storage.deviceImpactBytes) + StorageRow(AppIcon.TotalStorage, stringResource(Res.string.storage_total), storage.deviceImpactBytes) } } Button( @@ -75,6 +76,6 @@ internal fun StorageSettings( } @Composable -private fun StorageRow(title: String, bytes: ULong) { - SettingsRow(icon = SettingsIcons.Drive, title = title, value = formatBytes(bytes)) +private fun StorageRow(icon: AppIcon, title: String, bytes: ULong) { + SettingsRow(icon = icon, title = title, value = formatBytes(bytes)) } diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/components/AdaptiveDrawer.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/components/AdaptiveDrawer.kt index 56e9ee3..c8f162b 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/components/AdaptiveDrawer.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/components/AdaptiveDrawer.kt @@ -8,22 +8,18 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Surface import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.path import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.vnidrop.app.isDesktop +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.platform.LocalUiPlatform import com.vnidrop.app.ui.platform.usesMobilePresentation import com.vnidrop.app.ui.state.WindowClass @@ -75,14 +71,7 @@ private fun ClosableModalContent( onClick = onClose, modifier = Modifier.align(androidx.compose.ui.Alignment.TopEnd).padding(8.dp).size(40.dp), ) { - Icon(CloseIcon, stringResource(Res.string.button_close), tint = LocalVniDropColors.current.foregroundLight) + PlatformIcon(AppIcon.Close, stringResource(Res.string.button_close), tint = LocalVniDropColors.current.foregroundLight) } } } - -private val CloseIcon = ImageVector.Builder("Close", 24.dp, 24.dp, 24f, 24f).apply { - path(fill = SolidColor(Color.Transparent), stroke = SolidColor(Color.Black), strokeLineWidth = 2f, strokeLineCap = StrokeCap.Round) { - moveTo(6f, 6f); lineTo(18f, 18f) - moveTo(18f, 6f); lineTo(6f, 18f) - } -}.build() diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/feedback/VniDropSnackbarHost.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/feedback/VniDropSnackbarHost.kt index d3454bb..7e8ce53 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/feedback/VniDropSnackbarHost.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/feedback/VniDropSnackbarHost.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SnackbarData @@ -28,12 +27,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.path import androidx.compose.ui.unit.dp +import com.vnidrop.app.ui.icons.AppIcon +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.theme.LocalVniDropColors import org.jetbrains.compose.resources.getString import org.jetbrains.compose.resources.stringResource @@ -131,8 +127,8 @@ private fun SnackbarMessage(message: String, modifier: Modifier = Modifier) { @Composable private fun DismissButton(onClick: () -> Unit) { IconButton(onClick = onClick, modifier = Modifier.size(40.dp)) { - Icon( - imageVector = CloseIcon, + PlatformIcon( + icon = AppIcon.Close, contentDescription = stringResource(Res.string.snackbar_dismiss), tint = LocalVniDropColors.current.foregroundLighter, modifier = Modifier.size(18.dp), @@ -140,21 +136,6 @@ private fun DismissButton(onClick: () -> Unit) { } } -private val CloseIcon = ImageVector.Builder("Close", 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = 2f, - strokeLineCap = StrokeCap.Round, - pathFillType = PathFillType.NonZero, - ) { - moveTo(6f, 6f) - lineTo(18f, 18f) - moveTo(18f, 6f) - lineTo(6f, 18f) - } -}.build() - private suspend fun UiText.resolve(): String = when (this) { is UiText.Dynamic -> value is UiText.Resource -> getString(resource) diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/icons/PlatformIcons.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/icons/PlatformIcons.kt new file mode 100644 index 0000000..bd7e6a0 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/icons/PlatformIcons.kt @@ -0,0 +1,115 @@ +package com.vnidrop.app.ui.icons + +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import com.vnidrop.app.UiPlatform +import com.vnidrop.app.ui.platform.LocalUiPlatform +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.painterResource +import vnidrop.shared.generated.resources.* + +internal enum class AppIcon( + val material: DrawableResource, + val fluent: DrawableResource, + val lucide: DrawableResource, +) { + Add(Res.drawable.icon_material_add, Res.drawable.icon_fluent_add, Res.drawable.icon_lucide_add), + ArrowBack(Res.drawable.icon_material_arrow_back, Res.drawable.icon_fluent_arrow_back, Res.drawable.icon_lucide_arrow_back), + Bell(Res.drawable.icon_material_bell, Res.drawable.icon_fluent_bell, Res.drawable.icon_lucide_bell), + Bug(Res.drawable.icon_material_bug, Res.drawable.icon_fluent_bug, Res.drawable.icon_lucide_bug), + Check(Res.drawable.icon_material_check, Res.drawable.icon_fluent_check, Res.drawable.icon_lucide_check), + ChevronRight( + Res.drawable.icon_material_chevron_right, + Res.drawable.icon_fluent_chevron_right, + Res.drawable.icon_lucide_chevron_right, + ), + Close(Res.drawable.icon_material_close, Res.drawable.icon_fluent_close, Res.drawable.icon_lucide_close), + Code(Res.drawable.icon_material_code, Res.drawable.icon_fluent_code, Res.drawable.icon_lucide_code), + CloudOff(Res.drawable.icon_material_cloud_off, Res.drawable.icon_fluent_cloud_off, Res.drawable.icon_lucide_cloud_off), + Delete(Res.drawable.icon_material_delete, Res.drawable.icon_fluent_delete, Res.drawable.icon_lucide_delete), + Document(Res.drawable.icon_material_document, Res.drawable.icon_fluent_document, Res.drawable.icon_lucide_document), + Download(Res.drawable.icon_material_download, Res.drawable.icon_fluent_download, Res.drawable.icon_lucide_download), + File(Res.drawable.icon_material_file, Res.drawable.icon_fluent_file, Res.drawable.icon_lucide_file), + Folder(Res.drawable.icon_material_folder, Res.drawable.icon_fluent_folder, Res.drawable.icon_lucide_folder), + Globe(Res.drawable.icon_material_globe, Res.drawable.icon_fluent_globe, Res.drawable.icon_lucide_globe), + Hand(Res.drawable.icon_material_hand, Res.drawable.icon_fluent_hand, Res.drawable.icon_lucide_hand), + Info(Res.drawable.icon_material_info, Res.drawable.icon_fluent_info, Res.drawable.icon_lucide_info), + Lock(Res.drawable.icon_material_lock, Res.drawable.icon_fluent_lock, Res.drawable.icon_lucide_lock), + Megaphone(Res.drawable.icon_material_megaphone, Res.drawable.icon_fluent_megaphone, Res.drawable.icon_lucide_megaphone), + Moon(Res.drawable.icon_material_moon, Res.drawable.icon_fluent_moon, Res.drawable.icon_lucide_moon), + Nfc(Res.drawable.icon_material_nfc, Res.drawable.icon_fluent_nfc, Res.drawable.icon_lucide_nfc), + QrCode(Res.drawable.icon_material_qr_code, Res.drawable.icon_fluent_qr_code, Res.drawable.icon_lucide_qr_code), + Radio(Res.drawable.icon_material_radio, Res.drawable.icon_fluent_radio, Res.drawable.icon_lucide_radio), + Scan(Res.drawable.icon_material_scan, Res.drawable.icon_fluent_scan, Res.drawable.icon_lucide_scan), + Send(Res.drawable.icon_material_send, Res.drawable.icon_fluent_send, Res.drawable.icon_lucide_send), + Settings(Res.drawable.icon_material_settings, Res.drawable.icon_fluent_settings, Res.drawable.icon_lucide_settings), + Shield(Res.drawable.icon_material_shield, Res.drawable.icon_fluent_shield, Res.drawable.icon_lucide_shield), + ShieldCheck( + Res.drawable.icon_material_shield_check, + Res.drawable.icon_fluent_shield_check, + Res.drawable.icon_lucide_shield_check, + ), + Storage(Res.drawable.icon_material_storage, Res.drawable.icon_fluent_storage, Res.drawable.icon_lucide_storage), + Sun(Res.drawable.icon_material_sun, Res.drawable.icon_fluent_sun, Res.drawable.icon_lucide_sun), + Sync(Res.drawable.icon_material_sync, Res.drawable.icon_fluent_sync, Res.drawable.icon_lucide_sync), + SystemTheme( + Res.drawable.icon_material_system_theme, + Res.drawable.icon_fluent_system_theme, + Res.drawable.icon_lucide_system_theme, + ), + Temporary( + Res.drawable.icon_material_temporary, + Res.drawable.icon_fluent_temporary, + Res.drawable.icon_lucide_temporary, + ), + TotalStorage( + Res.drawable.icon_material_total_storage, + Res.drawable.icon_fluent_total_storage, + Res.drawable.icon_lucide_total_storage, + ), + TransferData( + Res.drawable.icon_material_transfer_data, + Res.drawable.icon_fluent_transfer_data, + Res.drawable.icon_lucide_transfer_data, + ), + User(Res.drawable.icon_material_user, Res.drawable.icon_fluent_user, Res.drawable.icon_lucide_user), + UserOff(Res.drawable.icon_material_user_off, Res.drawable.icon_fluent_user_off, Res.drawable.icon_lucide_user_off), +} + +internal enum class IconFamily { + Material, + Fluent, + Lucide, +} + +internal fun iconFamilyFor(uiPlatform: UiPlatform): IconFamily = when (uiPlatform) { + UiPlatform.Android -> IconFamily.Material + UiPlatform.Windows -> IconFamily.Fluent + UiPlatform.Linux, + UiPlatform.Desktop, + -> IconFamily.Lucide +} + +internal fun AppIcon.resourceFor(uiPlatform: UiPlatform): DrawableResource = when (iconFamilyFor(uiPlatform)) { + IconFamily.Material -> material + IconFamily.Fluent -> fluent + IconFamily.Lucide -> lucide +} + +@Composable +internal fun PlatformIcon( + icon: AppIcon, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = LocalContentColor.current, +) { + Icon( + painter = painterResource(icon.resourceFor(LocalUiPlatform.current)), + contentDescription = contentDescription, + modifier = modifier, + tint = tint, + ) +} diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppDestination.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppDestination.kt index cfa21cf..a2bc095 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppDestination.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppDestination.kt @@ -1,6 +1,6 @@ package com.vnidrop.app.ui.navigation -import androidx.compose.ui.graphics.vector.ImageVector +import com.vnidrop.app.ui.icons.AppIcon import org.jetbrains.compose.resources.StringResource import vnidrop.shared.generated.resources.Res import vnidrop.shared.generated.resources.nav_receive @@ -13,17 +13,17 @@ enum class AppDestination { Settings, } -data class NavigationItem( +internal data class NavigationItem( val destination: AppDestination, val label: StringResource, - val icon: ImageVector, + val icon: AppIcon, ) // The route list is intentionally tiny for this phase. Activity, receiver // requests, and diagnostics remain available inside screens instead of being // promoted to top-level navigation. -val primaryNavigationItems = listOf( - NavigationItem(AppDestination.Send, Res.string.nav_send, VniDropIcons.Send), - NavigationItem(AppDestination.Receive, Res.string.nav_receive, VniDropIcons.Receive), - NavigationItem(AppDestination.Settings, Res.string.nav_settings, VniDropIcons.Settings), +internal val primaryNavigationItems = listOf( + NavigationItem(AppDestination.Send, Res.string.nav_send, AppIcon.Send), + NavigationItem(AppDestination.Receive, Res.string.nav_receive, AppIcon.Download), + NavigationItem(AppDestination.Settings, Res.string.nav_settings, AppIcon.Settings), ) diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppNavigation.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppNavigation.kt index 37c55f2..1a1b416 100644 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppNavigation.kt +++ b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/AppNavigation.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem @@ -32,6 +31,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.vnidrop.app.UiPlatform import com.vnidrop.app.isDesktop +import com.vnidrop.app.ui.icons.PlatformIcon import com.vnidrop.app.ui.platform.DesktopNavigationWidthDp import com.vnidrop.app.ui.state.WindowClass import com.vnidrop.app.ui.theme.LocalVniDropColors @@ -86,7 +86,7 @@ private fun AndroidNavigationRail( NavigationRailItem( selected = item.destination == selected, onClick = { onDestinationSelected(item.destination) }, - icon = { Icon(item.icon, contentDescription = label) }, + icon = { PlatformIcon(item.icon, contentDescription = label) }, label = { Text(label, maxLines = 1, overflow = TextOverflow.Ellipsis) }, colors = NavigationRailItemDefaults.colors( selectedIconColor = colors.brandLink, @@ -152,7 +152,7 @@ private fun DesktopNavigationItem( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - Icon(item.icon, contentDescription = label, tint = if (selected) colors.brandLink else foreground, modifier = Modifier.size(20.dp)) + PlatformIcon(item.icon, contentDescription = label, tint = if (selected) colors.brandLink else foreground, modifier = Modifier.size(20.dp)) Text( text = label, color = foreground, @@ -180,7 +180,7 @@ fun AppBottomNavigation( NavigationBarItem( selected = item.destination == selected, onClick = { onDestinationSelected(item.destination) }, - icon = { Icon(item.icon, contentDescription = label, modifier = Modifier.size(24.dp)) }, + icon = { PlatformIcon(item.icon, contentDescription = label, modifier = Modifier.size(24.dp)) }, label = { Text(label, maxLines = 1, overflow = TextOverflow.Ellipsis) }, colors = NavigationBarItemDefaults.colors( selectedIconColor = colors.brandLink, diff --git a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/VniDropIcons.kt b/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/VniDropIcons.kt deleted file mode 100644 index eddae76..0000000 --- a/shared/src/commonMain/kotlin/com/vnidrop/app/ui/navigation/VniDropIcons.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.vnidrop.app.ui.navigation - -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.StrokeJoin -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.unit.dp - -object VniDropIcons { - val Send: ImageVector by lazy { - ImageVector.Builder("Send", 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = 2f, - strokeLineCap = StrokeCap.Round, - strokeLineJoin = StrokeJoin.Round, - pathFillType = PathFillType.NonZero, - ) { - moveTo(22f, 2f) - lineTo(11f, 13f) - moveTo(22f, 2f) - lineTo(15f, 22f) - lineTo(11f, 13f) - lineTo(2f, 9f) - lineTo(22f, 2f) - } - }.build() - } - - val Receive: ImageVector by lazy { - ImageVector.Builder("Receive", 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = 2f, - strokeLineCap = StrokeCap.Round, - strokeLineJoin = StrokeJoin.Round, - pathFillType = PathFillType.NonZero, - ) { - moveTo(12f, 17f) - lineTo(12f, 3f) - moveTo(6f, 11f) - lineTo(12f, 17f) - lineTo(18f, 11f) - moveTo(19f, 21f) - lineTo(5f, 21f) - } - }.build() - } - - val Settings: ImageVector by lazy { - ImageVector.Builder("Settings", 24.dp, 24.dp, 24f, 24f).apply { - path( - fill = SolidColor(Color.Transparent), - stroke = SolidColor(Color.Black), - strokeLineWidth = 2f, - strokeLineCap = StrokeCap.Round, - strokeLineJoin = StrokeJoin.Round, - pathFillType = PathFillType.NonZero, - ) { - moveTo(9.671f, 4.136f) - arcToRelative(2.34f, 2.34f, 0f, false, true, 4.659f, 0f) - arcToRelative(2.34f, 2.34f, 0f, false, false, 3.319f, 1.915f) - arcToRelative(2.34f, 2.34f, 0f, false, true, 2.33f, 4.033f) - arcToRelative(2.34f, 2.34f, 0f, false, false, 0f, 3.831f) - arcToRelative(2.34f, 2.34f, 0f, false, true, -2.33f, 4.033f) - arcToRelative(2.34f, 2.34f, 0f, false, false, -3.319f, 1.915f) - arcToRelative(2.34f, 2.34f, 0f, false, true, -4.659f, 0f) - arcToRelative(2.34f, 2.34f, 0f, false, false, -3.32f, -1.915f) - arcToRelative(2.34f, 2.34f, 0f, false, true, -2.33f, -4.033f) - arcToRelative(2.34f, 2.34f, 0f, false, false, 0f, -3.831f) - arcTo(2.34f, 2.34f, 0f, false, true, 6.35f, 6.051f) - arcToRelative(2.34f, 2.34f, 0f, false, false, 3.319f, -1.915f) - moveTo(12f, 15f) - arcTo(3f, 3f, 0f, false, true, 12f, 9f) - arcTo(3f, 3f, 0f, false, true, 12f, 15f) - } - }.build() - } -} diff --git a/shared/src/commonTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsTest.kt b/shared/src/commonTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsTest.kt new file mode 100644 index 0000000..a56ca81 --- /dev/null +++ b/shared/src/commonTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsTest.kt @@ -0,0 +1,24 @@ +package com.vnidrop.app.ui.icons + +import com.vnidrop.app.UiPlatform +import kotlin.test.Test +import kotlin.test.assertEquals + +class PlatformIconsTest { + @Test + fun iconFamiliesFollowTheRuntimePlatform() { + assertEquals(IconFamily.Material, iconFamilyFor(UiPlatform.Android)) + assertEquals(IconFamily.Fluent, iconFamilyFor(UiPlatform.Windows)) + assertEquals(IconFamily.Lucide, iconFamilyFor(UiPlatform.Linux)) + assertEquals(IconFamily.Lucide, iconFamilyFor(UiPlatform.Desktop)) + } + + @Test + fun everySemanticIconResolvesToItsPlatformResource() { + AppIcon.entries.forEach { icon -> + assertEquals(icon.material, icon.resourceFor(UiPlatform.Android), icon.name) + assertEquals(icon.fluent, icon.resourceFor(UiPlatform.Windows), icon.name) + assertEquals(icon.lucide, icon.resourceFor(UiPlatform.Linux), icon.name) + } + } +} diff --git a/shared/src/jvmTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsComposeTest.kt b/shared/src/jvmTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsComposeTest.kt new file mode 100644 index 0000000..0e2cd40 --- /dev/null +++ b/shared/src/jvmTest/kotlin/com/vnidrop/app/ui/icons/PlatformIconsComposeTest.kt @@ -0,0 +1,52 @@ +package com.vnidrop.app.ui.icons + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.v2.runComposeUiTest +import androidx.compose.ui.unit.dp +import com.vnidrop.app.UiPlatform +import com.vnidrop.app.ui.platform.LocalUiPlatform +import com.vnidrop.app.ui.theme.VniDropTheme +import kotlin.test.Test + +@OptIn(ExperimentalTestApi::class) +class PlatformIconsComposeTest { + @Test + fun everyPlatformIconResourceRenders() = runComposeUiTest { + val platforms = listOf(UiPlatform.Android, UiPlatform.Windows, UiPlatform.Linux) + setContent { + VniDropTheme(isDarkTheme = false) { + Column { + platforms.forEach { platform -> + CompositionLocalProvider(LocalUiPlatform provides platform) { + AppIcon.entries.chunked(10).forEach { icons -> + Row { + icons.forEach { icon -> + PlatformIcon( + icon = icon, + contentDescription = null, + modifier = Modifier.size(24.dp).testTag("${platform.name}-${icon.name}"), + ) + } + } + } + } + } + } + } + } + + platforms.forEach { platform -> + AppIcon.entries.forEach { icon -> + onNodeWithTag("${platform.name}-${icon.name}").assertIsDisplayed() + } + } + } +} diff --git a/shared/tools/import_platform_icons.py b/shared/tools/import_platform_icons.py new file mode 100644 index 0000000..4dc0978 --- /dev/null +++ b/shared/tools/import_platform_icons.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +"""Import the curated platform icon set as Compose vector resources.""" + +from __future__ import annotations + +import re +import subprocess +import urllib.parse +import xml.etree.ElementTree as ET +from dataclasses import dataclass +from pathlib import Path + + +MATERIAL_REVISION = "abd7f5c0e179c83f068c770650bd14ebac5d5a09" +FLUENT_REVISION = "3cc5907ff2b187df22c6c711e8d0a96da41debf8" +LUCIDE_REVISION = "4e2efb9350fac7dbcb94caae9ccac5654bdcc050" + +ANDROID_NS = "http://schemas.android.com/apk/res/android" +ET.register_namespace("android", ANDROID_NS) + + +@dataclass(frozen=True) +class IconSource: + name: str + material: str + fluent_directory: str + fluent_file: str + lucide: str + + +ICONS = ( + IconSource("add", "add", "Add", "add", "plus"), + IconSource("arrow_back", "arrow_back", "Arrow Left", "arrow_left", "arrow-left"), + IconSource("bell", "notifications", "Alert", "alert", "bell"), + IconSource("bug", "bug_report", "Bug", "bug", "bug"), + IconSource("check", "check", "Checkmark", "checkmark", "check"), + IconSource("chevron_right", "chevron_right", "Chevron Right", "chevron_right", "chevron-right"), + IconSource("close", "close", "Dismiss", "dismiss", "x"), + IconSource("code", "code", "Code", "code", "code-xml"), + IconSource("cloud_off", "cloud_off", "Cloud Off", "cloud_off", "cloud-off"), + IconSource("delete", "delete", "Delete", "delete", "trash-2"), + IconSource("document", "description", "Document", "document", "file-text"), + IconSource("download", "download", "Arrow Download", "arrow_download", "download"), + IconSource("file", "draft", "Document", "document", "file"), + IconSource("folder", "folder", "Folder", "folder", "folder"), + IconSource("globe", "language", "Globe", "globe", "globe"), + IconSource("hand", "back_hand", "Hand Right", "hand_right", "hand"), + IconSource("info", "info", "Info", "info", "info"), + IconSource("lock", "lock", "Lock Closed", "lock_closed", "lock"), + IconSource("megaphone", "campaign", "Megaphone", "megaphone", "megaphone"), + IconSource("moon", "dark_mode", "Weather Moon", "weather_moon", "moon"), + IconSource("nfc", "nfc", "Tap Double", "tap_double", "nfc"), + IconSource("qr_code", "qr_code_scanner", "QR Code", "qr_code", "qr-code"), + IconSource("radio", "cell_tower", "Cellular Data 1", "cellular_data_1", "radio-tower"), + IconSource("scan", "document_scanner", "Scan Type", "scan_type", "scan-line"), + IconSource("send", "send", "Send", "send", "send"), + IconSource("settings", "settings", "Settings", "settings", "settings"), + IconSource("shield", "shield", "Shield", "shield", "shield"), + IconSource("shield_check", "verified_user", "Shield Checkmark", "shield_checkmark", "shield-check"), + IconSource("storage", "database", "Database", "database", "database"), + IconSource("sun", "light_mode", "Weather Sunny", "weather_sunny", "sun"), + IconSource("sync", "sync", "Arrow Sync", "arrow_sync", "refresh-cw"), + IconSource("system_theme", "devices", "Desktop", "desktop", "monitor-cog"), + IconSource("temporary", "schedule", "Clock", "clock", "timer-reset"), + IconSource("total_storage", "data_usage", "Data Pie", "data_pie", "chart-pie"), + IconSource("transfer_data", "inventory_2", "Archive", "archive", "package"), + IconSource("user", "account_circle", "Person Circle", "person_circle", "circle-user-round"), + IconSource("user_off", "person_off", "Person Prohibited", "person_prohibited", "user-round-x"), +) + +ROOT = Path(__file__).resolve().parents[1] +DRAWABLES = ROOT / "src/commonMain/composeResources/drawable" +LICENSES = ROOT / "src/commonMain/composeResources/files/icon-licenses" + + +def fetch(url: str) -> bytes: + return subprocess.run( + ["curl", "--fail", "--location", "--silent", "--show-error", url], + check=True, + capture_output=True, + ).stdout + + +def android_attr(name: str) -> str: + return f"{{{ANDROID_NS}}}{name}" + + +def write_vector(name: str, family: str, vector: ET.Element) -> None: + vector.insert(0, ET.Comment(f" {family} icon imported by shared/tools/import_platform_icons.py. ")) + ET.indent(vector, space=" ") + data = ET.tostring(vector, encoding="unicode", xml_declaration=True) + (DRAWABLES / f"icon_{family}_{name}.xml").write_text(data + "\n", encoding="utf-8") + + +def import_material(icon: IconSource) -> None: + url = ( + "https://raw.githubusercontent.com/google/material-design-icons/" + f"{MATERIAL_REVISION}/symbols/android/{icon.material}/materialsymbolsrounded/" + f"{icon.material}_24px.xml" + ) + vector = ET.fromstring(fetch(url)) + vector.attrib.pop(android_attr("tint"), None) + for path in vector.iter("path"): + path.set(android_attr("fillColor"), "#FF000000") + write_vector(icon.name, "material", vector) + + +def import_fluent(icon: IconSource) -> None: + directory = urllib.parse.quote(icon.fluent_directory) + url = ( + "https://raw.githubusercontent.com/microsoft/fluentui-system-icons/" + f"{FLUENT_REVISION}/assets/{directory}/SVG/" + f"ic_fluent_{icon.fluent_file}_24_regular.svg" + ) + svg = ET.fromstring(fetch(url)) + view_box = [float(value) for value in svg.attrib["viewBox"].split()] + vector = vector_root(view_box[2], view_box[3]) + for element in svg.iter(): + if element.tag.rsplit("}", 1)[-1] != "path": + continue + path = ET.SubElement(vector, "path") + path.set(android_attr("pathData"), element.attrib["d"]) + path.set(android_attr("fillColor"), "#FF000000") + if element.attrib.get("fill-rule") == "evenodd": + path.set(android_attr("fillType"), "evenOdd") + write_vector(icon.name, "fluent", vector) + + +def clean_number(value: str | float) -> str: + value = float(value) + return str(int(value)) if value.is_integer() else str(value) + + +def points_path(points: str, close: bool) -> str: + numbers = re.findall(r"-?\d+(?:\.\d+)?", points) + pairs = list(zip(numbers[0::2], numbers[1::2])) + commands = [f"M {x} {y}" if index == 0 else f"L {x} {y}" for index, (x, y) in enumerate(pairs)] + if close: + commands.append("Z") + return " ".join(commands) + + +def primitive_path(element: ET.Element) -> str | None: + tag = element.tag.rsplit("}", 1)[-1] + attributes = element.attrib + if tag == "path": + return attributes["d"] + if tag == "line": + return f"M {attributes['x1']} {attributes['y1']} L {attributes['x2']} {attributes['y2']}" + if tag == "polyline": + return points_path(attributes["points"], close=False) + if tag == "polygon": + return points_path(attributes["points"], close=True) + if tag in {"circle", "ellipse"}: + cx = float(attributes["cx"]) + cy = float(attributes["cy"]) + rx = float(attributes.get("r", attributes.get("rx", "0"))) + ry = float(attributes.get("r", attributes.get("ry", "0"))) + return ( + f"M {clean_number(cx + rx)} {clean_number(cy)} " + f"A {clean_number(rx)} {clean_number(ry)} 0 1 0 {clean_number(cx - rx)} {clean_number(cy)} " + f"A {clean_number(rx)} {clean_number(ry)} 0 1 0 {clean_number(cx + rx)} {clean_number(cy)}" + ) + if tag == "rect": + x = float(attributes.get("x", "0")) + y = float(attributes.get("y", "0")) + width = float(attributes["width"]) + height = float(attributes["height"]) + radius = float(attributes.get("rx", "0")) + if radius == 0: + return f"M {clean_number(x)} {clean_number(y)} h {clean_number(width)} v {clean_number(height)} h -{clean_number(width)} Z" + return ( + f"M {clean_number(x + radius)} {clean_number(y)} " + f"H {clean_number(x + width - radius)} A {clean_number(radius)} {clean_number(radius)} 0 0 1 {clean_number(x + width)} {clean_number(y + radius)} " + f"V {clean_number(y + height - radius)} A {clean_number(radius)} {clean_number(radius)} 0 0 1 {clean_number(x + width - radius)} {clean_number(y + height)} " + f"H {clean_number(x + radius)} A {clean_number(radius)} {clean_number(radius)} 0 0 1 {clean_number(x)} {clean_number(y + height - radius)} " + f"V {clean_number(y + radius)} A {clean_number(radius)} {clean_number(radius)} 0 0 1 {clean_number(x + radius)} {clean_number(y)} Z" + ) + return None + + +def import_lucide(icon: IconSource) -> None: + url = ( + "https://raw.githubusercontent.com/lucide-icons/lucide/" + f"{LUCIDE_REVISION}/icons/{icon.lucide}.svg" + ) + svg = ET.fromstring(fetch(url)) + view_box = [float(value) for value in svg.attrib["viewBox"].split()] + vector = vector_root(view_box[2], view_box[3]) + for element in svg.iter(): + path_data = primitive_path(element) + if path_data is None: + continue + path = ET.SubElement(vector, "path") + path.set(android_attr("pathData"), path_data) + path.set(android_attr("fillColor"), "#00000000") + path.set(android_attr("strokeColor"), "#FF000000") + path.set(android_attr("strokeWidth"), svg.attrib.get("stroke-width", "2")) + path.set(android_attr("strokeLineCap"), svg.attrib.get("stroke-linecap", "round")) + path.set(android_attr("strokeLineJoin"), svg.attrib.get("stroke-linejoin", "round")) + write_vector(icon.name, "lucide", vector) + + +def vector_root(width: float, height: float) -> ET.Element: + return ET.Element( + "vector", + { + android_attr("width"): "24dp", + android_attr("height"): "24dp", + android_attr("viewportWidth"): clean_number(width), + android_attr("viewportHeight"): clean_number(height), + }, + ) + + +def import_licenses() -> None: + licenses = { + "material-symbols-apache-2.0.txt": ( + "google/material-design-icons", + MATERIAL_REVISION, + "LICENSE", + ), + "fluent-system-icons-mit.txt": ( + "microsoft/fluentui-system-icons", + FLUENT_REVISION, + "LICENSE", + ), + "lucide-isc.txt": ("lucide-icons/lucide", LUCIDE_REVISION, "LICENSE"), + } + LICENSES.mkdir(parents=True, exist_ok=True) + for filename, (repository, revision, source_file) in licenses.items(): + url = f"https://raw.githubusercontent.com/{repository}/{revision}/{source_file}" + LICENSES.joinpath(filename).write_bytes(fetch(url)) + + +def main() -> None: + DRAWABLES.mkdir(parents=True, exist_ok=True) + for icon in ICONS: + import_material(icon) + import_fluent(icon) + import_lucide(icon) + import_licenses() + + +if __name__ == "__main__": + main()