diff --git a/appimage/AppRun b/appimage/AppRun
index 95b7c05..6eccc8d 100755
--- a/appimage/AppRun
+++ b/appimage/AppRun
@@ -1,4 +1,4 @@
#!/bin/sh
cd "$(dirname "$0")"
-exec ./fluffychat
\ No newline at end of file
+exec ./extera_next
diff --git a/appimage/Extera.AppDir/.DirIcon b/appimage/Extera.AppDir/.DirIcon
new file mode 120000
index 0000000..483c081
--- /dev/null
+++ b/appimage/Extera.AppDir/.DirIcon
@@ -0,0 +1 @@
+extera.svg
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/AppRun b/appimage/Extera.AppDir/AppRun
new file mode 100755
index 0000000..6eccc8d
--- /dev/null
+++ b/appimage/Extera.AppDir/AppRun
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd "$(dirname "$0")"
+exec ./extera_next
diff --git a/appimage/FluffyChat.desktop b/appimage/Extera.AppDir/Extera.desktop
similarity index 59%
rename from appimage/FluffyChat.desktop
rename to appimage/Extera.AppDir/Extera.desktop
index ceee4c9..81cabe1 100644
--- a/appimage/FluffyChat.desktop
+++ b/appimage/Extera.AppDir/Extera.desktop
@@ -1,9 +1,9 @@
[Desktop Entry]
Type=Application
Version=1.0
-Name=FluffyChat
+Name=Extera Next
Comment=Matrix Client. Chat with your friends
Exec=AppRun
-Icon=fluffychat
+Icon=extera
Terminal=false
-Categories=Network;Chat;InstantMessaging;X-Matrix;
\ No newline at end of file
+Categories=Network;Chat;InstantMessaging;X-Matrix;
diff --git a/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.bin b/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.bin
new file mode 100644
index 0000000..7b2603b
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.bin
@@ -0,0 +1 @@
+
assets/banner.png
assetassets/banner.pngassets/banner_transparent.png
assetassets/banner_transparent.pngassets/favicon.png
assetassets/favicon.pngassets/info-logo.png
assetassets/info-logo.pngassets/js/olm.zip
assetassets/js/olm.zipassets/logo.png
assetassets/logo.pngassets/logo.svg
assetassets/logo.svgassets/logo_transparent.png
assetassets/logo_transparent.pngassets/sas-emoji.json
assetassets/sas-emoji.jsonassets/sounds/call.ogg
assetassets/sounds/call.oggassets/sounds/notification.ogg
assetassets/sounds/notification.oggassets/sounds/phone.ogg
assetassets/sounds/phone.ogg2packages/cupertino_icons/assets/CupertinoIcons.ttf
asset2packages/cupertino_icons/assets/CupertinoIcons.ttf4packages/flutter_map/lib/assets/flutter_map_logo.png
asset4packages/flutter_map/lib/assets/flutter_map_logo.png2packages/handy_window/assets/handy-window-dark.css
asset2packages/handy_window/assets/handy-window-dark.css-packages/handy_window/assets/handy-window.css
asset-packages/handy_window/assets/handy-window.css(packages/material/lib/fonts/material.ttf
asset(packages/material/lib/fonts/material.ttf7packages/record_web/assets/js/record.fixwebmduration.js
asset7packages/record_web/assets/js/record.fixwebmduration.js/packages/record_web/assets/js/record.worklet.js
asset/packages/record_web/assets/js/record.worklet.js)packages/wakelock_plus/assets/no_sleep.js
asset)packages/wakelock_plus/assets/no_sleep.js
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.json b/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.json
new file mode 100644
index 0000000..7dfe5ad
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/AssetManifest.json
@@ -0,0 +1 @@
+{"assets/banner.png":["assets/banner.png"],"assets/banner_transparent.png":["assets/banner_transparent.png"],"assets/favicon.png":["assets/favicon.png"],"assets/info-logo.png":["assets/info-logo.png"],"assets/js/olm.zip":["assets/js/olm.zip"],"assets/logo.png":["assets/logo.png"],"assets/logo.svg":["assets/logo.svg"],"assets/logo_transparent.png":["assets/logo_transparent.png"],"assets/sas-emoji.json":["assets/sas-emoji.json"],"assets/sounds/call.ogg":["assets/sounds/call.ogg"],"assets/sounds/notification.ogg":["assets/sounds/notification.ogg"],"assets/sounds/phone.ogg":["assets/sounds/phone.ogg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"],"packages/handy_window/assets/handy-window-dark.css":["packages/handy_window/assets/handy-window-dark.css"],"packages/handy_window/assets/handy-window.css":["packages/handy_window/assets/handy-window.css"],"packages/material/lib/fonts/material.ttf":["packages/material/lib/fonts/material.ttf"],"packages/record_web/assets/js/record.fixwebmduration.js":["packages/record_web/assets/js/record.fixwebmduration.js"],"packages/record_web/assets/js/record.worklet.js":["packages/record_web/assets/js/record.worklet.js"],"packages/wakelock_plus/assets/no_sleep.js":["packages/wakelock_plus/assets/no_sleep.js"]}
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/FontManifest.json b/appimage/Extera.AppDir/data/flutter_assets/FontManifest.json
new file mode 100644
index 0000000..9899cce
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/FontManifest.json
@@ -0,0 +1 @@
+[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"packages/material/Material","fonts":[{"asset":"packages/material/lib/fonts/material.ttf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}]
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/NOTICES.Z b/appimage/Extera.AppDir/data/flutter_assets/NOTICES.Z
new file mode 100644
index 0000000..4855464
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/NOTICES.Z differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/NativeAssetsManifest.json b/appimage/Extera.AppDir/data/flutter_assets/NativeAssetsManifest.json
new file mode 100644
index 0000000..523bfc7
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/NativeAssetsManifest.json
@@ -0,0 +1 @@
+{"format-version":[1,0,0],"native-assets":{}}
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/banner.png b/appimage/Extera.AppDir/data/flutter_assets/assets/banner.png
new file mode 100644
index 0000000..8e1bb36
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/banner.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/banner_transparent.png b/appimage/Extera.AppDir/data/flutter_assets/assets/banner_transparent.png
new file mode 100644
index 0000000..8e1bb36
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/banner_transparent.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/favicon.png b/appimage/Extera.AppDir/data/flutter_assets/assets/favicon.png
new file mode 100644
index 0000000..61d0656
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/favicon.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/info-logo.png b/appimage/Extera.AppDir/data/flutter_assets/assets/info-logo.png
new file mode 100644
index 0000000..61d0656
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/info-logo.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/js/olm.zip b/appimage/Extera.AppDir/data/flutter_assets/assets/js/olm.zip
new file mode 100644
index 0000000..8537307
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/assets/js/olm.zip
@@ -0,0 +1 @@
+Not Found
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/logo.png b/appimage/Extera.AppDir/data/flutter_assets/assets/logo.png
new file mode 100644
index 0000000..61d0656
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/logo.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/logo.svg b/appimage/Extera.AppDir/data/flutter_assets/assets/logo.svg
new file mode 100644
index 0000000..767a86a
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/assets/logo.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/logo_transparent.png b/appimage/Extera.AppDir/data/flutter_assets/assets/logo_transparent.png
new file mode 100644
index 0000000..61d0656
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/logo_transparent.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/sas-emoji.json b/appimage/Extera.AppDir/data/flutter_assets/assets/sas-emoji.json
new file mode 100644
index 0000000..f0eb702
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/assets/sas-emoji.json
@@ -0,0 +1,2178 @@
+[
+ {
+ "number": 0,
+ "emoji": "🐶",
+ "description": "Dog",
+ "unicode": "U+1F436",
+ "translated_descriptions": {
+ "ar": "كَلب",
+ "bg": "Куче",
+ "ca": "Gos",
+ "cs": "Pes",
+ "de": "Hund",
+ "eo": "Hundo",
+ "es": "Perro",
+ "et": "Koer",
+ "fi": "Koira",
+ "fr": "Chien",
+ "hr": "pas",
+ "hu": "Kutya",
+ "it": "Cane",
+ "ja": "犬",
+ "nb_NO": "Hund",
+ "nl": "Hond",
+ "pt_BR": "Cachorro",
+ "ru": "Собака",
+ "si": "බල්ලා",
+ "sk": "Hlava psa",
+ "sr": "пас",
+ "sv": "Hund",
+ "szl": null,
+ "tzm": "Aydi",
+ "uk": "Пес",
+ "zh_Hans": "狗"
+ }
+ },
+ {
+ "number": 1,
+ "emoji": "🐱",
+ "description": "Cat",
+ "unicode": "U+1F431",
+ "translated_descriptions": {
+ "ar": "هِرَّة",
+ "bg": "Котка",
+ "ca": "Gat",
+ "cs": "Kočka",
+ "de": "Katze",
+ "eo": "Kato",
+ "es": "Gato",
+ "et": "Kass",
+ "fi": "Kissa",
+ "fr": "Chat",
+ "hr": "mačka",
+ "hu": "Macska",
+ "it": "Gatto",
+ "ja": "猫",
+ "nb_NO": "Katt",
+ "nl": "Kat",
+ "pt_BR": "Gato",
+ "ru": "Кошка",
+ "si": "පූසා",
+ "sk": "Hlava mačky",
+ "sr": "мачка",
+ "sv": "Katt",
+ "szl": null,
+ "tzm": "Amuc",
+ "uk": "Кіт",
+ "zh_Hans": "猫"
+ }
+ },
+ {
+ "number": 2,
+ "emoji": "🦁",
+ "description": "Lion",
+ "unicode": "U+1F981",
+ "translated_descriptions": {
+ "ar": "أَسَد",
+ "bg": "Лъв",
+ "ca": "Lleó",
+ "cs": "Lev",
+ "de": "Löwe",
+ "eo": "Leono",
+ "es": "León",
+ "et": "Lõvi",
+ "fi": "Leijona",
+ "fr": "Lion",
+ "hr": "lav",
+ "hu": "Oroszlán",
+ "it": "Leone",
+ "ja": "ライオン",
+ "nb_NO": "Løve",
+ "nl": "Leeuw",
+ "pt_BR": "Leão",
+ "ru": "Лев",
+ "si": "සිංහයා",
+ "sk": "Hlava leva",
+ "sr": "лав",
+ "sv": "Lejon",
+ "szl": null,
+ "tzm": "Izem",
+ "uk": "Лев",
+ "zh_Hans": "狮子"
+ }
+ },
+ {
+ "number": 3,
+ "emoji": "🐎",
+ "description": "Horse",
+ "unicode": "U+1F40E",
+ "translated_descriptions": {
+ "ar": "حِصَان",
+ "bg": "Кон",
+ "ca": "Cavall",
+ "cs": "Kůň",
+ "de": "Pferd",
+ "eo": "Ĉevalo",
+ "es": "Caballo",
+ "et": "Hobune",
+ "fi": "Hevonen",
+ "fr": "Cheval",
+ "hr": "konj",
+ "hu": "Ló",
+ "it": "Cavallo",
+ "ja": "馬",
+ "nb_NO": "Hest",
+ "nl": "Paard",
+ "pt_BR": "Cavalo",
+ "ru": "Лошадь",
+ "si": "අශ්වයා",
+ "sk": "Kôň",
+ "sr": "коњ",
+ "sv": "Häst",
+ "szl": null,
+ "tzm": "Ayyis",
+ "uk": "Кінь",
+ "zh_Hans": "马"
+ }
+ },
+ {
+ "number": 4,
+ "emoji": "🦄",
+ "description": "Unicorn",
+ "unicode": "U+1F984",
+ "translated_descriptions": {
+ "ar": "حِصَانٌ بِقَرن",
+ "bg": "Еднорог",
+ "ca": "Unicorn",
+ "cs": "Jednorožec",
+ "de": "Einhorn",
+ "eo": "Unukorno",
+ "es": "Unicornio",
+ "et": "Ükssarvik",
+ "fi": "Yksisarvinen",
+ "fr": "Licorne",
+ "hr": "jednorog",
+ "hu": "Egyszarvú",
+ "it": "Unicorno",
+ "ja": "ユニコーン",
+ "nb_NO": "Enhjørning",
+ "nl": "Eenhoorn",
+ "pt_BR": "Unicórnio",
+ "ru": "Единорог",
+ "si": null,
+ "sk": "Hlava jednorožca",
+ "sr": "једнорог",
+ "sv": "Enhörning",
+ "szl": null,
+ "tzm": null,
+ "uk": "Єдиноріг",
+ "zh_Hans": "独角兽"
+ }
+ },
+ {
+ "number": 5,
+ "emoji": "🐷",
+ "description": "Pig",
+ "unicode": "U+1F437",
+ "translated_descriptions": {
+ "ar": "خِنزِير",
+ "bg": "Прасе",
+ "ca": "Porc",
+ "cs": "Prase",
+ "de": "Schwein",
+ "eo": "Porko",
+ "es": "Cerdo",
+ "et": "Siga",
+ "fi": "Sika",
+ "fr": "Cochon",
+ "hr": "svinja",
+ "hu": "Malac",
+ "it": "Maiale",
+ "ja": "ブタ",
+ "nb_NO": "Gris",
+ "nl": "Varken",
+ "pt_BR": "Porco",
+ "ru": "Свинья",
+ "si": null,
+ "sk": "Hlava prasaťa",
+ "sr": "прасе",
+ "sv": "Gris",
+ "szl": null,
+ "tzm": "Ilef",
+ "uk": "Свиня",
+ "zh_Hans": "猪"
+ }
+ },
+ {
+ "number": 6,
+ "emoji": "🐘",
+ "description": "Elephant",
+ "unicode": "U+1F418",
+ "translated_descriptions": {
+ "ar": "فِيل",
+ "bg": "Слон",
+ "ca": "Elefant",
+ "cs": "Slon",
+ "de": "Elefant",
+ "eo": "Elefanto",
+ "es": "Elefante",
+ "et": "Elevant",
+ "fi": "Norsu",
+ "fr": "Éléphant",
+ "hr": "slon",
+ "hu": "Elefánt",
+ "it": "Elefante",
+ "ja": "ゾウ",
+ "nb_NO": "Elefant",
+ "nl": "Olifant",
+ "pt_BR": "Elefante",
+ "ru": "Слон",
+ "si": null,
+ "sk": "Slon",
+ "sr": "слон",
+ "sv": "Elefant",
+ "szl": null,
+ "tzm": "Ilu",
+ "uk": "Слон",
+ "zh_Hans": "大象"
+ }
+ },
+ {
+ "number": 7,
+ "emoji": "🐰",
+ "description": "Rabbit",
+ "unicode": "U+1F430",
+ "translated_descriptions": {
+ "ar": "أَرنَب",
+ "bg": "Заек",
+ "ca": "Conill",
+ "cs": "Králík",
+ "de": "Hase",
+ "eo": "Kuniklo",
+ "es": "Conejo",
+ "et": "Jänes",
+ "fi": "Kani",
+ "fr": "Lapin",
+ "hr": "zec",
+ "hu": "Nyúl",
+ "it": "Coniglio",
+ "ja": "うさぎ",
+ "nb_NO": "Kanin",
+ "nl": "Konijn",
+ "pt_BR": "Coelho",
+ "ru": "Кролик",
+ "si": null,
+ "sk": "Hlava zajaca",
+ "sr": "зец",
+ "sv": "Kanin",
+ "szl": null,
+ "tzm": "Agnin",
+ "uk": "Кріль",
+ "zh_Hans": "兔子"
+ }
+ },
+ {
+ "number": 8,
+ "emoji": "🐼",
+ "description": "Panda",
+ "unicode": "U+1F43C",
+ "translated_descriptions": {
+ "ar": "باندَا",
+ "bg": "Панда",
+ "ca": "Panda",
+ "cs": "Panda",
+ "de": "Panda",
+ "eo": "Pando",
+ "es": "Panda",
+ "et": "Panda",
+ "fi": "Panda",
+ "fr": "Panda",
+ "hr": "panda",
+ "hu": "Panda",
+ "it": "Panda",
+ "ja": "パンダ",
+ "nb_NO": "Panda",
+ "nl": "Panda",
+ "pt_BR": "Panda",
+ "ru": "Панда",
+ "si": null,
+ "sk": "Hlava pandy",
+ "sr": "панда",
+ "sv": "Panda",
+ "szl": null,
+ "tzm": null,
+ "uk": "Панда",
+ "zh_Hans": "熊猫"
+ }
+ },
+ {
+ "number": 9,
+ "emoji": "🐓",
+ "description": "Rooster",
+ "unicode": "U+1F413",
+ "translated_descriptions": {
+ "ar": "دِيك",
+ "bg": "Петел",
+ "ca": "Gall",
+ "cs": "Kohout",
+ "de": "Hahn",
+ "eo": "Virkoko",
+ "es": "Gallo",
+ "et": "Kukk",
+ "fi": "Kukko",
+ "fr": "Coq",
+ "hr": "kokot",
+ "hu": "Kakas",
+ "it": "Gallo",
+ "ja": "ニワトリ",
+ "nb_NO": "Hane",
+ "nl": "Haan",
+ "pt_BR": "Galo",
+ "ru": "Петух",
+ "si": null,
+ "sk": "Kohút",
+ "sr": "петао",
+ "sv": "Tupp",
+ "szl": null,
+ "tzm": "Ayaẓiḍ",
+ "uk": "Когут",
+ "zh_Hans": "公鸡"
+ }
+ },
+ {
+ "number": 10,
+ "emoji": "🐧",
+ "description": "Penguin",
+ "unicode": "U+1F427",
+ "translated_descriptions": {
+ "ar": "بِطريق",
+ "bg": "Пингвин",
+ "ca": "Pingüí",
+ "cs": "Tučňák",
+ "de": "Pinguin",
+ "eo": "Pingveno",
+ "es": "Pingüino",
+ "et": "Pingviin",
+ "fi": "Pingviini",
+ "fr": "Manchot",
+ "hr": "pingvin",
+ "hu": "Pingvin",
+ "it": "Pinguino",
+ "ja": "ペンギン",
+ "nb_NO": "Pingvin",
+ "nl": "Pinguïn",
+ "pt_BR": "Pinguim",
+ "ru": "Пингвин",
+ "si": null,
+ "sk": "Tučniak",
+ "sr": "пингвин",
+ "sv": "Pingvin",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пінгвін",
+ "zh_Hans": "企鹅"
+ }
+ },
+ {
+ "number": 11,
+ "emoji": "🐢",
+ "description": "Turtle",
+ "unicode": "U+1F422",
+ "translated_descriptions": {
+ "ar": "سُلحفاة",
+ "bg": "Костенурка",
+ "ca": "Tortuga",
+ "cs": "Želva",
+ "de": "Schildkröte",
+ "eo": "Testudo",
+ "es": "Tortuga",
+ "et": "Kilpkonn",
+ "fi": "Kilpikonna",
+ "fr": "Tortue",
+ "hr": "kornjača",
+ "hu": "Teknős",
+ "it": "Tartaruga",
+ "ja": "亀",
+ "nb_NO": "Skilpadde",
+ "nl": "Schildpad",
+ "pt_BR": "Tartaruga",
+ "ru": "Черепаха",
+ "si": null,
+ "sk": "Korytnačka",
+ "sr": "корњача",
+ "sv": "Sköldpadda",
+ "szl": null,
+ "tzm": "Ifker",
+ "uk": "Черепаха",
+ "zh_Hans": "乌龟"
+ }
+ },
+ {
+ "number": 12,
+ "emoji": "🐟",
+ "description": "Fish",
+ "unicode": "U+1F41F",
+ "translated_descriptions": {
+ "ar": "سَمَكَة",
+ "bg": "Риба",
+ "ca": "Peix",
+ "cs": "Ryba",
+ "de": "Fisch",
+ "eo": "Fiŝo",
+ "es": "Pez",
+ "et": "Kala",
+ "fi": "Kala",
+ "fr": "Poisson",
+ "hr": "riba",
+ "hu": "Hal",
+ "it": "Pesce",
+ "ja": "魚",
+ "nb_NO": "Fisk",
+ "nl": "Vis",
+ "pt_BR": "Peixe",
+ "ru": "Рыба",
+ "si": null,
+ "sk": "Ryba",
+ "sr": "риба",
+ "sv": "Fisk",
+ "szl": null,
+ "tzm": "Aselm",
+ "uk": "Риба",
+ "zh_Hans": "鱼"
+ }
+ },
+ {
+ "number": 13,
+ "emoji": "🐙",
+ "description": "Octopus",
+ "unicode": "U+1F419",
+ "translated_descriptions": {
+ "ar": "أُخطُبُوط",
+ "bg": "Октопод",
+ "ca": "Pop",
+ "cs": "Chobotnice",
+ "de": "Oktopus",
+ "eo": "Polpo",
+ "es": "Pulpo",
+ "et": "Kaheksajalg",
+ "fi": "Tursas",
+ "fr": "Poulpe",
+ "hr": "hobotnica",
+ "hu": "Polip",
+ "it": "Polpo",
+ "ja": "たこ",
+ "nb_NO": "Blekksprut",
+ "nl": "Octopus",
+ "pt_BR": "Polvo",
+ "ru": "Осьминог",
+ "si": null,
+ "sk": "Chobotnica",
+ "sr": "октопод",
+ "sv": "Bläckfisk",
+ "szl": null,
+ "tzm": null,
+ "uk": "Восьминіг",
+ "zh_Hans": "章鱼"
+ }
+ },
+ {
+ "number": 14,
+ "emoji": "🦋",
+ "description": "Butterfly",
+ "unicode": "U+1F98B",
+ "translated_descriptions": {
+ "ar": "فَرَاشَة",
+ "bg": "Пеперуда",
+ "ca": "Papallona",
+ "cs": "Motýl",
+ "de": "Schmetterling",
+ "eo": "Papilio",
+ "es": "Mariposa",
+ "et": "Liblikas",
+ "fi": "Perhonen",
+ "fr": "Papillon",
+ "hr": "leptir",
+ "hu": "Pillangó",
+ "it": "Farfalla",
+ "ja": "ちょうちょ",
+ "nb_NO": "Sommerfugl",
+ "nl": "Vlinder",
+ "pt_BR": "Borboleta",
+ "ru": "Бабочка",
+ "si": null,
+ "sk": "Motýľ",
+ "sr": "лептир",
+ "sv": "Fjäril",
+ "szl": null,
+ "tzm": null,
+ "uk": "Метелик",
+ "zh_Hans": "蝴蝶"
+ }
+ },
+ {
+ "number": 15,
+ "emoji": "🌷",
+ "description": "Flower",
+ "unicode": "U+1F337",
+ "translated_descriptions": {
+ "ar": "زَهرَة",
+ "bg": "Цвете",
+ "ca": "Flor",
+ "cs": "Květina",
+ "de": "Blume",
+ "eo": "Floro",
+ "es": "Flor",
+ "et": "Lill",
+ "fi": "Kukka",
+ "fr": "Fleur",
+ "hr": "svijet",
+ "hu": "Virág",
+ "it": "Fiore",
+ "ja": "花",
+ "nb_NO": "Blomst",
+ "nl": "Bloem",
+ "pt_BR": "Flor",
+ "ru": "Цветок",
+ "si": null,
+ "sk": "Tulipán",
+ "sr": "цвет",
+ "sv": "Blomma",
+ "szl": null,
+ "tzm": null,
+ "uk": "Квітка",
+ "zh_Hans": "花"
+ }
+ },
+ {
+ "number": 16,
+ "emoji": "🌳",
+ "description": "Tree",
+ "unicode": "U+1F333",
+ "translated_descriptions": {
+ "ar": "شَجَرَة",
+ "bg": "Дърво",
+ "ca": "Arbre",
+ "cs": "Strom",
+ "de": "Baum",
+ "eo": "Arbo",
+ "es": "Árbol",
+ "et": "Puu",
+ "fi": "Puu",
+ "fr": "Arbre",
+ "hr": "drvo",
+ "hu": "Fa",
+ "it": "Albero",
+ "ja": "木",
+ "nb_NO": "Tre",
+ "nl": "Boom",
+ "pt_BR": "Árvore",
+ "ru": "Дерево",
+ "si": null,
+ "sk": "Listnatý strom",
+ "sr": "дрво",
+ "sv": "Träd",
+ "szl": null,
+ "tzm": "Aseklu",
+ "uk": "Дерево",
+ "zh_Hans": "树"
+ }
+ },
+ {
+ "number": 17,
+ "emoji": "🌵",
+ "description": "Cactus",
+ "unicode": "U+1F335",
+ "translated_descriptions": {
+ "ar": "صبار",
+ "bg": "Кактус",
+ "ca": "Cactus",
+ "cs": "Kaktus",
+ "de": "Kaktus",
+ "eo": "Kakto",
+ "es": "Cactus",
+ "et": "Kaktus",
+ "fi": "Kaktus",
+ "fr": "Cactus",
+ "hr": "kaktus",
+ "hu": "Kaktusz",
+ "it": "Cactus",
+ "ja": "サボテン",
+ "nb_NO": "Kaktus",
+ "nl": "Cactus",
+ "pt_BR": "Cacto",
+ "ru": "Кактус",
+ "si": null,
+ "sk": "Kaktus",
+ "sr": "кактус",
+ "sv": "Kaktus",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кактус",
+ "zh_Hans": "仙人掌"
+ }
+ },
+ {
+ "number": 18,
+ "emoji": "🍄",
+ "description": "Mushroom",
+ "unicode": "U+1F344",
+ "translated_descriptions": {
+ "ar": "فُطر",
+ "bg": "Гъба",
+ "ca": "Bolet",
+ "cs": "Houba",
+ "de": "Pilz",
+ "eo": "Fungo",
+ "es": "Seta",
+ "et": "Seen",
+ "fi": "Sieni",
+ "fr": "Champignon",
+ "hr": "gljiva",
+ "hu": "Gomba",
+ "it": "Fungo",
+ "ja": "きのこ",
+ "nb_NO": "Sopp",
+ "nl": "Paddenstoel",
+ "pt_BR": "Cogumelo",
+ "ru": "Гриб",
+ "si": null,
+ "sk": "Huba",
+ "sr": "печурка",
+ "sv": "Svamp",
+ "szl": null,
+ "tzm": "Agursel",
+ "uk": "Гриб",
+ "zh_Hans": "蘑菇"
+ }
+ },
+ {
+ "number": 19,
+ "emoji": "🌏",
+ "description": "Globe",
+ "unicode": "U+1F30F",
+ "translated_descriptions": {
+ "ar": "كُرَةٌ أرضِيَّة",
+ "bg": "Глобус",
+ "ca": "Globus terraqüi",
+ "cs": "Zeměkoule",
+ "de": "Globus",
+ "eo": "Globo",
+ "es": "Globo",
+ "et": "Maakera",
+ "fi": "Maapallo",
+ "fr": "Globe",
+ "hr": "Globus",
+ "hu": "Földgömb",
+ "it": "Globo",
+ "ja": "地球",
+ "nb_NO": "Globus",
+ "nl": "Wereldbol",
+ "pt_BR": "Globo",
+ "ru": "Глобус",
+ "si": null,
+ "sk": "Zemeguľa",
+ "sr": "глобус",
+ "sv": "Jordklot",
+ "szl": null,
+ "tzm": null,
+ "uk": "Глобус",
+ "zh_Hans": "地球"
+ }
+ },
+ {
+ "number": 20,
+ "emoji": "🌙",
+ "description": "Moon",
+ "unicode": "U+1F319",
+ "translated_descriptions": {
+ "ar": "قَمَر",
+ "bg": "Луна",
+ "ca": "Lluna",
+ "cs": "Měsíc",
+ "de": "Mond",
+ "eo": "Luno",
+ "es": "Luna",
+ "et": "Kuu",
+ "fi": "Kuu",
+ "fr": "Lune",
+ "hr": "mjesec",
+ "hu": "Hold",
+ "it": "Luna",
+ "ja": "月",
+ "nb_NO": "Måne",
+ "nl": "Maan",
+ "pt_BR": "Lua",
+ "ru": "Луна",
+ "si": null,
+ "sk": "Polmesiac",
+ "sr": "месец",
+ "sv": "Måne",
+ "szl": null,
+ "tzm": "Ayyur",
+ "uk": "Місяць",
+ "zh_Hans": "月亮"
+ }
+ },
+ {
+ "number": 21,
+ "emoji": "☁️",
+ "description": "Cloud",
+ "unicode": "U+2601U+FE0F",
+ "translated_descriptions": {
+ "ar": "سَحابَة",
+ "bg": "Облак",
+ "ca": "Núvol",
+ "cs": "Mrak",
+ "de": "Wolke",
+ "eo": "Nubo",
+ "es": "Nube",
+ "et": "Pilv",
+ "fi": "Pilvi",
+ "fr": "Nuage",
+ "hr": "oblak",
+ "hu": "Felhő",
+ "it": "Nuvola",
+ "ja": "雲",
+ "nb_NO": "Sky",
+ "nl": "Wolk",
+ "pt_BR": "Nuvem",
+ "ru": "Облако",
+ "si": null,
+ "sk": "Oblak",
+ "sr": "облак",
+ "sv": "Moln",
+ "szl": null,
+ "tzm": null,
+ "uk": "Хмара",
+ "zh_Hans": "云"
+ }
+ },
+ {
+ "number": 22,
+ "emoji": "🔥",
+ "description": "Fire",
+ "unicode": "U+1F525",
+ "translated_descriptions": {
+ "ar": "نار",
+ "bg": "Огън",
+ "ca": "Foc",
+ "cs": "Oheň",
+ "de": "Feuer",
+ "eo": "Fajro",
+ "es": "Fuego",
+ "et": "Tuli",
+ "fi": "Tuli",
+ "fr": "Feu",
+ "hr": "vatra",
+ "hu": "Tűz",
+ "it": "Fuoco",
+ "ja": "炎",
+ "nb_NO": "Flamme",
+ "nl": "Vuur",
+ "pt_BR": "Fogo",
+ "ru": "Огонь",
+ "si": null,
+ "sk": "Oheň",
+ "sr": "ватра",
+ "sv": "Eld",
+ "szl": null,
+ "tzm": "Timessi",
+ "uk": "Вогонь",
+ "zh_Hans": "火"
+ }
+ },
+ {
+ "number": 23,
+ "emoji": "🍌",
+ "description": "Banana",
+ "unicode": "U+1F34C",
+ "translated_descriptions": {
+ "ar": "مَوزَة",
+ "bg": "Банан",
+ "ca": "Plàtan",
+ "cs": "Banán",
+ "de": "Banane",
+ "eo": "Banano",
+ "es": "Plátano",
+ "et": "Banaan",
+ "fi": "Banaani",
+ "fr": "Banane",
+ "hr": "banana",
+ "hu": "Banán",
+ "it": "Banana",
+ "ja": "バナナ",
+ "nb_NO": "Banan",
+ "nl": "Banaan",
+ "pt_BR": "Banana",
+ "ru": "Банан",
+ "si": null,
+ "sk": "Banán",
+ "sr": "банана",
+ "sv": "Banan",
+ "szl": null,
+ "tzm": "Tabanant",
+ "uk": "Банан",
+ "zh_Hans": "香蕉"
+ }
+ },
+ {
+ "number": 24,
+ "emoji": "🍎",
+ "description": "Apple",
+ "unicode": "U+1F34E",
+ "translated_descriptions": {
+ "ar": "تُفَّاحَة",
+ "bg": "Ябълка",
+ "ca": "Poma",
+ "cs": "Jablko",
+ "de": "Apfel",
+ "eo": "Pomo",
+ "es": "Manzana",
+ "et": "Õun",
+ "fi": "Omena",
+ "fr": "Pomme",
+ "hr": "jabuka",
+ "hu": "Alma",
+ "it": "Mela",
+ "ja": "リンゴ",
+ "nb_NO": "Eple",
+ "nl": "Appel",
+ "pt_BR": "Maçã",
+ "ru": "Яблоко",
+ "si": null,
+ "sk": "Červené jablko",
+ "sr": "јабука",
+ "sv": "Äpple",
+ "szl": null,
+ "tzm": "Tadeffuyt",
+ "uk": "Яблуко",
+ "zh_Hans": "苹果"
+ }
+ },
+ {
+ "number": 25,
+ "emoji": "🍓",
+ "description": "Strawberry",
+ "unicode": "U+1F353",
+ "translated_descriptions": {
+ "ar": "فَراوِلَة",
+ "bg": "Ягода",
+ "ca": "Maduixa",
+ "cs": "Jahoda",
+ "de": "Erdbeere",
+ "eo": "Frago",
+ "es": "Fresa",
+ "et": "Maasikas",
+ "fi": "Mansikka",
+ "fr": "Fraise",
+ "hr": "jagoda",
+ "hu": "Eper",
+ "it": "Fragola",
+ "ja": "いちご",
+ "nb_NO": "Jordbær",
+ "nl": "Aardbei",
+ "pt_BR": "Morango",
+ "ru": "Клубника",
+ "si": null,
+ "sk": "Jahoda",
+ "sr": "јагода",
+ "sv": "Jordgubbe",
+ "szl": null,
+ "tzm": null,
+ "uk": "Полуниця",
+ "zh_Hans": "草莓"
+ }
+ },
+ {
+ "number": 26,
+ "emoji": "🌽",
+ "description": "Corn",
+ "unicode": "U+1F33D",
+ "translated_descriptions": {
+ "ar": "ذُرَة",
+ "bg": "Царевица",
+ "ca": "Blat de moro",
+ "cs": "Kukuřice",
+ "de": "Mais",
+ "eo": "Maizo",
+ "es": "Maíz",
+ "et": "Mais",
+ "fi": "Maissi",
+ "fr": "Maïs",
+ "hr": "kukuruza",
+ "hu": "Kukorica",
+ "it": "Mais",
+ "ja": "とうもろこし",
+ "nb_NO": "Mais",
+ "nl": "Maïs",
+ "pt_BR": "Milho",
+ "ru": "Кукуруза",
+ "si": null,
+ "sk": "Kukuričný klas",
+ "sr": "кукуруз",
+ "sv": "Majs",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кукурудза",
+ "zh_Hans": "玉米"
+ }
+ },
+ {
+ "number": 27,
+ "emoji": "🍕",
+ "description": "Pizza",
+ "unicode": "U+1F355",
+ "translated_descriptions": {
+ "ar": "بِيتزا",
+ "bg": "Пица",
+ "ca": "Pizza",
+ "cs": "Pizza",
+ "de": "Pizza",
+ "eo": "Pico",
+ "es": "Pizza",
+ "et": "Pitsa",
+ "fi": "Pizza",
+ "fr": "Pizza",
+ "hr": "pizza",
+ "hu": "Pizza",
+ "it": "Pizza",
+ "ja": "ピザ",
+ "nb_NO": "Pizza",
+ "nl": "Pizza",
+ "pt_BR": "Pizza",
+ "ru": "Пицца",
+ "si": null,
+ "sk": "Pizza",
+ "sr": "пица",
+ "sv": "Pizza",
+ "szl": null,
+ "tzm": null,
+ "uk": "Піца",
+ "zh_Hans": "披萨"
+ }
+ },
+ {
+ "number": 28,
+ "emoji": "🎂",
+ "description": "Cake",
+ "unicode": "U+1F382",
+ "translated_descriptions": {
+ "ar": "كَعكَة",
+ "bg": "Торта",
+ "ca": "Pastís",
+ "cs": "Dort",
+ "de": "Kuchen",
+ "eo": "Torto",
+ "es": "Tarta",
+ "et": "Kook",
+ "fi": "Kakku",
+ "fr": "Gâteau",
+ "hr": "torta",
+ "hu": "Süti",
+ "it": "Torta",
+ "ja": "ケーキ",
+ "nb_NO": "Kake",
+ "nl": "Taart",
+ "pt_BR": "Bolo",
+ "ru": "Торт",
+ "si": null,
+ "sk": "Narodeninová torta",
+ "sr": "торта",
+ "sv": "Tårta",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пиріг",
+ "zh_Hans": "蛋糕"
+ }
+ },
+ {
+ "number": 29,
+ "emoji": "❤️",
+ "description": "Heart",
+ "unicode": "U+2764U+FE0F",
+ "translated_descriptions": {
+ "ar": "قَلب",
+ "bg": "Сърце",
+ "ca": "Cor",
+ "cs": "Srdce",
+ "de": "Herz",
+ "eo": "Koro",
+ "es": "Corazón",
+ "et": "Süda",
+ "fi": "Sydän",
+ "fr": "Cœur",
+ "hr": "srca",
+ "hu": "Szív",
+ "it": "Cuore",
+ "ja": "ハート",
+ "nb_NO": "Hjerte",
+ "nl": "Hart",
+ "pt_BR": "Coração",
+ "ru": "Сердце",
+ "si": null,
+ "sk": "červené srdce",
+ "sr": "срце",
+ "sv": "Hjärta",
+ "szl": null,
+ "tzm": "Ul",
+ "uk": "Серце",
+ "zh_Hans": "心"
+ }
+ },
+ {
+ "number": 30,
+ "emoji": "😀",
+ "description": "Smiley",
+ "unicode": "U+1F600",
+ "translated_descriptions": {
+ "ar": "اِبتِسَامَة",
+ "bg": "Усмивка",
+ "ca": "Somrient",
+ "cs": "Smajlík",
+ "de": "Lächeln",
+ "eo": "Rideto",
+ "es": "Emoticono",
+ "et": "Smaili",
+ "fi": "Hymynaama",
+ "fr": "Sourire",
+ "hr": "smajlića",
+ "hu": "Mosoly",
+ "it": "Faccina sorridente",
+ "ja": "スマイル",
+ "nb_NO": "Smilefjes",
+ "nl": "Smiley",
+ "pt_BR": "Sorriso",
+ "ru": "Улыбка",
+ "si": null,
+ "sk": "Škeriaca sa tvár",
+ "sr": "смајли",
+ "sv": "Smiley",
+ "szl": null,
+ "tzm": null,
+ "uk": "Посмішка",
+ "zh_Hans": "笑脸"
+ }
+ },
+ {
+ "number": 31,
+ "emoji": "🤖",
+ "description": "Robot",
+ "unicode": "U+1F916",
+ "translated_descriptions": {
+ "ar": "رُوبُوت",
+ "bg": "Робот",
+ "ca": "Robot",
+ "cs": "Robot",
+ "de": "Roboter",
+ "eo": "Roboto",
+ "es": "Robot",
+ "et": "Robot",
+ "fi": "Robotti",
+ "fr": "Robot",
+ "hr": "robot",
+ "hu": "Robot",
+ "it": "Robot",
+ "ja": "ロボと",
+ "nb_NO": "Robot",
+ "nl": "Robot",
+ "pt_BR": "Robô",
+ "ru": "Робот",
+ "si": null,
+ "sk": "Robot",
+ "sr": "робот",
+ "sv": "Robot",
+ "szl": null,
+ "tzm": "Aṛubu",
+ "uk": "Робот",
+ "zh_Hans": "机器人"
+ }
+ },
+ {
+ "number": 32,
+ "emoji": "🎩",
+ "description": "Hat",
+ "unicode": "U+1F3A9",
+ "translated_descriptions": {
+ "ar": "قُبَّعَة",
+ "bg": "Шапка",
+ "ca": "Barret",
+ "cs": "Klobouk",
+ "de": "Hut",
+ "eo": "Ĉapelo",
+ "es": "Sombrero",
+ "et": "Kübar",
+ "fi": "Hattu",
+ "fr": "Chapeau",
+ "hr": "kapa",
+ "hu": "Kalap",
+ "it": "Cappello",
+ "ja": "帽子",
+ "nb_NO": "Hatt",
+ "nl": "Hoed",
+ "pt_BR": "Chapéu",
+ "ru": "Шляпа",
+ "si": null,
+ "sk": "Cilinder",
+ "sr": "шешир",
+ "sv": "Hatt",
+ "szl": null,
+ "tzm": "Taraza",
+ "uk": "Капелюх",
+ "zh_Hans": "帽子"
+ }
+ },
+ {
+ "number": 33,
+ "emoji": "👓",
+ "description": "Glasses",
+ "unicode": "U+1F453",
+ "translated_descriptions": {
+ "ar": "نَظَّارَة",
+ "bg": "Очила",
+ "ca": "Ulleres",
+ "cs": "Brýle",
+ "de": "Brille",
+ "eo": "Okulvitroj",
+ "es": "Gafas",
+ "et": "Prillid",
+ "fi": "Silmälasit",
+ "fr": "Lunettes",
+ "hr": "naočale",
+ "hu": "Szemüveg",
+ "it": "Occhiali",
+ "ja": "めがね",
+ "nb_NO": "Briller",
+ "nl": "Bril",
+ "pt_BR": "Óculos",
+ "ru": "Очки",
+ "si": null,
+ "sk": "Okuliare",
+ "sr": "наочаре",
+ "sv": "Glasögon",
+ "szl": null,
+ "tzm": null,
+ "uk": "Окуляри",
+ "zh_Hans": "眼镜"
+ }
+ },
+ {
+ "number": 34,
+ "emoji": "🔧",
+ "description": "Spanner",
+ "unicode": "U+1F527",
+ "translated_descriptions": {
+ "ar": "مِفتَاحُ رَبط",
+ "bg": "Гаечен ключ",
+ "ca": "Clau anglesa",
+ "cs": "Klíč",
+ "de": "Schraubenschlüssel",
+ "eo": "Ŝraŭbŝlosilo",
+ "es": "Llave inglesa",
+ "et": "Mutrivõti",
+ "fi": "Kiintoavain",
+ "fr": "Clé à molette",
+ "hr": "ključ",
+ "hu": "Csavarkulcs",
+ "it": "Chiave inglese",
+ "ja": "スパナ",
+ "nb_NO": "Fastnøkkel",
+ "nl": "Moersleutel",
+ "pt_BR": "Chave inglesa",
+ "ru": "Ключ",
+ "si": null,
+ "sk": "Francúzsky kľúč",
+ "sr": "кључ",
+ "sv": "Skruvnyckel",
+ "szl": null,
+ "tzm": null,
+ "uk": "Гайковий ключ",
+ "zh_Hans": "扳手"
+ }
+ },
+ {
+ "number": 35,
+ "emoji": "🎅",
+ "description": "Santa",
+ "unicode": "U+1F385",
+ "translated_descriptions": {
+ "ar": "سانتا",
+ "bg": "Дядо Коледа",
+ "ca": "Pare Noél",
+ "cs": "Mikuláš",
+ "de": "Weihnachtsmann",
+ "eo": "Kristnaska viro",
+ "es": "Papá Noel",
+ "et": "Jõuluvana",
+ "fi": "Joulupukki",
+ "fr": "Père Noël",
+ "hr": "deda Mraz",
+ "hu": "Télapó",
+ "it": "Babbo Natale",
+ "ja": "サンタ",
+ "nb_NO": "Julenisse",
+ "nl": "Kerstman",
+ "pt_BR": "Papai-noel",
+ "ru": "Санта",
+ "si": null,
+ "sk": "Santa Claus",
+ "sr": "деда Мраз",
+ "sv": "Tomte",
+ "szl": null,
+ "tzm": null,
+ "uk": "Санта Клаус",
+ "zh_Hans": "圣诞老人"
+ }
+ },
+ {
+ "number": 36,
+ "emoji": "👍",
+ "description": "Thumbs Up",
+ "unicode": "U+1F44D",
+ "translated_descriptions": {
+ "ar": "رَفعُ إِبهَام",
+ "bg": "Палец нагоре",
+ "ca": "Polzes amunt",
+ "cs": "Palec nahoru",
+ "de": "Daumen Hoch",
+ "eo": "Dikfingro supren",
+ "es": "Pulgar arriba",
+ "et": "Pöidlad püsti",
+ "fi": "Peukalo ylös",
+ "fr": "Pouce en l’air",
+ "hr": "palac gore",
+ "hu": "Hüvelykujj fel",
+ "it": "Pollice alzato",
+ "ja": "いいね",
+ "nb_NO": "Tommel Opp",
+ "nl": "Duim omhoog",
+ "pt_BR": "Joinha",
+ "ru": "Большой палец вверх",
+ "si": null,
+ "sk": "Palec nahor",
+ "sr": "палчић горе",
+ "sv": "Tummen upp",
+ "szl": null,
+ "tzm": null,
+ "uk": "Великий палець вгору",
+ "zh_Hans": "赞"
+ }
+ },
+ {
+ "number": 37,
+ "emoji": "☂️",
+ "description": "Umbrella",
+ "unicode": "U+2602U+FE0F",
+ "translated_descriptions": {
+ "ar": "مِظَلَّة",
+ "bg": "Чадър",
+ "ca": "Paraigües",
+ "cs": "Deštník",
+ "de": "Regenschirm",
+ "eo": "Ombrelo",
+ "es": "Paraguas",
+ "et": "Vihmavari",
+ "fi": "Sateenvarjo",
+ "fr": "Parapluie",
+ "hr": "kišobran",
+ "hu": "Esernyő",
+ "it": "Ombrello",
+ "ja": "傘",
+ "nb_NO": "Paraply",
+ "nl": "Paraplu",
+ "pt_BR": "Guarda-chuva",
+ "ru": "Зонт",
+ "si": null,
+ "sk": "Dáždnik",
+ "sr": "кишобран",
+ "sv": "Paraply",
+ "szl": null,
+ "tzm": null,
+ "uk": "Парасолька",
+ "zh_Hans": "伞"
+ }
+ },
+ {
+ "number": 38,
+ "emoji": "⌛",
+ "description": "Hourglass",
+ "unicode": "U+231B",
+ "translated_descriptions": {
+ "ar": "سَاعَةٌ رَملِيَّة",
+ "bg": "Пясъчен часовник",
+ "ca": "Rellotge de sorra",
+ "cs": "Přesýpací hodiny",
+ "de": "Sanduhr",
+ "eo": "Sablohorloĝo",
+ "es": "Reloj de arena",
+ "et": "Liivakell",
+ "fi": "Tiimalasi",
+ "fr": "Sablier",
+ "hr": "pješčani sat",
+ "hu": "Homokóra",
+ "it": "Clessidra",
+ "ja": "砂時計",
+ "nb_NO": "Timeglass",
+ "nl": "Zandloper",
+ "pt_BR": "Ampulheta",
+ "ru": "Песочные часы",
+ "si": null,
+ "sk": "Presýpacie hodiny",
+ "sr": "пешчаник",
+ "sv": "Timglas",
+ "szl": null,
+ "tzm": null,
+ "uk": "Пісковий годинник",
+ "zh_Hans": "沙漏"
+ }
+ },
+ {
+ "number": 39,
+ "emoji": "⏰",
+ "description": "Clock",
+ "unicode": "U+23F0",
+ "translated_descriptions": {
+ "ar": "سَاعَة",
+ "bg": "Часовник",
+ "ca": "Rellotge",
+ "cs": "Hodiny",
+ "de": "Uhr",
+ "eo": "Horloĝo",
+ "es": "Reloj",
+ "et": "Kell",
+ "fi": "Pöytäkello",
+ "fr": "Réveil",
+ "hr": "sat",
+ "hu": "Óra",
+ "it": "Orologio",
+ "ja": "時計",
+ "nb_NO": "Klokke",
+ "nl": "Wekker",
+ "pt_BR": "Relógio",
+ "ru": "Часы",
+ "si": null,
+ "sk": "Budík",
+ "sr": "сат",
+ "sv": "Klocka",
+ "szl": null,
+ "tzm": null,
+ "uk": "Годинник",
+ "zh_Hans": "时钟"
+ }
+ },
+ {
+ "number": 40,
+ "emoji": "🎁",
+ "description": "Gift",
+ "unicode": "U+1F381",
+ "translated_descriptions": {
+ "ar": "هَدِيَّة",
+ "bg": "Подарък",
+ "ca": "Regal",
+ "cs": "Dárek",
+ "de": "Geschenk",
+ "eo": "Donaco",
+ "es": "Regalo",
+ "et": "Kingitus",
+ "fi": "Lahja",
+ "fr": "Cadeau",
+ "hr": "poklon",
+ "hu": "Ajándék",
+ "it": "Regalo",
+ "ja": "ギフト",
+ "nb_NO": "Gave",
+ "nl": "Geschenk",
+ "pt_BR": "Presente",
+ "ru": "Подарок",
+ "si": null,
+ "sk": "Zabalený darček",
+ "sr": "поклон",
+ "sv": "Present",
+ "szl": null,
+ "tzm": null,
+ "uk": "Подарунок",
+ "zh_Hans": "礼物"
+ }
+ },
+ {
+ "number": 41,
+ "emoji": "💡",
+ "description": "Light Bulb",
+ "unicode": "U+1F4A1",
+ "translated_descriptions": {
+ "ar": "مِصبَاح",
+ "bg": "Лампа",
+ "ca": "Bombeta",
+ "cs": "Žárovka",
+ "de": "Glühbirne",
+ "eo": "Lampo",
+ "es": "Bombilla",
+ "et": "Lambipirn",
+ "fi": "Hehkulamppu",
+ "fr": "Ampoule",
+ "hr": "žarulja",
+ "hu": "Égő",
+ "it": "Lampadina",
+ "ja": "電球",
+ "nb_NO": "Lyspære",
+ "nl": "Gloeilamp",
+ "pt_BR": "Lâmpada",
+ "ru": "Лампочка",
+ "si": null,
+ "sk": "Žiarovka",
+ "sr": "сијалица",
+ "sv": "Lampa",
+ "szl": null,
+ "tzm": null,
+ "uk": "Лампочка",
+ "zh_Hans": "灯泡"
+ }
+ },
+ {
+ "number": 42,
+ "emoji": "📕",
+ "description": "Book",
+ "unicode": "U+1F4D5",
+ "translated_descriptions": {
+ "ar": "كِتَاب",
+ "bg": "Книга",
+ "ca": "Llibre",
+ "cs": "Kniha",
+ "de": "Buch",
+ "eo": "Libro",
+ "es": "Libro",
+ "et": "Raamat",
+ "fi": "Kirja",
+ "fr": "Livre",
+ "hr": "knjiga",
+ "hu": "Könyv",
+ "it": "Libro",
+ "ja": "本",
+ "nb_NO": "Bok",
+ "nl": "Boek",
+ "pt_BR": "Livro",
+ "ru": "Книга",
+ "si": null,
+ "sk": "Zatvorená kniha",
+ "sr": "књига",
+ "sv": "Bok",
+ "szl": null,
+ "tzm": "Adlis",
+ "uk": "Книга",
+ "zh_Hans": "书"
+ }
+ },
+ {
+ "number": 43,
+ "emoji": "✏️",
+ "description": "Pencil",
+ "unicode": "U+270FU+FE0F",
+ "translated_descriptions": {
+ "ar": "قَلَمُ رَصاص",
+ "bg": "Молив",
+ "ca": "Llapis",
+ "cs": "Tužka",
+ "de": "Bleistift",
+ "eo": "Krajono",
+ "es": "Lápiz",
+ "et": "Pliiats",
+ "fi": "Lyijykynä",
+ "fr": "Crayon",
+ "hr": "olovka",
+ "hu": "Ceruza",
+ "it": "Matita",
+ "ja": "鉛筆",
+ "nb_NO": "Blyant",
+ "nl": "Potlood",
+ "pt_BR": "Lápis",
+ "ru": "Карандаш",
+ "si": null,
+ "sk": "Ceruzka",
+ "sr": "оловка",
+ "sv": "Penna",
+ "szl": null,
+ "tzm": null,
+ "uk": "Олівець",
+ "zh_Hans": "铅笔"
+ }
+ },
+ {
+ "number": 44,
+ "emoji": "📎",
+ "description": "Paperclip",
+ "unicode": "U+1F4CE",
+ "translated_descriptions": {
+ "ar": "مِشبَكُ وَرَق",
+ "bg": "Кламер",
+ "ca": "Clip",
+ "cs": "Sponka",
+ "de": "Büroklammer",
+ "eo": "Paperkuntenilo",
+ "es": "Clip",
+ "et": "Kirjaklamber",
+ "fi": "Paperiliitin",
+ "fr": "Trombone",
+ "hr": "spajalica",
+ "hu": "Gémkapocs",
+ "it": "Graffetta",
+ "ja": "クリップ",
+ "nb_NO": "BInders",
+ "nl": "Papierklemmetje",
+ "pt_BR": "Clipe de papel",
+ "ru": "Скрепка",
+ "si": null,
+ "sk": "Sponka na papier",
+ "sr": "спајалица",
+ "sv": "Gem",
+ "szl": null,
+ "tzm": null,
+ "uk": "Спиначка",
+ "zh_Hans": "回形针"
+ }
+ },
+ {
+ "number": 45,
+ "emoji": "✂️",
+ "description": "Scissors",
+ "unicode": "U+2702U+FE0F",
+ "translated_descriptions": {
+ "ar": "مِقَصّ",
+ "bg": "Ножици",
+ "ca": "Tisores",
+ "cs": "Nůžky",
+ "de": "Schere",
+ "eo": "Tondilo",
+ "es": "Tijeras",
+ "et": "Käärid",
+ "fi": "Sakset",
+ "fr": "Ciseaux",
+ "hr": "škare",
+ "hu": "Olló",
+ "it": "Forbici",
+ "ja": "はさみ",
+ "nb_NO": "Saks",
+ "nl": "Schaar",
+ "pt_BR": "Tesoura",
+ "ru": "Ножницы",
+ "si": null,
+ "sk": "Nožnice",
+ "sr": "маказе",
+ "sv": "Sax",
+ "szl": null,
+ "tzm": null,
+ "uk": "Ножиці",
+ "zh_Hans": "剪刀"
+ }
+ },
+ {
+ "number": 46,
+ "emoji": "🔒",
+ "description": "Lock",
+ "unicode": "U+1F512",
+ "translated_descriptions": {
+ "ar": "قُفل",
+ "bg": "Катинар",
+ "ca": "Cadenat",
+ "cs": "Zámek",
+ "de": "Schloss",
+ "eo": "Seruro",
+ "es": "Candado",
+ "et": "Lukk",
+ "fi": "Lukko",
+ "fr": "Cadenas",
+ "hr": "zaključati",
+ "hu": "Lakat",
+ "it": "Lucchetto",
+ "ja": "錠前",
+ "nb_NO": "Lås",
+ "nl": "Slot",
+ "pt_BR": "Cadeado",
+ "ru": "Замок",
+ "si": null,
+ "sk": "Zatvorená zámka",
+ "sr": "катанац",
+ "sv": "Lås",
+ "szl": null,
+ "tzm": null,
+ "uk": "Замок",
+ "zh_Hans": "锁"
+ }
+ },
+ {
+ "number": 47,
+ "emoji": "🔑",
+ "description": "Key",
+ "unicode": "U+1F511",
+ "translated_descriptions": {
+ "ar": "مِفتَاح",
+ "bg": "Ключ",
+ "ca": "Clau",
+ "cs": "Klíč",
+ "de": "Schlüssel",
+ "eo": "Ŝlosilo",
+ "es": "Llave",
+ "et": "Võti",
+ "fi": "Avain",
+ "fr": "Clé",
+ "hr": "ključ",
+ "hu": "Kulcs",
+ "it": "Chiave",
+ "ja": "鍵",
+ "nb_NO": "Nøkkel",
+ "nl": "Sleutel",
+ "pt_BR": "Chave",
+ "ru": "Ключ",
+ "si": null,
+ "sk": "Kľúč",
+ "sr": "кључ",
+ "sv": "Nyckel",
+ "szl": null,
+ "tzm": "Tasarut",
+ "uk": "Ключ",
+ "zh_Hans": "钥匙"
+ }
+ },
+ {
+ "number": 48,
+ "emoji": "🔨",
+ "description": "Hammer",
+ "unicode": "U+1F528",
+ "translated_descriptions": {
+ "ar": "مِطرَقَة",
+ "bg": "Чук",
+ "ca": "Martell",
+ "cs": "Kladivo",
+ "de": "Hammer",
+ "eo": "Martelo",
+ "es": "Martillo",
+ "et": "Haamer",
+ "fi": "Vasara",
+ "fr": "Marteau",
+ "hr": "čekić",
+ "hu": "Kalapács",
+ "it": "Martello",
+ "ja": "金槌",
+ "nb_NO": "Hammer",
+ "nl": "Hamer",
+ "pt_BR": "Martelo",
+ "ru": "Молоток",
+ "si": null,
+ "sk": "Kladivo",
+ "sr": "чекић",
+ "sv": "Hammare",
+ "szl": null,
+ "tzm": null,
+ "uk": "Молоток",
+ "zh_Hans": "锤子"
+ }
+ },
+ {
+ "number": 49,
+ "emoji": "☎️",
+ "description": "Telephone",
+ "unicode": "U+260EU+FE0F",
+ "translated_descriptions": {
+ "ar": "تِلِفُون",
+ "bg": "Телефон",
+ "ca": "Telèfon",
+ "cs": "Telefon",
+ "de": "Telefon",
+ "eo": "Telefono",
+ "es": "Telefono",
+ "et": "Telefon",
+ "fi": "Puhelin",
+ "fr": "Téléphone",
+ "hr": "telefon",
+ "hu": "Telefon",
+ "it": "Telefono",
+ "ja": "電話機",
+ "nb_NO": "Telefon",
+ "nl": "Telefoon",
+ "pt_BR": "Telefone",
+ "ru": "Телефон",
+ "si": null,
+ "sk": "Telefón",
+ "sr": "телефон",
+ "sv": "Telefon",
+ "szl": null,
+ "tzm": "Atilifun",
+ "uk": "Телефон",
+ "zh_Hans": "电话"
+ }
+ },
+ {
+ "number": 50,
+ "emoji": "🏁",
+ "description": "Flag",
+ "unicode": "U+1F3C1",
+ "translated_descriptions": {
+ "ar": "عَلَم",
+ "bg": "Флаг",
+ "ca": "Bandera",
+ "cs": "Vlajka",
+ "de": "Flagge",
+ "eo": "Flago",
+ "es": "Bandera",
+ "et": "Lipp",
+ "fi": "Lippu",
+ "fr": "Drapeau",
+ "hr": "zastava",
+ "hu": "Zászló",
+ "it": "Bandiera",
+ "ja": "旗",
+ "nb_NO": "Flagg",
+ "nl": "Vlag",
+ "pt_BR": "Bandeira",
+ "ru": "Флаг",
+ "si": null,
+ "sk": "Kockovaná zástava",
+ "sr": "застава",
+ "sv": "Flagga",
+ "szl": null,
+ "tzm": "Acenyal",
+ "uk": "Прапор",
+ "zh_Hans": "旗帜"
+ }
+ },
+ {
+ "number": 51,
+ "emoji": "🚂",
+ "description": "Train",
+ "unicode": "U+1F682",
+ "translated_descriptions": {
+ "ar": "قِطَار",
+ "bg": "Влак",
+ "ca": "Tren",
+ "cs": "Vlak",
+ "de": "Zug",
+ "eo": "Vagonaro",
+ "es": "Tren",
+ "et": "Rong",
+ "fi": "Juna",
+ "fr": "Train",
+ "hr": "vlak",
+ "hu": "Vonat",
+ "it": "Treno",
+ "ja": "電車",
+ "nb_NO": "Tog",
+ "nl": "Trein",
+ "pt_BR": "Trem",
+ "ru": "Поезд",
+ "si": null,
+ "sk": "Rušeň",
+ "sr": "воз",
+ "sv": "Tåg",
+ "szl": null,
+ "tzm": null,
+ "uk": "Потяг",
+ "zh_Hans": "火车"
+ }
+ },
+ {
+ "number": 52,
+ "emoji": "🚲",
+ "description": "Bicycle",
+ "unicode": "U+1F6B2",
+ "translated_descriptions": {
+ "ar": "دَرّاجَة",
+ "bg": "Колело",
+ "ca": "Bicicleta",
+ "cs": "Kolo",
+ "de": "Fahrrad",
+ "eo": "Biciklo",
+ "es": "Bicicleta",
+ "et": "Jalgratas",
+ "fi": "Polkupyörä",
+ "fr": "Vélo",
+ "hr": "bicikl",
+ "hu": "Kerékpár",
+ "it": "Bicicletta",
+ "ja": "自転車",
+ "nb_NO": "Sykkel",
+ "nl": "Fiets",
+ "pt_BR": "Bicicleta",
+ "ru": "Велосипед",
+ "si": null,
+ "sk": "Bicykel",
+ "sr": "бицикл",
+ "sv": "Cykel",
+ "szl": null,
+ "tzm": null,
+ "uk": "Велосипед",
+ "zh_Hans": "自行车"
+ }
+ },
+ {
+ "number": 53,
+ "emoji": "✈️",
+ "description": "Aeroplane",
+ "unicode": "U+2708U+FE0F",
+ "translated_descriptions": {
+ "ar": "طَائِرة",
+ "bg": "Самолет",
+ "ca": "Avió",
+ "cs": "Letadlo",
+ "de": "Flugzeug",
+ "eo": "Aviadilo",
+ "es": "Avión",
+ "et": "Lennuk",
+ "fi": "Lentokone",
+ "fr": "Avion",
+ "hr": "avion",
+ "hu": "Repülő",
+ "it": "Aeroplano",
+ "ja": "飛行機",
+ "nb_NO": "Fly",
+ "nl": "Vliegtuig",
+ "pt_BR": "Avião",
+ "ru": "Самолет",
+ "si": null,
+ "sk": "Lietadlo",
+ "sr": "авион",
+ "sv": "Flygplan",
+ "szl": null,
+ "tzm": null,
+ "uk": "Літак",
+ "zh_Hans": "飞机"
+ }
+ },
+ {
+ "number": 54,
+ "emoji": "🚀",
+ "description": "Rocket",
+ "unicode": "U+1F680",
+ "translated_descriptions": {
+ "ar": "صَارُوخ",
+ "bg": "Ракета",
+ "ca": "Coet",
+ "cs": "Raketa",
+ "de": "Rakete",
+ "eo": "Raketo",
+ "es": "Cohete",
+ "et": "Rakett",
+ "fi": "Raketti",
+ "fr": "Fusée",
+ "hr": "raketa",
+ "hu": "Rakáta",
+ "it": "Razzo",
+ "ja": "ロケット",
+ "nb_NO": "Rakett",
+ "nl": "Raket",
+ "pt_BR": "Foguete",
+ "ru": "Ракета",
+ "si": null,
+ "sk": "Raketa",
+ "sr": "ракета",
+ "sv": "Raket",
+ "szl": null,
+ "tzm": null,
+ "uk": "Ракета",
+ "zh_Hans": "火箭"
+ }
+ },
+ {
+ "number": 55,
+ "emoji": "🏆",
+ "description": "Trophy",
+ "unicode": "U+1F3C6",
+ "translated_descriptions": {
+ "ar": "كَأسُ النَّصر",
+ "bg": "Трофей",
+ "ca": "Trofeu",
+ "cs": "Pohár",
+ "de": "Pokal",
+ "eo": "Trofeo",
+ "es": "Trofeo",
+ "et": "Auhind",
+ "fi": "Palkinto",
+ "fr": "Trophée",
+ "hr": "trofej",
+ "hu": "Trófea",
+ "it": "Trofeo",
+ "ja": "トロフィー",
+ "nb_NO": "Pokal",
+ "nl": "Trofee",
+ "pt_BR": "Troféu",
+ "ru": "Кубок",
+ "si": null,
+ "sk": "Trofej",
+ "sr": "пехар",
+ "sv": "Trofé",
+ "szl": null,
+ "tzm": null,
+ "uk": "Приз",
+ "zh_Hans": "奖杯"
+ }
+ },
+ {
+ "number": 56,
+ "emoji": "⚽",
+ "description": "Ball",
+ "unicode": "U+26BD",
+ "translated_descriptions": {
+ "ar": "كُرَة",
+ "bg": "Топка",
+ "ca": "Pilota",
+ "cs": "Míč",
+ "de": "Ball",
+ "eo": "Pilko",
+ "es": "Bola",
+ "et": "Pall",
+ "fi": "Pallo",
+ "fr": "Ballon",
+ "hr": "lopta",
+ "hu": "Labda",
+ "it": "Palla",
+ "ja": "ボール",
+ "nb_NO": "Ball",
+ "nl": "Bal",
+ "pt_BR": "Bola",
+ "ru": "Мяч",
+ "si": null,
+ "sk": "Futbal",
+ "sr": "лопта",
+ "sv": "Boll",
+ "szl": null,
+ "tzm": "Tcama",
+ "uk": "М'яч",
+ "zh_Hans": "球"
+ }
+ },
+ {
+ "number": 57,
+ "emoji": "🎸",
+ "description": "Guitar",
+ "unicode": "U+1F3B8",
+ "translated_descriptions": {
+ "ar": "غيتار",
+ "bg": "Китара",
+ "ca": "Guitarra",
+ "cs": "Kytara",
+ "de": "Gitarre",
+ "eo": "Gitaro",
+ "es": "Guitarra",
+ "et": "Kitarr",
+ "fi": "Kitara",
+ "fr": "Guitare",
+ "hr": "gitara",
+ "hu": "Gitár",
+ "it": "Chitarra",
+ "ja": "ギター",
+ "nb_NO": "Gitar",
+ "nl": "Gitaar",
+ "pt_BR": "Guitarra",
+ "ru": "Гитара",
+ "si": null,
+ "sk": "Gitara",
+ "sr": "гитара",
+ "sv": "Gitarr",
+ "szl": null,
+ "tzm": "Agiṭaṛ",
+ "uk": "Гітара",
+ "zh_Hans": "吉他"
+ }
+ },
+ {
+ "number": 58,
+ "emoji": "🎺",
+ "description": "Trumpet",
+ "unicode": "U+1F3BA",
+ "translated_descriptions": {
+ "ar": "بُوق",
+ "bg": "Тромпет",
+ "ca": "Trompeta",
+ "cs": "Trumpeta",
+ "de": "Trompete",
+ "eo": "Trumpeto",
+ "es": "Trompeta",
+ "et": "Trompet",
+ "fi": "Trumpetti",
+ "fr": "Trompette",
+ "hr": "truba",
+ "hu": "Trombita",
+ "it": "Trombetta",
+ "ja": "トランペット",
+ "nb_NO": "Trompet",
+ "nl": "Trompet",
+ "pt_BR": "Trombeta",
+ "ru": "Труба",
+ "si": null,
+ "sk": "Trúbka",
+ "sr": "труба",
+ "sv": "Trumpet",
+ "szl": null,
+ "tzm": null,
+ "uk": "Труба",
+ "zh_Hans": "喇叭"
+ }
+ },
+ {
+ "number": 59,
+ "emoji": "🔔",
+ "description": "Bell",
+ "unicode": "U+1F514",
+ "translated_descriptions": {
+ "ar": "جَرَس",
+ "bg": "Звънец",
+ "ca": "Campana",
+ "cs": "Zvonek",
+ "de": "Glocke",
+ "eo": "Sonorilo",
+ "es": "Campana",
+ "et": "Kelluke",
+ "fi": "Soittokello",
+ "fr": "Cloche",
+ "hr": "zvono",
+ "hu": "Harang",
+ "it": "Campana",
+ "ja": "ベル",
+ "nb_NO": "Bjelle",
+ "nl": "Bel",
+ "pt_BR": "Sino",
+ "ru": "Колокол",
+ "si": null,
+ "sk": "Zvon",
+ "sr": "звоно",
+ "sv": "Bjällra",
+ "szl": null,
+ "tzm": null,
+ "uk": "Дзвін",
+ "zh_Hans": "铃铛"
+ }
+ },
+ {
+ "number": 60,
+ "emoji": "⚓",
+ "description": "Anchor",
+ "unicode": "U+2693",
+ "translated_descriptions": {
+ "ar": "مِرسَاة",
+ "bg": "Котва",
+ "ca": "Àncora",
+ "cs": "Kotva",
+ "de": "Anker",
+ "eo": "Ankro",
+ "es": "Ancla",
+ "et": "Ankur",
+ "fi": "Ankkuri",
+ "fr": "Ancre",
+ "hr": "sidro",
+ "hu": "Horgony",
+ "it": "Ancora",
+ "ja": "いかり",
+ "nb_NO": "Anker",
+ "nl": "Anker",
+ "pt_BR": "Âncora",
+ "ru": "Якорь",
+ "si": null,
+ "sk": "Kotva",
+ "sr": "сидро",
+ "sv": "Ankare",
+ "szl": null,
+ "tzm": null,
+ "uk": "Якір",
+ "zh_Hans": "锚"
+ }
+ },
+ {
+ "number": 61,
+ "emoji": "🎧",
+ "description": "Headphones",
+ "unicode": "U+1F3A7",
+ "translated_descriptions": {
+ "ar": "سَمّاعَة رَأس",
+ "bg": "Слушалки",
+ "ca": "Auriculars",
+ "cs": "Sluchátka",
+ "de": "Kopfhörer",
+ "eo": "Kapaŭdilo",
+ "es": "Cascos",
+ "et": "Kõrvaklapid",
+ "fi": "Kuulokkeet",
+ "fr": "Casque audio",
+ "hr": "slušalice",
+ "hu": "Fejhallgató",
+ "it": "Cuffie",
+ "ja": "ヘッドホン",
+ "nb_NO": "Hodetelefoner",
+ "nl": "Koptelefoon",
+ "pt_BR": "Fones de ouvido",
+ "ru": "Наушники",
+ "si": null,
+ "sk": "Slúchadlá",
+ "sr": "слушалице",
+ "sv": "Hörlurar",
+ "szl": null,
+ "tzm": null,
+ "uk": "Навушники",
+ "zh_Hans": "耳机"
+ }
+ },
+ {
+ "number": 62,
+ "emoji": "📁",
+ "description": "Folder",
+ "unicode": "U+1F4C1",
+ "translated_descriptions": {
+ "ar": "مُجَلَّد",
+ "bg": "Папка",
+ "ca": "Carpeta",
+ "cs": "Složka",
+ "de": "Ordner",
+ "eo": "Dosierujo",
+ "es": "Carpeta",
+ "et": "Kaust",
+ "fi": "Kansio",
+ "fr": "Dossier",
+ "hr": "mapu",
+ "hu": "Mappa",
+ "it": "Cartella",
+ "ja": "フォルダ",
+ "nb_NO": "Mappe",
+ "nl": "Map",
+ "pt_BR": "Pasta",
+ "ru": "Папка",
+ "si": null,
+ "sk": "Fascikel",
+ "sr": "фасцикла",
+ "sv": "Mapp",
+ "szl": null,
+ "tzm": "Asdaw",
+ "uk": "Тека",
+ "zh_Hans": "文件夹"
+ }
+ },
+ {
+ "number": 63,
+ "emoji": "📌",
+ "description": "Pin",
+ "unicode": "U+1F4CC",
+ "translated_descriptions": {
+ "ar": "دَبُّوس",
+ "bg": "Кабърче",
+ "ca": "Xinxeta",
+ "cs": "Špendlík",
+ "de": "Stecknadel",
+ "eo": "Pinglo",
+ "es": "Alfiler",
+ "et": "Nööpnõel",
+ "fi": "Nuppineula",
+ "fr": "Punaise",
+ "hr": "pribadača",
+ "hu": "Rajszeg",
+ "it": "Puntina",
+ "ja": "ピン",
+ "nb_NO": "Tegnestift",
+ "nl": "Duimspijker",
+ "pt_BR": "Alfinete",
+ "ru": "Булавка",
+ "si": null,
+ "sk": "Špendlík",
+ "sr": "чиода",
+ "sv": "Häftstift",
+ "szl": null,
+ "tzm": null,
+ "uk": "Кнопка",
+ "zh_Hans": "图钉"
+ }
+ }
+]
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/call.ogg b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/call.ogg
new file mode 100644
index 0000000..63b5d4d
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/call.ogg differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/notification.ogg b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/notification.ogg
new file mode 100644
index 0000000..390f2bf
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/notification.ogg differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/phone.ogg b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/phone.ogg
new file mode 100644
index 0000000..7cd2864
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/assets/sounds/phone.ogg differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/fonts/MaterialIcons-Regular.otf b/appimage/Extera.AppDir/data/flutter_assets/fonts/MaterialIcons-Regular.otf
new file mode 100644
index 0000000..8c99266
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/fonts/MaterialIcons-Regular.otf differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf b/appimage/Extera.AppDir/data/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf
new file mode 100644
index 0000000..d580ce7
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png b/appimage/Extera.AppDir/data/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png
new file mode 100644
index 0000000..8603d0a
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window-dark.css b/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window-dark.css
new file mode 100644
index 0000000..a714179
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window-dark.css
@@ -0,0 +1 @@
+window{background-color:#252525}window.csd.unified decoration-overlay{box-shadow:none}window.csd.unified:not(.solid-csd):not(.fullscreen):not(.maximized) decoration-overlay{box-shadow:inset 0 0 0 1px rgba(255,255,255,.07)}window.csd.unified decoration{box-shadow:0 3px 9px 1px rgba(0,0,0,.5)}window.csd.unified decoration:backdrop{box-shadow:0 3px 9px 1px rgba(0,0,0,0),0 2px 6px 2px rgba(0,0,0,.2)}headerbar{min-height:47px;background:#303030;box-shadow:inset 0 -1px rgba(0,0,0,.36);border:none}headerbar:backdrop{background:#242424}button.titlebutton{padding:4px;margin:1px}
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window.css b/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window.css
new file mode 100644
index 0000000..662c93c
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/packages/handy_window/assets/handy-window.css
@@ -0,0 +1 @@
+window{background-color:#fff}window.csd.unified decoration-overlay{box-shadow:none}window.csd.unified:not(.solid-csd):not(.fullscreen):not(.maximized) decoration-overlay{box-shadow:inset 0 0 0 1px rgba(255,255,255,.07)}window.csd.unified decoration{box-shadow:0 3px 9px 1px rgba(0,0,0,.5)}window.csd.unified decoration:backdrop{box-shadow:0 3px 9px 1px rgba(0,0,0,0),0 2px 6px 2px rgba(0,0,0,.2)}headerbar{min-height:47px;background:#ebebeb;box-shadow:inset 0 -1px rgba(0,0,0,.07);border:none}headerbar:backdrop{background:#fafafa}button.titlebutton{padding:4px;margin:1px}
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/material/lib/fonts/material.ttf b/appimage/Extera.AppDir/data/flutter_assets/packages/material/lib/fonts/material.ttf
new file mode 100644
index 0000000..84c815d
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/packages/material/lib/fonts/material.ttf differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.fixwebmduration.js b/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.fixwebmduration.js
new file mode 100644
index 0000000..dbb3cc6
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.fixwebmduration.js
@@ -0,0 +1,507 @@
+(function (name, definition) {
+ window.jsFixWebmDuration = definition();
+})('fix-webm-duration', function () {
+ /*
+ * This is the list of possible WEBM file sections by their IDs.
+ * Possible types: Container, Binary, Uint, Int, String, Float, Date
+ */
+ var sections = {
+ 0xa45dfa3: { name: 'EBML', type: 'Container' },
+ 0x286: { name: 'EBMLVersion', type: 'Uint' },
+ 0x2f7: { name: 'EBMLReadVersion', type: 'Uint' },
+ 0x2f2: { name: 'EBMLMaxIDLength', type: 'Uint' },
+ 0x2f3: { name: 'EBMLMaxSizeLength', type: 'Uint' },
+ 0x282: { name: 'DocType', type: 'String' },
+ 0x287: { name: 'DocTypeVersion', type: 'Uint' },
+ 0x285: { name: 'DocTypeReadVersion', type: 'Uint' },
+ 0x6c: { name: 'Void', type: 'Binary' },
+ 0x3f: { name: 'CRC-32', type: 'Binary' },
+ 0xb538667: { name: 'SignatureSlot', type: 'Container' },
+ 0x3e8a: { name: 'SignatureAlgo', type: 'Uint' },
+ 0x3e9a: { name: 'SignatureHash', type: 'Uint' },
+ 0x3ea5: { name: 'SignaturePublicKey', type: 'Binary' },
+ 0x3eb5: { name: 'Signature', type: 'Binary' },
+ 0x3e5b: { name: 'SignatureElements', type: 'Container' },
+ 0x3e7b: { name: 'SignatureElementList', type: 'Container' },
+ 0x2532: { name: 'SignedElement', type: 'Binary' },
+ 0x8538067: { name: 'Segment', type: 'Container' },
+ 0x14d9b74: { name: 'SeekHead', type: 'Container' },
+ 0xdbb: { name: 'Seek', type: 'Container' },
+ 0x13ab: { name: 'SeekID', type: 'Binary' },
+ 0x13ac: { name: 'SeekPosition', type: 'Uint' },
+ 0x549a966: { name: 'Info', type: 'Container' },
+ 0x33a4: { name: 'SegmentUID', type: 'Binary' },
+ 0x3384: { name: 'SegmentFilename', type: 'String' },
+ 0x1cb923: { name: 'PrevUID', type: 'Binary' },
+ 0x1c83ab: { name: 'PrevFilename', type: 'String' },
+ 0x1eb923: { name: 'NextUID', type: 'Binary' },
+ 0x1e83bb: { name: 'NextFilename', type: 'String' },
+ 0x444: { name: 'SegmentFamily', type: 'Binary' },
+ 0x2924: { name: 'ChapterTranslate', type: 'Container' },
+ 0x29fc: { name: 'ChapterTranslateEditionUID', type: 'Uint' },
+ 0x29bf: { name: 'ChapterTranslateCodec', type: 'Uint' },
+ 0x29a5: { name: 'ChapterTranslateID', type: 'Binary' },
+ 0xad7b1: { name: 'TimecodeScale', type: 'Uint' },
+ 0x489: { name: 'Duration', type: 'Float' },
+ 0x461: { name: 'DateUTC', type: 'Date' },
+ 0x3ba9: { name: 'Title', type: 'String' },
+ 0xd80: { name: 'MuxingApp', type: 'String' },
+ 0x1741: { name: 'WritingApp', type: 'String' },
+ // 0xf43b675: { name: 'Cluster', type: 'Container' },
+ 0x67: { name: 'Timecode', type: 'Uint' },
+ 0x1854: { name: 'SilentTracks', type: 'Container' },
+ 0x18d7: { name: 'SilentTrackNumber', type: 'Uint' },
+ 0x27: { name: 'Position', type: 'Uint' },
+ 0x2b: { name: 'PrevSize', type: 'Uint' },
+ 0x23: { name: 'SimpleBlock', type: 'Binary' },
+ 0x20: { name: 'BlockGroup', type: 'Container' },
+ 0x21: { name: 'Block', type: 'Binary' },
+ 0x22: { name: 'BlockVirtual', type: 'Binary' },
+ 0x35a1: { name: 'BlockAdditions', type: 'Container' },
+ 0x26: { name: 'BlockMore', type: 'Container' },
+ 0x6e: { name: 'BlockAddID', type: 'Uint' },
+ 0x25: { name: 'BlockAdditional', type: 'Binary' },
+ 0x1b: { name: 'BlockDuration', type: 'Uint' },
+ 0x7a: { name: 'ReferencePriority', type: 'Uint' },
+ 0x7b: { name: 'ReferenceBlock', type: 'Int' },
+ 0x7d: { name: 'ReferenceVirtual', type: 'Int' },
+ 0x24: { name: 'CodecState', type: 'Binary' },
+ 0x35a2: { name: 'DiscardPadding', type: 'Int' },
+ 0xe: { name: 'Slices', type: 'Container' },
+ 0x68: { name: 'TimeSlice', type: 'Container' },
+ 0x4c: { name: 'LaceNumber', type: 'Uint' },
+ 0x4d: { name: 'FrameNumber', type: 'Uint' },
+ 0x4b: { name: 'BlockAdditionID', type: 'Uint' },
+ 0x4e: { name: 'Delay', type: 'Uint' },
+ 0x4f: { name: 'SliceDuration', type: 'Uint' },
+ 0x48: { name: 'ReferenceFrame', type: 'Container' },
+ 0x49: { name: 'ReferenceOffset', type: 'Uint' },
+ 0x4a: { name: 'ReferenceTimeCode', type: 'Uint' },
+ 0x2f: { name: 'EncryptedBlock', type: 'Binary' },
+ 0x654ae6b: { name: 'Tracks', type: 'Container' },
+ 0x2e: { name: 'TrackEntry', type: 'Container' },
+ 0x57: { name: 'TrackNumber', type: 'Uint' },
+ 0x33c5: { name: 'TrackUID', type: 'Uint' },
+ 0x3: { name: 'TrackType', type: 'Uint' },
+ 0x39: { name: 'FlagEnabled', type: 'Uint' },
+ 0x8: { name: 'FlagDefault', type: 'Uint' },
+ 0x15aa: { name: 'FlagForced', type: 'Uint' },
+ 0x1c: { name: 'FlagLacing', type: 'Uint' },
+ 0x2de7: { name: 'MinCache', type: 'Uint' },
+ 0x2df8: { name: 'MaxCache', type: 'Uint' },
+ 0x3e383: { name: 'DefaultDuration', type: 'Uint' },
+ 0x34e7a: { name: 'DefaultDecodedFieldDuration', type: 'Uint' },
+ 0x3314f: { name: 'TrackTimecodeScale', type: 'Float' },
+ 0x137f: { name: 'TrackOffset', type: 'Int' },
+ 0x15ee: { name: 'MaxBlockAdditionID', type: 'Uint' },
+ 0x136e: { name: 'Name', type: 'String' },
+ 0x2b59c: { name: 'Language', type: 'String' },
+ 0x6: { name: 'CodecID', type: 'String' },
+ 0x23a2: { name: 'CodecPrivate', type: 'Binary' },
+ 0x58688: { name: 'CodecName', type: 'String' },
+ 0x3446: { name: 'AttachmentLink', type: 'Uint' },
+ 0x1a9697: { name: 'CodecSettings', type: 'String' },
+ 0x1b4040: { name: 'CodecInfoURL', type: 'String' },
+ 0x6b240: { name: 'CodecDownloadURL', type: 'String' },
+ 0x2a: { name: 'CodecDecodeAll', type: 'Uint' },
+ 0x2fab: { name: 'TrackOverlay', type: 'Uint' },
+ 0x16aa: { name: 'CodecDelay', type: 'Uint' },
+ 0x16bb: { name: 'SeekPreRoll', type: 'Uint' },
+ 0x2624: { name: 'TrackTranslate', type: 'Container' },
+ 0x26fc: { name: 'TrackTranslateEditionUID', type: 'Uint' },
+ 0x26bf: { name: 'TrackTranslateCodec', type: 'Uint' },
+ 0x26a5: { name: 'TrackTranslateTrackID', type: 'Binary' },
+ 0x60: { name: 'Video', type: 'Container' },
+ 0x1a: { name: 'FlagInterlaced', type: 'Uint' },
+ 0x13b8: { name: 'StereoMode', type: 'Uint' },
+ 0x13c0: { name: 'AlphaMode', type: 'Uint' },
+ 0x13b9: { name: 'OldStereoMode', type: 'Uint' },
+ 0x30: { name: 'PixelWidth', type: 'Uint' },
+ 0x3a: { name: 'PixelHeight', type: 'Uint' },
+ 0x14aa: { name: 'PixelCropBottom', type: 'Uint' },
+ 0x14bb: { name: 'PixelCropTop', type: 'Uint' },
+ 0x14cc: { name: 'PixelCropLeft', type: 'Uint' },
+ 0x14dd: { name: 'PixelCropRight', type: 'Uint' },
+ 0x14b0: { name: 'DisplayWidth', type: 'Uint' },
+ 0x14ba: { name: 'DisplayHeight', type: 'Uint' },
+ 0x14b2: { name: 'DisplayUnit', type: 'Uint' },
+ 0x14b3: { name: 'AspectRatioType', type: 'Uint' },
+ 0xeb524: { name: 'ColourSpace', type: 'Binary' },
+ 0xfb523: { name: 'GammaValue', type: 'Float' },
+ 0x383e3: { name: 'FrameRate', type: 'Float' },
+ 0x61: { name: 'Audio', type: 'Container' },
+ 0x35: { name: 'SamplingFrequency', type: 'Float' },
+ 0x38b5: { name: 'OutputSamplingFrequency', type: 'Float' },
+ 0x1f: { name: 'Channels', type: 'Uint' },
+ 0x3d7b: { name: 'ChannelPositions', type: 'Binary' },
+ 0x2264: { name: 'BitDepth', type: 'Uint' },
+ 0x62: { name: 'TrackOperation', type: 'Container' },
+ 0x63: { name: 'TrackCombinePlanes', type: 'Container' },
+ 0x64: { name: 'TrackPlane', type: 'Container' },
+ 0x65: { name: 'TrackPlaneUID', type: 'Uint' },
+ 0x66: { name: 'TrackPlaneType', type: 'Uint' },
+ 0x69: { name: 'TrackJoinBlocks', type: 'Container' },
+ 0x6d: { name: 'TrackJoinUID', type: 'Uint' },
+ 0x40: { name: 'TrickTrackUID', type: 'Uint' },
+ 0x41: { name: 'TrickTrackSegmentUID', type: 'Binary' },
+ 0x46: { name: 'TrickTrackFlag', type: 'Uint' },
+ 0x47: { name: 'TrickMasterTrackUID', type: 'Uint' },
+ 0x44: { name: 'TrickMasterTrackSegmentUID', type: 'Binary' },
+ 0x2d80: { name: 'ContentEncodings', type: 'Container' },
+ 0x2240: { name: 'ContentEncoding', type: 'Container' },
+ 0x1031: { name: 'ContentEncodingOrder', type: 'Uint' },
+ 0x1032: { name: 'ContentEncodingScope', type: 'Uint' },
+ 0x1033: { name: 'ContentEncodingType', type: 'Uint' },
+ 0x1034: { name: 'ContentCompression', type: 'Container' },
+ 0x254: { name: 'ContentCompAlgo', type: 'Uint' },
+ 0x255: { name: 'ContentCompSettings', type: 'Binary' },
+ 0x1035: { name: 'ContentEncryption', type: 'Container' },
+ 0x7e1: { name: 'ContentEncAlgo', type: 'Uint' },
+ 0x7e2: { name: 'ContentEncKeyID', type: 'Binary' },
+ 0x7e3: { name: 'ContentSignature', type: 'Binary' },
+ 0x7e4: { name: 'ContentSigKeyID', type: 'Binary' },
+ 0x7e5: { name: 'ContentSigAlgo', type: 'Uint' },
+ 0x7e6: { name: 'ContentSigHashAlgo', type: 'Uint' },
+ 0xc53bb6b: { name: 'Cues', type: 'Container' },
+ 0x3b: { name: 'CuePoint', type: 'Container' },
+ 0x33: { name: 'CueTime', type: 'Uint' },
+ 0x37: { name: 'CueTrackPositions', type: 'Container' },
+ 0x77: { name: 'CueTrack', type: 'Uint' },
+ 0x71: { name: 'CueClusterPosition', type: 'Uint' },
+ 0x70: { name: 'CueRelativePosition', type: 'Uint' },
+ 0x32: { name: 'CueDuration', type: 'Uint' },
+ 0x1378: { name: 'CueBlockNumber', type: 'Uint' },
+ 0x6a: { name: 'CueCodecState', type: 'Uint' },
+ 0x5b: { name: 'CueReference', type: 'Container' },
+ 0x16: { name: 'CueRefTime', type: 'Uint' },
+ 0x17: { name: 'CueRefCluster', type: 'Uint' },
+ 0x135f: { name: 'CueRefNumber', type: 'Uint' },
+ 0x6b: { name: 'CueRefCodecState', type: 'Uint' },
+ 0x941a469: { name: 'Attachments', type: 'Container' },
+ 0x21a7: { name: 'AttachedFile', type: 'Container' },
+ 0x67e: { name: 'FileDescription', type: 'String' },
+ 0x66e: { name: 'FileName', type: 'String' },
+ 0x660: { name: 'FileMimeType', type: 'String' },
+ 0x65c: { name: 'FileData', type: 'Binary' },
+ 0x6ae: { name: 'FileUID', type: 'Uint' },
+ 0x675: { name: 'FileReferral', type: 'Binary' },
+ 0x661: { name: 'FileUsedStartTime', type: 'Uint' },
+ 0x662: { name: 'FileUsedEndTime', type: 'Uint' },
+ 0x43a770: { name: 'Chapters', type: 'Container' },
+ 0x5b9: { name: 'EditionEntry', type: 'Container' },
+ 0x5bc: { name: 'EditionUID', type: 'Uint' },
+ 0x5bd: { name: 'EditionFlagHidden', type: 'Uint' },
+ 0x5db: { name: 'EditionFlagDefault', type: 'Uint' },
+ 0x5dd: { name: 'EditionFlagOrdered', type: 'Uint' },
+ 0x36: { name: 'ChapterAtom', type: 'Container' },
+ 0x33c4: { name: 'ChapterUID', type: 'Uint' },
+ 0x1654: { name: 'ChapterStringUID', type: 'String' },
+ 0x11: { name: 'ChapterTimeStart', type: 'Uint' },
+ 0x12: { name: 'ChapterTimeEnd', type: 'Uint' },
+ 0x18: { name: 'ChapterFlagHidden', type: 'Uint' },
+ 0x598: { name: 'ChapterFlagEnabled', type: 'Uint' },
+ 0x2e67: { name: 'ChapterSegmentUID', type: 'Binary' },
+ 0x2ebc: { name: 'ChapterSegmentEditionUID', type: 'Uint' },
+ 0x23c3: { name: 'ChapterPhysicalEquiv', type: 'Uint' },
+ 0xf: { name: 'ChapterTrack', type: 'Container' },
+ 0x9: { name: 'ChapterTrackNumber', type: 'Uint' },
+ 0x0: { name: 'ChapterDisplay', type: 'Container' },
+ 0x5: { name: 'ChapString', type: 'String' },
+ 0x37c: { name: 'ChapLanguage', type: 'String' },
+ 0x37e: { name: 'ChapCountry', type: 'String' },
+ 0x2944: { name: 'ChapProcess', type: 'Container' },
+ 0x2955: { name: 'ChapProcessCodecID', type: 'Uint' },
+ 0x50d: { name: 'ChapProcessPrivate', type: 'Binary' },
+ 0x2911: { name: 'ChapProcessCommand', type: 'Container' },
+ 0x2922: { name: 'ChapProcessTime', type: 'Uint' },
+ 0x2933: { name: 'ChapProcessData', type: 'Binary' },
+ 0x254c367: { name: 'Tags', type: 'Container' },
+ 0x3373: { name: 'Tag', type: 'Container' },
+ 0x23c0: { name: 'Targets', type: 'Container' },
+ 0x28ca: { name: 'TargetTypeValue', type: 'Uint' },
+ 0x23ca: { name: 'TargetType', type: 'String' },
+ 0x23c5: { name: 'TagTrackUID', type: 'Uint' },
+ 0x23c9: { name: 'TagEditionUID', type: 'Uint' },
+ 0x23c4: { name: 'TagChapterUID', type: 'Uint' },
+ 0x23c6: { name: 'TagAttachmentUID', type: 'Uint' },
+ 0x27c8: { name: 'SimpleTag', type: 'Container' },
+ 0x5a3: { name: 'TagName', type: 'String' },
+ 0x47a: { name: 'TagLanguage', type: 'String' },
+ 0x484: { name: 'TagDefault', type: 'Uint' },
+ 0x487: { name: 'TagString', type: 'String' },
+ 0x485: { name: 'TagBinary', type: 'Binary' }
+ };
+
+ function doInherit(newClass, baseClass) {
+ newClass.prototype = Object.create(baseClass.prototype);
+ newClass.prototype.constructor = newClass;
+ }
+
+ function WebmBase(name, type) {
+ this.name = name || 'Unknown';
+ this.type = type || 'Unknown';
+ }
+ WebmBase.prototype.updateBySource = function () { };
+ WebmBase.prototype.setSource = function (source) {
+ this.source = source;
+ this.updateBySource();
+ };
+ WebmBase.prototype.updateByData = function () { };
+ WebmBase.prototype.setData = function (data) {
+ this.data = data;
+ this.updateByData();
+ };
+
+ function WebmUint(name, type) {
+ WebmBase.call(this, name, type || 'Uint');
+ }
+ doInherit(WebmUint, WebmBase);
+ function padHex(hex) {
+ return hex.length % 2 === 1 ? '0' + hex : hex;
+ }
+ WebmUint.prototype.updateBySource = function () {
+ // use hex representation of a number instead of number value
+ this.data = '';
+ for (var i = 0; i < this.source.length; i++) {
+ var hex = this.source[i].toString(16);
+ this.data += padHex(hex);
+ }
+ };
+ WebmUint.prototype.updateByData = function () {
+ var length = this.data.length / 2;
+ this.source = new Uint8Array(length);
+ for (var i = 0; i < length; i++) {
+ var hex = this.data.substr(i * 2, 2);
+ this.source[i] = parseInt(hex, 16);
+ }
+ };
+ WebmUint.prototype.getValue = function () {
+ return parseInt(this.data, 16);
+ };
+ WebmUint.prototype.setValue = function (value) {
+ this.setData(padHex(value.toString(16)));
+ };
+
+ function WebmFloat(name, type) {
+ WebmBase.call(this, name, type || 'Float');
+ }
+ doInherit(WebmFloat, WebmBase);
+ WebmFloat.prototype.getFloatArrayType = function () {
+ return this.source && this.source.length === 4 ? Float32Array : Float64Array;
+ };
+ WebmFloat.prototype.updateBySource = function () {
+ var byteArray = this.source.reverse();
+ var floatArrayType = this.getFloatArrayType();
+ var floatArray = new floatArrayType(byteArray.buffer);
+ this.data = floatArray[0];
+ };
+ WebmFloat.prototype.updateByData = function () {
+ var floatArrayType = this.getFloatArrayType();
+ var floatArray = new floatArrayType([this.data]);
+ var byteArray = new Uint8Array(floatArray.buffer);
+ this.source = byteArray.reverse();
+ };
+ WebmFloat.prototype.getValue = function () {
+ return this.data;
+ };
+ WebmFloat.prototype.setValue = function (value) {
+ this.setData(value);
+ };
+
+ function WebmContainer(name, type) {
+ WebmBase.call(this, name, type || 'Container');
+ }
+ doInherit(WebmContainer, WebmBase);
+ WebmContainer.prototype.readByte = function () {
+ return this.source[this.offset++];
+ };
+ WebmContainer.prototype.readUint = function () {
+ var firstByte = this.readByte();
+ var bytes = 8 - firstByte.toString(2).length;
+ var value = firstByte - (1 << (7 - bytes));
+ for (var i = 0; i < bytes; i++) {
+ // don't use bit operators to support x86
+ value *= 256;
+ value += this.readByte();
+ }
+ return value;
+ };
+ WebmContainer.prototype.updateBySource = function () {
+ this.data = [];
+ for (this.offset = 0; this.offset < this.source.length; this.offset = end) {
+ var id = this.readUint();
+ var len = this.readUint();
+ var end = Math.min(this.offset + len, this.source.length);
+ var data = this.source.slice(this.offset, end);
+
+ var info = sections[id] || { name: 'Unknown', type: 'Unknown' };
+ var ctr = WebmBase;
+ switch (info.type) {
+ case 'Container':
+ ctr = WebmContainer;
+ break;
+ case 'Uint':
+ ctr = WebmUint;
+ break;
+ case 'Float':
+ ctr = WebmFloat;
+ break;
+ }
+ var section = new ctr(info.name, info.type);
+ section.setSource(data);
+ this.data.push({
+ id: id,
+ idHex: id.toString(16),
+ data: section
+ });
+ }
+ };
+ WebmContainer.prototype.writeUint = function (x, draft) {
+ for (var bytes = 1, flag = 0x80; x >= flag && bytes < 8; bytes++, flag *= 0x80) { }
+
+ if (!draft) {
+ var value = flag + x;
+ for (var i = bytes - 1; i >= 0; i--) {
+ // don't use bit operators to support x86
+ var c = value % 256;
+ this.source[this.offset + i] = c;
+ value = (value - c) / 256;
+ }
+ }
+
+ this.offset += bytes;
+ };
+ WebmContainer.prototype.writeSections = function (draft) {
+ this.offset = 0;
+ for (var i = 0; i < this.data.length; i++) {
+ var section = this.data[i],
+ content = section.data.source,
+ contentLength = content.length;
+ this.writeUint(section.id, draft);
+ this.writeUint(contentLength, draft);
+ if (!draft) {
+ this.source.set(content, this.offset);
+ }
+ this.offset += contentLength;
+ }
+ return this.offset;
+ };
+ WebmContainer.prototype.updateByData = function () {
+ // run without accessing this.source to determine total length - need to know it to create Uint8Array
+ var length = this.writeSections('draft');
+ this.source = new Uint8Array(length);
+ // now really write data
+ this.writeSections();
+ };
+ WebmContainer.prototype.getSectionById = function (id) {
+ for (var i = 0; i < this.data.length; i++) {
+ var section = this.data[i];
+ if (section.id === id) {
+ return section.data;
+ }
+ }
+ return null;
+ };
+
+ function WebmFile(source) {
+ WebmContainer.call(this, 'File', 'File');
+ this.setSource(source);
+ }
+ doInherit(WebmFile, WebmContainer);
+ WebmFile.prototype.fixDuration = function (duration, options) {
+ var logger = options && options.logger;
+ if (logger === undefined) {
+ logger = function (message) {
+ console.log(message);
+ };
+ } else if (!logger) {
+ logger = function () { };
+ }
+
+ var segmentSection = this.getSectionById(0x8538067);
+ if (!segmentSection) {
+ logger('[fix-webm-duration] Segment section is missing');
+ return false;
+ }
+
+ var infoSection = segmentSection.getSectionById(0x549a966);
+ if (!infoSection) {
+ logger('[fix-webm-duration] Info section is missing');
+ return false;
+ }
+
+ var timeScaleSection = infoSection.getSectionById(0xad7b1);
+ if (!timeScaleSection) {
+ logger('[fix-webm-duration] TimecodeScale section is missing');
+ return false;
+ }
+
+ var durationSection = infoSection.getSectionById(0x489);
+ if (durationSection) {
+ if (durationSection.getValue() <= 0) {
+ logger('[fix-webm-duration] Duration section is present, but the value is empty. Applying ' + duration.toLocaleString() + ' ms.');
+ durationSection.setValue(duration);
+ } else {
+ logger('[fix-webm-duration] Duration section is present');
+ return false;
+ }
+ } else {
+ logger('[fix-webm-duration] Duration section is missing. Applying ' + duration.toLocaleString() + ' ms.');
+ // append Duration section
+ durationSection = new WebmFloat('Duration', 'Float');
+ durationSection.setValue(duration);
+ infoSection.data.push({
+ id: 0x489,
+ data: durationSection
+ });
+ }
+
+ // set default time scale to 1 millisecond (1000000 nanoseconds)
+ timeScaleSection.setValue(1000000);
+ infoSection.updateByData();
+ segmentSection.updateByData();
+ this.updateByData();
+
+ return true;
+ };
+ WebmFile.prototype.toBlob = function (mimeType) {
+ return new Blob([this.source.buffer], { type: mimeType || 'audio/webm' });
+ };
+
+ function fixWebmDuration(blob, duration, callback, options) {
+ // The callback may be omitted - then the third argument is options
+ if (typeof callback === "object") {
+ options = callback;
+ callback = undefined;
+ }
+
+ if (!callback) {
+ return new Promise(function (resolve) {
+ fixWebmDuration(blob, duration, resolve, options);
+ });
+ }
+
+ try {
+ var reader = new FileReader();
+ reader.onloadend = function () {
+ try {
+ var file = new WebmFile(new Uint8Array(reader.result));
+ if (file.fixDuration(duration, options)) {
+ blob = file.toBlob(blob.type);
+ }
+ } catch (ex) {
+ // ignore
+ }
+ callback(blob);
+ };
+ reader.readAsArrayBuffer(blob);
+ } catch (ex) {
+ callback(blob);
+ }
+ }
+
+ // Support AMD import default
+ fixWebmDuration.default = fixWebmDuration;
+
+ return fixWebmDuration;
+});
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.worklet.js b/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.worklet.js
new file mode 100644
index 0000000..90952fc
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/packages/record_web/assets/js/record.worklet.js
@@ -0,0 +1,400 @@
+class RecorderProcessor extends AudioWorkletProcessor {
+ static get parameterDescriptors() {
+ return [
+ {
+ name: 'numChannels',
+ defaultValue: 1,
+ minValue: 1,
+ maxValue: 16
+ },
+ {
+ name: 'sampleRate',
+ defaultValue: 48000,
+ minValue: 8000,
+ maxValue: 96000
+ }
+ ];
+ }
+
+ // Buffer size compromise between size and process call frequency
+ _bufferSize = 4096
+ // The current buffer fill level
+ _bytesWritten = 0
+ // Buffer per channel
+ _buffers = []
+ // Resampler (passthrough, down or up)
+ _resampler = null
+ // Config
+ _numChannels = 1
+ _sampleRate = 48000
+
+ constructor(options) {
+ super(options)
+
+ this._numChannels = options.parameterData.numChannels
+ this._sampleRate = options.parameterData.sampleRate
+
+ // Resampler(current context sample rate, desired sample rate, num channels, buffer size)
+ // num channels is always 1 since we resample after interleaving channels
+ this._resampler = new Resampler(sampleRate, this._sampleRate, 1, this._bufferSize * this._numChannels)
+
+ this.initBuffers()
+ }
+
+ initBuffers() {
+ this._bytesWritten = 0
+ this._buffers = []
+
+ for (let channel = 0; channel < this._numChannels; channel++) {
+ this._buffers[channel] = []
+ }
+ }
+
+ /**
+ * @returns {boolean}
+ */
+ isBufferEmpty() {
+ return this._bytesWritten === 0
+ }
+
+ /**
+ * @returns {boolean}
+ */
+ isBufferFull() {
+ return this._bytesWritten >= this._bufferSize
+ }
+
+ /**
+ * @param {Float32Array[][]} inputs
+ * @returns {boolean}
+ */
+ process(inputs) {
+ if (this.isBufferFull()) {
+ this.flush()
+ }
+
+ const input = inputs[0]
+
+ if (input.length == 0) {
+ // Sometimes, Firefox doesn't give any input. Skip this frame to not fail.
+ return true
+ }
+
+ for (let channel = 0; channel < this._numChannels; channel++) {
+ // Push a copy of the array.
+ // The underlying implementation may reuse it which will break the recording.
+ this._buffers[channel].push([...input[channel]])
+ }
+
+ this._bytesWritten += input[0].length
+
+ return true
+ }
+
+ flush() {
+ let channels = []
+ for (let channel = 0; channel < this._numChannels; channel++) {
+ channels.push(this.mergeFloat32Arrays(this._buffers[channel], this._bytesWritten))
+ }
+
+ let interleaved = this.interleave(channels)
+
+ let resampled = this._resampler.resample(interleaved)
+
+ this.port.postMessage(this.floatTo16BitPCM(resampled))
+
+ this.initBuffers()
+ }
+
+ mergeFloat32Arrays(arrays, bytesWritten) {
+ let result = new Float32Array(bytesWritten)
+ var offset = 0
+
+ for (let i = 0; i < arrays.length; i++) {
+ result.set(arrays[i], offset)
+ offset += arrays[i].length
+ }
+
+ return result
+ }
+
+ // Interleave data from channels from LLLLRRRR to LRLRLRLR
+ interleave(channels) {
+ if (channels === 1) {
+ return channels[0]
+ }
+
+ var length = 0
+ for (let i = 0; i < channels.length; i++) {
+ length += channels[i].length
+ }
+
+ let result = new Float32Array(length)
+
+ var index = 0
+ var inputIndex = 0
+
+ while (index < length) {
+ for (let i = 0; i < channels.length; i++) {
+ result[index] = channels[i][inputIndex]
+ index++
+ }
+
+ inputIndex++
+ }
+
+ return result
+ }
+
+ floatTo16BitPCM(input) {
+ let output = new DataView(new ArrayBuffer(input.length * 2))
+
+ for (let i = 0; i < input.length; i++) {
+ let s = Math.max(-1, Math.min(1, input[i]))
+ let s16 = s < 0 ? s * 0x8000 : s * 0x7FFF
+ output.setInt16(i * 2, s16, true)
+ }
+
+ return new Int16Array(output.buffer)
+ }
+}
+
+class Resampler {
+ constructor(fromSampleRate, toSampleRate, channels, inputBufferSize) {
+
+ if (!fromSampleRate || !toSampleRate || !channels) {
+ throw (new Error("Invalid settings specified for the resampler."));
+ }
+ this.resampler = null;
+ this.fromSampleRate = fromSampleRate;
+ this.toSampleRate = toSampleRate;
+ this.channels = channels || 0;
+ this.inputBufferSize = inputBufferSize;
+ this.initialize()
+ }
+
+ initialize() {
+ if (this.fromSampleRate == this.toSampleRate) {
+
+ // Setup resampler bypass - Resampler just returns what was passed through
+ this.resampler = (buffer) => {
+ return buffer
+ };
+ this.ratioWeight = 1;
+
+ } else {
+ if (this.fromSampleRate < this.toSampleRate) {
+
+ // Use generic linear interpolation if upsampling,
+ // as linear interpolation produces a gradient that we want
+ // and works fine with two input sample points per output in this case.
+ this.linearInterpolation();
+ this.lastWeight = 1;
+
+ } else {
+
+ // Custom resampler I wrote that doesn't skip samples
+ // like standard linear interpolation in high downsampling.
+ // This is more accurate than linear interpolation on downsampling.
+ this.multiTap();
+ this.tailExists = false;
+ this.lastWeight = 0;
+ }
+
+ // Initialize the internal buffer:
+ this.initializeBuffers();
+ this.ratioWeight = this.fromSampleRate / this.toSampleRate;
+ }
+ }
+
+ bufferSlice(sliceAmount) {
+
+ //Typed array and normal array buffer section referencing:
+ try {
+ return this.outputBuffer.subarray(0, sliceAmount);
+ }
+ catch (error) {
+ try {
+ //Regular array pass:
+ this.outputBuffer.length = sliceAmount;
+ return this.outputBuffer;
+ }
+ catch (error) {
+ //Nightly Firefox 4 used to have the subarray function named as slice:
+ return this.outputBuffer.slice(0, sliceAmount);
+ }
+ }
+ }
+
+ initializeBuffers() {
+ this.outputBufferSize = (Math.ceil(this.inputBufferSize * this.toSampleRate / this.fromSampleRate / this.channels * 1.000000476837158203125) + this.channels) + this.channels;
+ try {
+ this.outputBuffer = new Float32Array(this.outputBufferSize);
+ this.lastOutput = new Float32Array(this.channels);
+ }
+ catch (error) {
+ this.outputBuffer = [];
+ this.lastOutput = [];
+ }
+ }
+
+ linearInterpolation() {
+ this.resampler = (buffer) => {
+ let bufferLength = buffer.length,
+ channels = this.channels,
+ outLength,
+ ratioWeight,
+ weight,
+ firstWeight,
+ secondWeight,
+ sourceOffset,
+ outputOffset,
+ outputBuffer,
+ channel;
+
+ if ((bufferLength % channels) !== 0) {
+ throw (new Error("Buffer was of incorrect sample length."));
+ }
+ if (bufferLength <= 0) {
+ return [];
+ }
+
+ outLength = this.outputBufferSize;
+ ratioWeight = this.ratioWeight;
+ weight = this.lastWeight;
+ firstWeight = 0;
+ secondWeight = 0;
+ sourceOffset = 0;
+ outputOffset = 0;
+ outputBuffer = this.outputBuffer;
+
+ for (; weight < 1; weight += ratioWeight) {
+ secondWeight = weight % 1;
+ firstWeight = 1 - secondWeight;
+ this.lastWeight = weight % 1;
+ for (channel = 0; channel < this.channels; ++channel) {
+ outputBuffer[outputOffset++] = (this.lastOutput[channel] * firstWeight) + (buffer[channel] * secondWeight);
+ }
+ }
+ weight -= 1;
+ for (bufferLength -= channels, sourceOffset = Math.floor(weight) * channels; outputOffset < outLength && sourceOffset < bufferLength;) {
+ secondWeight = weight % 1;
+ firstWeight = 1 - secondWeight;
+ for (channel = 0; channel < this.channels; ++channel) {
+ outputBuffer[outputOffset++] = (buffer[sourceOffset + ((channel > 0) ? (channel) : 0)] * firstWeight) + (buffer[sourceOffset + (channels + channel)] * secondWeight);
+ }
+ weight += ratioWeight;
+ sourceOffset = Math.floor(weight) * channels;
+ }
+ for (channel = 0; channel < channels; ++channel) {
+ this.lastOutput[channel] = buffer[sourceOffset++];
+ }
+ return this.bufferSlice(outputOffset);
+ };
+ }
+
+ multiTap() {
+ this.resampler = (buffer) => {
+ let bufferLength = buffer.length,
+ outLength,
+ output_variable_list,
+ channels = this.channels,
+ ratioWeight,
+ weight,
+ channel,
+ actualPosition,
+ amountToNext,
+ alreadyProcessedTail,
+ outputBuffer,
+ outputOffset,
+ currentPosition;
+
+ if ((bufferLength % channels) !== 0) {
+ throw (new Error("Buffer was of incorrect sample length."));
+ }
+ if (bufferLength <= 0) {
+ return [];
+ }
+
+ outLength = this.outputBufferSize;
+ output_variable_list = [];
+ ratioWeight = this.ratioWeight;
+ weight = 0;
+ actualPosition = 0;
+ amountToNext = 0;
+ alreadyProcessedTail = !this.tailExists;
+ this.tailExists = false;
+ outputBuffer = this.outputBuffer;
+ outputOffset = 0;
+ currentPosition = 0;
+
+ for (channel = 0; channel < channels; ++channel) {
+ output_variable_list[channel] = 0;
+ }
+
+ do {
+ if (alreadyProcessedTail) {
+ weight = ratioWeight;
+ for (channel = 0; channel < channels; ++channel) {
+ output_variable_list[channel] = 0;
+ }
+ } else {
+ weight = this.lastWeight;
+ for (channel = 0; channel < channels; ++channel) {
+ output_variable_list[channel] = this.lastOutput[channel];
+ }
+ alreadyProcessedTail = true;
+ }
+ while (weight > 0 && actualPosition < bufferLength) {
+ amountToNext = 1 + actualPosition - currentPosition;
+ if (weight >= amountToNext) {
+ for (channel = 0; channel < channels; ++channel) {
+ output_variable_list[channel] += buffer[actualPosition++] * amountToNext;
+ }
+ currentPosition = actualPosition;
+ weight -= amountToNext;
+ } else {
+ for (channel = 0; channel < channels; ++channel) {
+ output_variable_list[channel] += buffer[actualPosition + ((channel > 0) ? channel : 0)] * weight;
+ }
+ currentPosition += weight;
+ weight = 0;
+ break;
+ }
+ }
+
+ if (weight === 0) {
+ for (channel = 0; channel < channels; ++channel) {
+ outputBuffer[outputOffset++] = output_variable_list[channel] / ratioWeight;
+ }
+ } else {
+ this.lastWeight = weight;
+ for (channel = 0; channel < channels; ++channel) {
+ this.lastOutput[channel] = output_variable_list[channel];
+ }
+ this.tailExists = true;
+ break;
+ }
+ } while (actualPosition < bufferLength && outputOffset < outLength);
+ return this.bufferSlice(outputOffset);
+ };
+ }
+
+ resample(buffer) {
+ if (this.fromSampleRate == this.toSampleRate) {
+ this.ratioWeight = 1;
+ } else {
+ if (this.fromSampleRate < this.toSampleRate) {
+ this.lastWeight = 1;
+ } else {
+ this.tailExists = false;
+ this.lastWeight = 0;
+ }
+ this.initializeBuffers();
+ this.ratioWeight = this.fromSampleRate / this.toSampleRate;
+ }
+ return this.resampler(buffer)
+ }
+}
+
+registerProcessor("recorder.worklet", RecorderProcessor)
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/flutter_assets/packages/wakelock_plus/assets/no_sleep.js b/appimage/Extera.AppDir/data/flutter_assets/packages/wakelock_plus/assets/no_sleep.js
new file mode 100644
index 0000000..ccfab74
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/packages/wakelock_plus/assets/no_sleep.js
@@ -0,0 +1,230 @@
+var webm =
+ 'data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='
+var mp4 =
+ 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA='
+
+var _createClass = (function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i]
+ descriptor.enumerable = descriptor.enumerable || false
+ descriptor.configurable = true
+ if ('value' in descriptor) descriptor.writable = true
+ Object.defineProperty(target, descriptor.key, descriptor)
+ }
+ }
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps)
+ if (staticProps) defineProperties(Constructor, staticProps)
+ return Constructor
+ }
+})()
+
+function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError('Cannot call a class as a function')
+ }
+}
+
+// Detect iOS browsers < version 10
+var oldIOS =
+ typeof navigator !== 'undefined' &&
+ parseFloat(
+ (
+ '' +
+ (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(
+ navigator.userAgent
+ ) || [0, ''])[1]
+ )
+ .replace('undefined', '3_2')
+ .replace('_', '.')
+ .replace('_', '')
+ ) < 10 &&
+ !window.MSStream
+
+// Detect native Wake Lock API support
+var nativeWakeLock = 'wakeLock' in navigator
+
+var NoSleep = (function () {
+ var _releasedNative = true
+ var _nativeRequestInProgress = false
+
+ function NoSleep() {
+ var _this = this
+
+ _classCallCheck(this, NoSleep)
+
+ if (nativeWakeLock) {
+ this._wakeLock = null
+ var handleVisibilityChange = function handleVisibilityChange() {
+ if (
+ _this._wakeLock !== null &&
+ document.visibilityState === 'visible'
+ ) {
+ _this.enable()
+ }
+ }
+ document.addEventListener('visibilitychange', handleVisibilityChange)
+ document.addEventListener('fullscreenchange', handleVisibilityChange)
+ } else if (oldIOS) {
+ this.noSleepTimer = null
+ } else {
+ // Set up no sleep video element
+ this.noSleepVideo = document.createElement('video')
+
+ this.noSleepVideo.setAttribute('title', 'No Sleep')
+ this.noSleepVideo.setAttribute('playsinline', '')
+
+ this._addSourceToVideo(this.noSleepVideo, 'webm', webm)
+ this._addSourceToVideo(this.noSleepVideo, 'mp4', mp4)
+
+ this.noSleepVideo.addEventListener('loadedmetadata', function () {
+ if (_this.noSleepVideo.duration <= 1) {
+ // webm source
+ _this.noSleepVideo.setAttribute('loop', '')
+ } else {
+ // mp4 source
+ _this.noSleepVideo.addEventListener('timeupdate', function () {
+ if (_this.noSleepVideo.currentTime > 0.5) {
+ _this.noSleepVideo.currentTime = Math.random()
+ }
+ })
+ }
+ })
+ }
+ }
+
+ _createClass(NoSleep, [
+ {
+ key: '_addSourceToVideo',
+ value: function _addSourceToVideo(element, type, dataURI) {
+ var source = document.createElement('source')
+ source.src = dataURI
+ source.type = 'video/' + type
+ element.appendChild(source)
+ },
+ },
+ {
+ key: 'enable',
+ value: function enable() {
+ var _this2 = this
+
+ if (nativeWakeLock) {
+ _nativeRequestInProgress = true
+ navigator.wakeLock
+ .request('screen')
+ .then(function (wakeLock) {
+ _releasedNative = false
+ _nativeRequestInProgress = false
+
+ _this2._wakeLock = wakeLock
+ _this2._wakeLock.addEventListener('release', function () {
+ _releasedNative = true
+ _this2._wakeLock = null
+ })
+ })
+ .catch(function (err) {
+ _nativeRequestInProgress = false
+ console.error(err.name + ', ' + err.message)
+ })
+ } else if (oldIOS) {
+ this.disable()
+ console.warn(
+ '\n NoSleep enabled for older iOS devices. This can interrupt\n active or long-running network requests from completing successfully.\n See https://github.com/richtr/NoSleep.js/issues/15 for more details.\n '
+ )
+ this.noSleepTimer = window.setInterval(function () {
+ if (!document.hidden) {
+ window.location.href = window.location.href.split('#')[0]
+ window.setTimeout(window.stop, 0)
+ }
+ }, 15000)
+ } else {
+ this.noSleepVideo.play()
+ }
+ },
+ },
+ {
+ key: 'disable',
+ value: function disable() {
+ if (nativeWakeLock) {
+ if (this._wakeLock != null) {
+ _releasedNative = true
+ this._wakeLock.release()
+ }
+
+ this._wakeLock = null
+ } else if (oldIOS) {
+ if (this.noSleepTimer) {
+ console.warn(
+ '\n NoSleep now disabled for older iOS devices.\n '
+ )
+ window.clearInterval(this.noSleepTimer)
+ this.noSleepTimer = null
+ }
+ } else {
+ this.noSleepVideo.pause()
+ }
+ },
+ },
+ {
+ key: 'enabled',
+ value: async function enabled() {
+ if (nativeWakeLock) {
+ if (_nativeRequestInProgress == true) {
+ // Wait until the request is done.
+ while (true) {
+ // Wait for 42 milliseconds.
+ await new Promise((resolve, reject) => setTimeout(resolve, 42))
+ if (_nativeRequestInProgress == false) {
+ break
+ }
+ }
+ }
+
+ // todo: use WakeLockSentinel.released when that is available (https://developer.mozilla.org/en-US/docs/Web/API/WakeLockSentinel/released)
+ if (_releasedNative != false) {
+ return false
+ }
+
+ return true
+ } else if (oldIOS) {
+ return this.noSleepTimer != null
+ } else {
+ if (this.noSleepVideo == undefined) {
+ return false
+ }
+
+ return !this.noSleepVideo.paused
+ }
+ },
+ },
+ ])
+
+ return NoSleep
+})()
+
+var noSleep = new NoSleep()
+
+var Wakelock = {
+ enabled: async function () {
+ try {
+ return noSleep.enabled()
+ } catch (e) {
+ return false
+ }
+ },
+ toggle: async function (enable) {
+ if (enable) {
+ noSleep.enable()
+ } else {
+ noSleep.disable()
+ }
+ },
+}
+
+if (nativeWakeLock != true) {
+ // The first non-native call sometimes throws an error, however,
+ // the error does not leak the try-catch above. Therefore, this
+ // is an easy fix that realiably works.
+ Wakelock.enabled()
+}
diff --git a/appimage/Extera.AppDir/data/flutter_assets/shaders/ink_sparkle.frag b/appimage/Extera.AppDir/data/flutter_assets/shaders/ink_sparkle.frag
new file mode 100644
index 0000000..5c91a6c
Binary files /dev/null and b/appimage/Extera.AppDir/data/flutter_assets/shaders/ink_sparkle.frag differ
diff --git a/appimage/Extera.AppDir/data/flutter_assets/version.json b/appimage/Extera.AppDir/data/flutter_assets/version.json
new file mode 100644
index 0000000..eacb670
--- /dev/null
+++ b/appimage/Extera.AppDir/data/flutter_assets/version.json
@@ -0,0 +1 @@
+{"app_name":"extera_next","version":"2.0.0","package_name":"extera_next"}
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/data/icudtl.dat b/appimage/Extera.AppDir/data/icudtl.dat
new file mode 100644
index 0000000..17e5b2a
Binary files /dev/null and b/appimage/Extera.AppDir/data/icudtl.dat differ
diff --git a/appimage/Extera.AppDir/extera.svg b/appimage/Extera.AppDir/extera.svg
new file mode 100644
index 0000000..767a86a
--- /dev/null
+++ b/appimage/Extera.AppDir/extera.svg
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/appimage/Extera.AppDir/extera_next b/appimage/Extera.AppDir/extera_next
new file mode 100755
index 0000000..fcc8c70
Binary files /dev/null and b/appimage/Extera.AppDir/extera_next differ
diff --git a/appimage/Extera.AppDir/lib/libapp.so b/appimage/Extera.AppDir/lib/libapp.so
new file mode 100644
index 0000000..046d4c3
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libapp.so differ
diff --git a/appimage/Extera.AppDir/lib/libdesktop_drop_plugin.so b/appimage/Extera.AppDir/lib/libdesktop_drop_plugin.so
new file mode 100644
index 0000000..0cfdc62
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libdesktop_drop_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libdynamic_color_plugin.so b/appimage/Extera.AppDir/lib/libdynamic_color_plugin.so
new file mode 100644
index 0000000..0fd22d8
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libdynamic_color_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libemoji_picker_flutter_plugin.so b/appimage/Extera.AppDir/lib/libemoji_picker_flutter_plugin.so
new file mode 100644
index 0000000..bebd365
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libemoji_picker_flutter_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libfile_selector_linux_plugin.so b/appimage/Extera.AppDir/lib/libfile_selector_linux_plugin.so
new file mode 100644
index 0000000..5e78878
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libfile_selector_linux_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libflutter_linux_gtk.so b/appimage/Extera.AppDir/lib/libflutter_linux_gtk.so
new file mode 100644
index 0000000..f6023c4
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libflutter_linux_gtk.so differ
diff --git a/appimage/Extera.AppDir/lib/libflutter_secure_storage_linux_plugin.so b/appimage/Extera.AppDir/lib/libflutter_secure_storage_linux_plugin.so
new file mode 100644
index 0000000..4759d19
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libflutter_secure_storage_linux_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libflutter_webrtc_plugin.so b/appimage/Extera.AppDir/lib/libflutter_webrtc_plugin.so
new file mode 100644
index 0000000..0135e10
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libflutter_webrtc_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libgtk_plugin.so b/appimage/Extera.AppDir/lib/libgtk_plugin.so
new file mode 100644
index 0000000..da9a983
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libgtk_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libhandy_flutter.so b/appimage/Extera.AppDir/lib/libhandy_flutter.so
new file mode 100644
index 0000000..e783d91
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libhandy_flutter.so differ
diff --git a/appimage/Extera.AppDir/lib/libhandy_window_plugin.so b/appimage/Extera.AppDir/lib/libhandy_window_plugin.so
new file mode 100644
index 0000000..d20758a
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libhandy_window_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libpasteboard_plugin.so b/appimage/Extera.AppDir/lib/libpasteboard_plugin.so
new file mode 100644
index 0000000..7f9781a
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libpasteboard_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/librecord_linux_plugin.so b/appimage/Extera.AppDir/lib/librecord_linux_plugin.so
new file mode 100644
index 0000000..c1e1ee2
Binary files /dev/null and b/appimage/Extera.AppDir/lib/librecord_linux_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libsqlcipher_flutter_libs_plugin.so b/appimage/Extera.AppDir/lib/libsqlcipher_flutter_libs_plugin.so
new file mode 100644
index 0000000..a01f2e4
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libsqlcipher_flutter_libs_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/liburl_launcher_linux_plugin.so b/appimage/Extera.AppDir/lib/liburl_launcher_linux_plugin.so
new file mode 100644
index 0000000..7137a19
Binary files /dev/null and b/appimage/Extera.AppDir/lib/liburl_launcher_linux_plugin.so differ
diff --git a/appimage/Extera.AppDir/lib/libvodozemac_bindings_dart.so b/appimage/Extera.AppDir/lib/libvodozemac_bindings_dart.so
new file mode 100644
index 0000000..904fb01
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libvodozemac_bindings_dart.so differ
diff --git a/appimage/Extera.AppDir/lib/libwebrtc.so b/appimage/Extera.AppDir/lib/libwebrtc.so
new file mode 100644
index 0000000..08ce7d1
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libwebrtc.so differ
diff --git a/appimage/Extera.AppDir/lib/libwindow_to_front_plugin.so b/appimage/Extera.AppDir/lib/libwindow_to_front_plugin.so
new file mode 100644
index 0000000..f535034
Binary files /dev/null and b/appimage/Extera.AppDir/lib/libwindow_to_front_plugin.so differ
diff --git a/appimage/Extera.desktop b/appimage/Extera.desktop
new file mode 100644
index 0000000..81cabe1
--- /dev/null
+++ b/appimage/Extera.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Type=Application
+Version=1.0
+Name=Extera Next
+Comment=Matrix Client. Chat with your friends
+Exec=AppRun
+Icon=extera
+Terminal=false
+Categories=Network;Chat;InstantMessaging;X-Matrix;
diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb
index dd1d0e9..79f1edb 100644
--- a/assets/l10n/intl_en.arb
+++ b/assets/l10n/intl_en.arb
@@ -2,6 +2,10 @@
"@@locale": "en",
"@@last_modified": "2025-06-05 12:38:37.885451",
"noSendPermission": "You can't send messages here",
+ "noMessagesYet": "No messages yet",
+ "longPressToRecordVoiceMessage": "Long press to record voice message.",
+ "pause": "Pause",
+ "resume": "Resume",
"@noSendPermission": {},
"alwaysUse24HourFormat": "false",
"@alwaysUse24HourFormat": {
diff --git a/assets/l10n/intl_ru.arb b/assets/l10n/intl_ru.arb
index cf6c6b5..200e428 100644
--- a/assets/l10n/intl_ru.arb
+++ b/assets/l10n/intl_ru.arb
@@ -3,6 +3,10 @@
"@@last_modified": "2021-08-14 12:41:09.903021",
"noSendPermission": "Вы не можете отправлять сообщения",
"@noSendPermission": {},
+ "noMessagesYet": "Нет сообщений",
+ "longPressToRecordVoiceMessage": "Зажмите, чтобы записать голосовое сообщение.",
+ "pause": "Пауза",
+ "resume": "Продолжить",
"alwaysUse24HourFormat": "нет",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
diff --git a/lib/config/themes.dart b/lib/config/themes.dart
index 5b04925..4e1958a 100644
--- a/lib/config/themes.dart
+++ b/lib/config/themes.dart
@@ -40,7 +40,7 @@ abstract class FluffyThemes {
BuildContext context,
Brightness brightness, [
Color? seed,
- bool? pureBlack,
+ bool? pureBlack,
]) {
final extraDarkColors = (brightness == Brightness.dark && pureBlack == true)
? {
@@ -79,6 +79,7 @@ abstract class FluffyThemes {
useMaterial3: true,
brightness: brightness,
colorScheme: colorScheme,
+ useSystemColors: true,
dividerColor: brightness == Brightness.dark
? colorScheme.surfaceContainerHighest
: colorScheme.surfaceContainer,
@@ -117,6 +118,8 @@ abstract class FluffyThemes {
isColumnMode ? colorScheme.surfaceContainer.withAlpha(128) : null,
surfaceTintColor: isColumnMode ? colorScheme.surface : null,
backgroundColor: isColumnMode ? colorScheme.surface : null,
+ actionsPadding:
+ isColumnMode ? const EdgeInsets.symmetric(horizontal: 16.0) : null,
systemOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: brightness.reversed,
@@ -139,6 +142,7 @@ abstract class FluffyThemes {
),
snackBarTheme: isColumnMode
? const SnackBarThemeData(
+ showCloseIcon: true,
behavior: SnackBarBehavior.floating,
width: FluffyThemes.columnWidth * 1.5,
)
diff --git a/lib/generated/l10n/l10n.dart b/lib/generated/l10n/l10n.dart
index 177afcf..f6273e2 100644
--- a/lib/generated/l10n/l10n.dart
+++ b/lib/generated/l10n/l10n.dart
@@ -199,6 +199,30 @@ abstract class L10n {
/// **'You can\'t send messages here'**
String get noSendPermission;
+ /// No description provided for @noMessagesYet.
+ ///
+ /// In en, this message translates to:
+ /// **'No messages yet'**
+ String get noMessagesYet;
+
+ /// No description provided for @longPressToRecordVoiceMessage.
+ ///
+ /// In en, this message translates to:
+ /// **'Long press to record voice message.'**
+ String get longPressToRecordVoiceMessage;
+
+ /// No description provided for @pause.
+ ///
+ /// In en, this message translates to:
+ /// **'Pause'**
+ String get pause;
+
+ /// No description provided for @resume.
+ ///
+ /// In en, this message translates to:
+ /// **'Resume'**
+ String get resume;
+
/// Set to true to always display time of day in 24 hour format.
///
/// In en, this message translates to:
diff --git a/lib/generated/l10n/l10n_ar.dart b/lib/generated/l10n/l10n_ar.dart
index 7d24b3f..1ed8657 100644
--- a/lib/generated/l10n/l10n_ar.dart
+++ b/lib/generated/l10n/l10n_ar.dart
@@ -11,6 +11,19 @@ class L10nAr extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_be.dart b/lib/generated/l10n/l10n_be.dart
index e21f337..093df27 100644
--- a/lib/generated/l10n/l10n_be.dart
+++ b/lib/generated/l10n/l10n_be.dart
@@ -11,6 +11,19 @@ class L10nBe extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_bn.dart b/lib/generated/l10n/l10n_bn.dart
index 5e23af8..2158fe0 100644
--- a/lib/generated/l10n/l10n_bn.dart
+++ b/lib/generated/l10n/l10n_bn.dart
@@ -11,6 +11,19 @@ class L10nBn extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_bo.dart b/lib/generated/l10n/l10n_bo.dart
index 02f7c7f..50241ed 100644
--- a/lib/generated/l10n/l10n_bo.dart
+++ b/lib/generated/l10n/l10n_bo.dart
@@ -11,6 +11,19 @@ class L10nBo extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ca.dart b/lib/generated/l10n/l10n_ca.dart
index 05a1467..9d2a928 100644
--- a/lib/generated/l10n/l10n_ca.dart
+++ b/lib/generated/l10n/l10n_ca.dart
@@ -11,6 +11,19 @@ class L10nCa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_cs.dart b/lib/generated/l10n/l10n_cs.dart
index 1ea1f9f..c676546 100644
--- a/lib/generated/l10n/l10n_cs.dart
+++ b/lib/generated/l10n/l10n_cs.dart
@@ -11,6 +11,19 @@ class L10nCs extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'Vypnuto';
diff --git a/lib/generated/l10n/l10n_de.dart b/lib/generated/l10n/l10n_de.dart
index b6223f0..31fb3b2 100644
--- a/lib/generated/l10n/l10n_de.dart
+++ b/lib/generated/l10n/l10n_de.dart
@@ -11,6 +11,19 @@ class L10nDe extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_el.dart b/lib/generated/l10n/l10n_el.dart
index 95eb3bb..3dda57c 100644
--- a/lib/generated/l10n/l10n_el.dart
+++ b/lib/generated/l10n/l10n_el.dart
@@ -11,6 +11,19 @@ class L10nEl extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_en.dart b/lib/generated/l10n/l10n_en.dart
index cf2149e..c770e14 100644
--- a/lib/generated/l10n/l10n_en.dart
+++ b/lib/generated/l10n/l10n_en.dart
@@ -11,6 +11,19 @@ class L10nEn extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_eo.dart b/lib/generated/l10n/l10n_eo.dart
index bb863ae..750e963 100644
--- a/lib/generated/l10n/l10n_eo.dart
+++ b/lib/generated/l10n/l10n_eo.dart
@@ -11,6 +11,19 @@ class L10nEo extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_es.dart b/lib/generated/l10n/l10n_es.dart
index 7b57496..34187da 100644
--- a/lib/generated/l10n/l10n_es.dart
+++ b/lib/generated/l10n/l10n_es.dart
@@ -11,6 +11,19 @@ class L10nEs extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'falso';
diff --git a/lib/generated/l10n/l10n_et.dart b/lib/generated/l10n/l10n_et.dart
index 6933dc2..152294c 100644
--- a/lib/generated/l10n/l10n_et.dart
+++ b/lib/generated/l10n/l10n_et.dart
@@ -11,6 +11,19 @@ class L10nEt extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_eu.dart b/lib/generated/l10n/l10n_eu.dart
index 406530e..25fb72a 100644
--- a/lib/generated/l10n/l10n_eu.dart
+++ b/lib/generated/l10n/l10n_eu.dart
@@ -11,6 +11,19 @@ class L10nEu extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_fa.dart b/lib/generated/l10n/l10n_fa.dart
index 8b104a6..e4da45e 100644
--- a/lib/generated/l10n/l10n_fa.dart
+++ b/lib/generated/l10n/l10n_fa.dart
@@ -11,6 +11,19 @@ class L10nFa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_fi.dart b/lib/generated/l10n/l10n_fi.dart
index 7c6e930..22d0e7e 100644
--- a/lib/generated/l10n/l10n_fi.dart
+++ b/lib/generated/l10n/l10n_fi.dart
@@ -11,6 +11,19 @@ class L10nFi extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_fil.dart b/lib/generated/l10n/l10n_fil.dart
index 4964f98..1e61fcc 100644
--- a/lib/generated/l10n/l10n_fil.dart
+++ b/lib/generated/l10n/l10n_fil.dart
@@ -11,6 +11,19 @@ class L10nFil extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_fr.dart b/lib/generated/l10n/l10n_fr.dart
index c79483f..7e872bc 100644
--- a/lib/generated/l10n/l10n_fr.dart
+++ b/lib/generated/l10n/l10n_fr.dart
@@ -11,6 +11,19 @@ class L10nFr extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_ga.dart b/lib/generated/l10n/l10n_ga.dart
index 5bb6f92..c204f86 100644
--- a/lib/generated/l10n/l10n_ga.dart
+++ b/lib/generated/l10n/l10n_ga.dart
@@ -11,6 +11,19 @@ class L10nGa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'bréagach';
diff --git a/lib/generated/l10n/l10n_gl.dart b/lib/generated/l10n/l10n_gl.dart
index 3b68412..9539583 100644
--- a/lib/generated/l10n/l10n_gl.dart
+++ b/lib/generated/l10n/l10n_gl.dart
@@ -11,6 +11,19 @@ class L10nGl extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'falso';
diff --git a/lib/generated/l10n/l10n_he.dart b/lib/generated/l10n/l10n_he.dart
index 82de3e2..8ef9c05 100644
--- a/lib/generated/l10n/l10n_he.dart
+++ b/lib/generated/l10n/l10n_he.dart
@@ -11,6 +11,19 @@ class L10nHe extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_hi.dart b/lib/generated/l10n/l10n_hi.dart
index e03e332..e3ef5b0 100644
--- a/lib/generated/l10n/l10n_hi.dart
+++ b/lib/generated/l10n/l10n_hi.dart
@@ -11,6 +11,19 @@ class L10nHi extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_hr.dart b/lib/generated/l10n/l10n_hr.dart
index e8fdae4..2f4fa52 100644
--- a/lib/generated/l10n/l10n_hr.dart
+++ b/lib/generated/l10n/l10n_hr.dart
@@ -11,6 +11,19 @@ class L10nHr extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_hu.dart b/lib/generated/l10n/l10n_hu.dart
index 567d2e3..51d1308 100644
--- a/lib/generated/l10n/l10n_hu.dart
+++ b/lib/generated/l10n/l10n_hu.dart
@@ -11,6 +11,19 @@ class L10nHu extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_ia.dart b/lib/generated/l10n/l10n_ia.dart
index 821f1c8..5530db0 100644
--- a/lib/generated/l10n/l10n_ia.dart
+++ b/lib/generated/l10n/l10n_ia.dart
@@ -11,6 +11,19 @@ class L10nIa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_id.dart b/lib/generated/l10n/l10n_id.dart
index 8114e83..c8f5597 100644
--- a/lib/generated/l10n/l10n_id.dart
+++ b/lib/generated/l10n/l10n_id.dart
@@ -11,6 +11,19 @@ class L10nId extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'tidak';
diff --git a/lib/generated/l10n/l10n_ie.dart b/lib/generated/l10n/l10n_ie.dart
index ac81d87..41c387a 100644
--- a/lib/generated/l10n/l10n_ie.dart
+++ b/lib/generated/l10n/l10n_ie.dart
@@ -11,6 +11,19 @@ class L10nIe extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_it.dart b/lib/generated/l10n/l10n_it.dart
index f0f87b2..f85665a 100644
--- a/lib/generated/l10n/l10n_it.dart
+++ b/lib/generated/l10n/l10n_it.dart
@@ -11,6 +11,19 @@ class L10nIt extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'disattivato';
diff --git a/lib/generated/l10n/l10n_ja.dart b/lib/generated/l10n/l10n_ja.dart
index b88e20e..9ac82ab 100644
--- a/lib/generated/l10n/l10n_ja.dart
+++ b/lib/generated/l10n/l10n_ja.dart
@@ -11,6 +11,19 @@ class L10nJa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ka.dart b/lib/generated/l10n/l10n_ka.dart
index 5468e69..fc04f1a 100644
--- a/lib/generated/l10n/l10n_ka.dart
+++ b/lib/generated/l10n/l10n_ka.dart
@@ -11,6 +11,19 @@ class L10nKa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ko.dart b/lib/generated/l10n/l10n_ko.dart
index 395e99a..c0f7426 100644
--- a/lib/generated/l10n/l10n_ko.dart
+++ b/lib/generated/l10n/l10n_ko.dart
@@ -11,6 +11,19 @@ class L10nKo extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_lt.dart b/lib/generated/l10n/l10n_lt.dart
index 92a774c..592aae0 100644
--- a/lib/generated/l10n/l10n_lt.dart
+++ b/lib/generated/l10n/l10n_lt.dart
@@ -11,6 +11,19 @@ class L10nLt extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_lv.dart b/lib/generated/l10n/l10n_lv.dart
index ba09a05..9401b1d 100644
--- a/lib/generated/l10n/l10n_lv.dart
+++ b/lib/generated/l10n/l10n_lv.dart
@@ -11,6 +11,19 @@ class L10nLv extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'nē';
diff --git a/lib/generated/l10n/l10n_nb.dart b/lib/generated/l10n/l10n_nb.dart
index 9ec5fc8..4eccdf3 100644
--- a/lib/generated/l10n/l10n_nb.dart
+++ b/lib/generated/l10n/l10n_nb.dart
@@ -11,6 +11,19 @@ class L10nNb extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_nl.dart b/lib/generated/l10n/l10n_nl.dart
index 0a5dd1e..d870b45 100644
--- a/lib/generated/l10n/l10n_nl.dart
+++ b/lib/generated/l10n/l10n_nl.dart
@@ -11,6 +11,19 @@ class L10nNl extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'true';
diff --git a/lib/generated/l10n/l10n_pl.dart b/lib/generated/l10n/l10n_pl.dart
index 24fb716..9c5655e 100644
--- a/lib/generated/l10n/l10n_pl.dart
+++ b/lib/generated/l10n/l10n_pl.dart
@@ -11,6 +11,19 @@ class L10nPl extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_pt.dart b/lib/generated/l10n/l10n_pt.dart
index 9b0eb9d..ee0a4ce 100644
--- a/lib/generated/l10n/l10n_pt.dart
+++ b/lib/generated/l10n/l10n_pt.dart
@@ -11,6 +11,19 @@ class L10nPt extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ro.dart b/lib/generated/l10n/l10n_ro.dart
index 5e0c83b..4868aae 100644
--- a/lib/generated/l10n/l10n_ro.dart
+++ b/lib/generated/l10n/l10n_ro.dart
@@ -11,6 +11,19 @@ class L10nRo extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ru.dart b/lib/generated/l10n/l10n_ru.dart
index 4828b09..ac3aeb2 100644
--- a/lib/generated/l10n/l10n_ru.dart
+++ b/lib/generated/l10n/l10n_ru.dart
@@ -11,6 +11,19 @@ class L10nRu extends L10n {
@override
String get noSendPermission => 'Вы не можете отправлять сообщения';
+ @override
+ String get noMessagesYet => 'Нет сообщений';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Зажмите, чтобы записать голосовое сообщение.';
+
+ @override
+ String get pause => 'Пауза';
+
+ @override
+ String get resume => 'Продолжить';
+
@override
String get alwaysUse24HourFormat => 'нет';
diff --git a/lib/generated/l10n/l10n_sk.dart b/lib/generated/l10n/l10n_sk.dart
index 0143e57..66942f2 100644
--- a/lib/generated/l10n/l10n_sk.dart
+++ b/lib/generated/l10n/l10n_sk.dart
@@ -11,6 +11,19 @@ class L10nSk extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_sl.dart b/lib/generated/l10n/l10n_sl.dart
index e6a92e4..2914d84 100644
--- a/lib/generated/l10n/l10n_sl.dart
+++ b/lib/generated/l10n/l10n_sl.dart
@@ -11,6 +11,19 @@ class L10nSl extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_sr.dart b/lib/generated/l10n/l10n_sr.dart
index 89c7258..91c0835 100644
--- a/lib/generated/l10n/l10n_sr.dart
+++ b/lib/generated/l10n/l10n_sr.dart
@@ -11,6 +11,19 @@ class L10nSr extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_sv.dart b/lib/generated/l10n/l10n_sv.dart
index 2b57a2c..531815c 100644
--- a/lib/generated/l10n/l10n_sv.dart
+++ b/lib/generated/l10n/l10n_sv.dart
@@ -11,6 +11,19 @@ class L10nSv extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_ta.dart b/lib/generated/l10n/l10n_ta.dart
index 1ea0a40..28701fc 100644
--- a/lib/generated/l10n/l10n_ta.dart
+++ b/lib/generated/l10n/l10n_ta.dart
@@ -11,6 +11,19 @@ class L10nTa extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'தவறு';
diff --git a/lib/generated/l10n/l10n_te.dart b/lib/generated/l10n/l10n_te.dart
index b43e78d..9264713 100644
--- a/lib/generated/l10n/l10n_te.dart
+++ b/lib/generated/l10n/l10n_te.dart
@@ -11,6 +11,19 @@ class L10nTe extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'తప్పుడు';
diff --git a/lib/generated/l10n/l10n_th.dart b/lib/generated/l10n/l10n_th.dart
index f0b05d9..96a63ea 100644
--- a/lib/generated/l10n/l10n_th.dart
+++ b/lib/generated/l10n/l10n_th.dart
@@ -11,6 +11,19 @@ class L10nTh extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_tr.dart b/lib/generated/l10n/l10n_tr.dart
index 00edb2b..5076833 100644
--- a/lib/generated/l10n/l10n_tr.dart
+++ b/lib/generated/l10n/l10n_tr.dart
@@ -11,6 +11,19 @@ class L10nTr extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/generated/l10n/l10n_uk.dart b/lib/generated/l10n/l10n_uk.dart
index 121ba06..3aecbbc 100644
--- a/lib/generated/l10n/l10n_uk.dart
+++ b/lib/generated/l10n/l10n_uk.dart
@@ -11,6 +11,19 @@ class L10nUk extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'ні';
diff --git a/lib/generated/l10n/l10n_vi.dart b/lib/generated/l10n/l10n_vi.dart
index c42c805..426f7cd 100644
--- a/lib/generated/l10n/l10n_vi.dart
+++ b/lib/generated/l10n/l10n_vi.dart
@@ -11,6 +11,19 @@ class L10nVi extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'Không';
diff --git a/lib/generated/l10n/l10n_zh.dart b/lib/generated/l10n/l10n_zh.dart
index f7bf045..d9e20bf 100644
--- a/lib/generated/l10n/l10n_zh.dart
+++ b/lib/generated/l10n/l10n_zh.dart
@@ -11,6 +11,19 @@ class L10nZh extends L10n {
@override
String get noSendPermission => 'You can\'t send messages here';
+ @override
+ String get noMessagesYet => 'No messages yet';
+
+ @override
+ String get longPressToRecordVoiceMessage =>
+ 'Long press to record voice message.';
+
+ @override
+ String get pause => 'Pause';
+
+ @override
+ String get resume => 'Resume';
+
@override
String get alwaysUse24HourFormat => 'false';
diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart
index 8e95006..3272989 100644
--- a/lib/pages/chat/chat.dart
+++ b/lib/pages/chat/chat.dart
@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:extera_next/pages/chat/recovered_event_dialog.dart';
import 'package:extera_next/pages/chat/translated_event_dialog.dart';
-import 'package:extera_next/utils/file_description.dart';
import 'package:extera_next/utils/matrix_sdk_extensions/synapse_admin_extension.dart';
import 'package:extera_next/utils/translator.dart';
import 'package:flutter/foundation.dart';
@@ -18,7 +17,6 @@ import 'package:extera_next/generated/l10n/l10n.dart';
import 'package:go_router/go_router.dart';
import 'package:image_picker/image_picker.dart';
import 'package:matrix/matrix.dart';
-import 'package:record/record.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:universal_html/html.dart' as html;
@@ -28,7 +26,6 @@ import 'package:extera_next/config/setting_keys.dart';
import 'package:extera_next/config/themes.dart';
import 'package:extera_next/pages/chat/chat_view.dart';
import 'package:extera_next/pages/chat/event_info_dialog.dart';
-import 'package:extera_next/pages/chat/recording_dialog.dart';
import 'package:extera_next/pages/chat_details/chat_details.dart';
import 'package:extera_next/utils/error_reporter.dart';
import 'package:extera_next/utils/file_selector.dart';
@@ -619,45 +616,39 @@ class ChatController extends State
);
}
- void voiceMessageAction() async {
+ Future onVoiceMessageSend(
+ String path,
+ int duration,
+ List waveform,
+ String? fileName,
+ ) async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
- if (PlatformInfos.isAndroid) {
- final info = await DeviceInfoPlugin().androidInfo;
- if (info.version.sdkInt < 19) {
- showOkAlertDialog(
- context: context,
- title: L10n.of(context).unsupportedAndroidVersion,
- message: L10n.of(context).unsupportedAndroidVersionLong,
- okLabel: L10n.of(context).close,
- );
- return;
- }
- }
+ final audioFile = XFile(path);
- if (await AudioRecorder().hasPermission() == false) return;
- final result = await showDialog(
+ final bytesResult = await showFutureLoadingDialog(
context: context,
- barrierDismissible: false,
- builder: (c) => const RecordingDialog(),
+ future: audioFile.readAsBytes,
);
- if (result == null) return;
- final audioFile = XFile(result.path);
+ final bytes = bytesResult.result;
+ if (bytes == null) return;
+
final file = MatrixAudioFile(
- bytes: await audioFile.readAsBytes(),
- name: result.fileName ?? audioFile.path,
+ bytes: bytes,
+ name: fileName ?? audioFile.path,
);
+
await room.sendFileEvent(
file,
inReplyTo: replyEvent,
extraContent: {
'info': {
...file.info,
- 'duration': result.duration,
+ 'duration': duration,
},
'org.matrix.msc3245.voice': {},
'org.matrix.msc1767.audio': {
- 'duration': result.duration,
- 'waveform': result.waveform,
+ 'duration': duration,
+ 'waveform': waveform,
},
},
).catchError((e) {
@@ -737,8 +728,11 @@ class ChatController extends State
return;
}
final event = selectedEvents.single;
- await mx.client.reportEvent(roomId, event.eventId,
- reason: "Extera (Next) Redacted Event Recover");
+ await mx.client.reportEvent(
+ roomId,
+ event.eventId,
+ reason: "Extera (Next) Redacted Event Recover",
+ );
final reports = await mx.client.getEventReports();
final report = reports.firstWhere(
@@ -753,11 +747,14 @@ class ChatController extends State
}
Navigator.of(context).push(new MaterialPageRoute(
- builder: (BuildContext ctx) {
- return RecoveredEventDialog(
- event: recoveredEvent!, timeline: timeline!);
- },
- fullscreenDialog: true));
+ builder: (BuildContext ctx) {
+ return RecoveredEventDialog(
+ event: recoveredEvent,
+ timeline: timeline!,
+ );
+ },
+ fullscreenDialog: true,
+ ));
}
void translateEventAction() async {
@@ -769,12 +766,6 @@ class ChatController extends State
}
final event = selectedEvents.single;
var text = event.isRichMessage ? event.formattedText : event.text;
- if (text == null) {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text(L10n.of(context).errorTranslatingMessage)),
- );
- return;
- }
var content = {...event.content};
try {
text = await Translator.translate(
diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart
index 0786be2..fbd4fa9 100644
--- a/lib/pages/chat/chat_input_row.dart
+++ b/lib/pages/chat/chat_input_row.dart
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:animations/animations.dart';
-import 'package:extera_next/generated/l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:extera_next/config/app_config.dart';
-import 'package:extera_next/utils/other_party_can_receive.dart';
+import 'package:extera_next/generated/l10n/l10n.dart';
+import 'package:extera_next/pages/chat/recording_input_row.dart';
+import 'package:extera_next/pages/chat/recording_view_model.dart';
import 'package:extera_next/utils/platform_infos.dart';
import 'package:extera_next/widgets/avatar.dart';
import 'package:extera_next/widgets/matrix.dart';
@@ -21,325 +22,331 @@ class ChatInputRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- if (controller.showEmojiPicker &&
- controller.emojiPickerType == EmojiPickerType.reaction) {
- return const SizedBox.shrink();
- }
+
const height = 48.0;
- if (!controller.room.canSendDefaultMessages) {
- return Center(
- child: Padding(
- padding: const EdgeInsets.all(12.0),
- child: Text(
- L10n.of(context).noSendPermission,
- style: theme.textTheme.bodySmall,
- textAlign: TextAlign.center,
- ),
- ),
- );
- }
+ final selectedTextButtonStyle = TextButton.styleFrom(
+ foregroundColor: theme.colorScheme.onTertiaryContainer,
+ );
- // if (!controller.room.otherPartyCanReceiveMessages) {
- // return Center(
- // child: Padding(
- // padding: const EdgeInsets.all(12.0),
- // child: Text(
- // L10n.of(context).otherPartyNotLoggedIn,
- // style: theme.textTheme.bodySmall,
- // textAlign: TextAlign.center,
- // ),
- // ),
- // );
- // }
-
-
-
- return Row(
- crossAxisAlignment: CrossAxisAlignment.end,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: controller.selectMode
- ? [
- if (controller.selectedEvents
- .every((event) => event.status == EventStatus.error))
- SizedBox(
- height: height,
- child: TextButton(
- style: TextButton.styleFrom(
- foregroundColor: theme.colorScheme.error,
+ return RecordingViewModel(
+ builder: (context, recordingViewModel) {
+ if (recordingViewModel.isRecording) {
+ return RecordingInputRow(
+ state: recordingViewModel,
+ onSend: controller.onVoiceMessageSend,
+ );
+ }
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: controller.selectMode
+ ? [
+ if (controller.selectedEvents
+ .every((event) => event.status == EventStatus.error))
+ SizedBox(
+ height: height,
+ child: TextButton(
+ style: TextButton.styleFrom(
+ foregroundColor: theme.colorScheme.error,
+ ),
+ onPressed: controller.deleteErrorEventsAction,
+ child: Row(
+ children: [
+ const Icon(Icons.delete_forever_outlined),
+ Text(L10n.of(context).delete),
+ ],
+ ),
+ ),
+ )
+ else
+ SizedBox(
+ height: height,
+ child: TextButton(
+ style: selectedTextButtonStyle,
+ onPressed: controller.forwardEventsAction,
+ child: Row(
+ children: [
+ const Icon(Icons.keyboard_arrow_left_outlined),
+ Text(L10n.of(context).forward),
+ ],
+ ),
+ ),
),
- onPressed: controller.deleteErrorEventsAction,
- child: Row(
- children: [
- const Icon(Icons.delete),
- Text(L10n.of(context).delete),
+ controller.selectedEvents.length == 1
+ ? controller.selectedEvents.first
+ .getDisplayEvent(controller.timeline!)
+ .status
+ .isSent
+ ? SizedBox(
+ height: height,
+ child: TextButton(
+ style: selectedTextButtonStyle,
+ onPressed: controller.replyAction,
+ child: Row(
+ children: [
+ Text(L10n.of(context).reply),
+ const Icon(Icons.keyboard_arrow_right),
+ ],
+ ),
+ ),
+ )
+ : SizedBox(
+ height: height,
+ child: TextButton(
+ style: selectedTextButtonStyle,
+ onPressed: controller.sendAgainAction,
+ child: Row(
+ children: [
+ Text(L10n.of(context).tryToSendAgain),
+ const SizedBox(width: 4),
+ const Icon(Icons.send_outlined, size: 16),
+ ],
+ ),
+ ),
+ )
+ : const SizedBox.shrink(),
+ ]
+ : [
+ const SizedBox(width: 4),
+ AnimatedContainer(
+ duration: FluffyThemes.animationDuration,
+ curve: FluffyThemes.animationCurve,
+ width:
+ controller.sendController.text.isNotEmpty ? 0 : height,
+ height: height,
+ alignment: Alignment.center,
+ decoration: const BoxDecoration(),
+ clipBehavior: Clip.hardEdge,
+ child: PopupMenuButton(
+ useRootNavigator: true,
+ icon: const Icon(Icons.add_circle_outline),
+ iconColor: theme.colorScheme.onPrimaryContainer,
+ onSelected: controller.onAddPopupMenuButtonSelected,
+ itemBuilder: (BuildContext context) =>
+ >[
+ if (PlatformInfos.isMobile)
+ PopupMenuItem(
+ value: 'location',
+ child: ListTile(
+ leading: CircleAvatar(
+ backgroundColor:
+ theme.colorScheme.onPrimaryContainer,
+ foregroundColor:
+ theme.colorScheme.primaryContainer,
+ child: const Icon(Icons.gps_fixed_outlined),
+ ),
+ title: Text(L10n.of(context).shareLocation),
+ contentPadding: const EdgeInsets.all(0),
+ ),
+ ),
+ // PopupMenuItem(
+ // value: 'image',
+ // child: ListTile(
+ // leading: CircleAvatar(
+ // backgroundColor:
+ // theme.colorScheme.onPrimaryContainer,
+ // foregroundColor:
+ // theme.colorScheme.primaryContainer,
+ // child: const Icon(Icons.photo_outlined),
+ // ),
+ // title: Text(L10n.of(context).sendImage),
+ // contentPadding: const EdgeInsets.all(0),
+ // ),
+ // ),
+ // PopupMenuItem(
+ // value: 'video',
+ // child: ListTile(
+ // leading: CircleAvatar(
+ // backgroundColor:
+ // theme.colorScheme.onPrimaryContainer,
+ // foregroundColor:
+ // theme.colorScheme.primaryContainer,
+ // child:
+ // const Icon(Icons.video_camera_back_outlined),
+ // ),
+ // title: Text(L10n.of(context).sendVideo),
+ // contentPadding: const EdgeInsets.all(0),
+ // ),
+ // ),
+ PopupMenuItem(
+ value: 'file',
+ child: ListTile(
+ leading: CircleAvatar(
+ backgroundColor:
+ theme.colorScheme.onPrimaryContainer,
+ foregroundColor:
+ theme.colorScheme.primaryContainer,
+ child: const Icon(Icons.attachment_outlined),
+ ),
+ title: Text(L10n.of(context).sendFile),
+ contentPadding: const EdgeInsets.all(0),
+ ),
+ ),
],
),
),
- )
- else
- SizedBox(
- height: height,
- child: TextButton(
- onPressed: controller.forwardEventsAction,
- child: Row(
- children: [
- const Icon(Icons.keyboard_arrow_left_outlined),
- Text(L10n.of(context).forward),
- ],
- ),
- ),
- ),
- controller.selectedEvents.length == 1
- ? controller.selectedEvents.first
- .getDisplayEvent(controller.timeline!)
- .status
- .isSent
- ? SizedBox(
- height: height,
- child: TextButton(
- onPressed: controller.replyAction,
- child: Row(
- children: [
- Text(L10n.of(context).reply),
- const Icon(Icons.keyboard_arrow_right),
- ],
+ if (PlatformInfos.isMobile)
+ AnimatedContainer(
+ duration: FluffyThemes.animationDuration,
+ curve: FluffyThemes.animationCurve,
+ width: controller.sendController.text.isNotEmpty
+ ? 0
+ : height,
+ height: height,
+ alignment: Alignment.center,
+ decoration: const BoxDecoration(),
+ clipBehavior: Clip.hardEdge,
+ child: PopupMenuButton(
+ useRootNavigator: true,
+ icon: const Icon(Icons.camera_alt_outlined),
+ onSelected: controller.onAddPopupMenuButtonSelected,
+ iconColor: theme.colorScheme.onPrimaryContainer,
+ itemBuilder: (context) => [
+ PopupMenuItem(
+ value: 'camera-video',
+ child: ListTile(
+ leading: CircleAvatar(
+ backgroundColor:
+ theme.colorScheme.onPrimaryContainer,
+ foregroundColor:
+ theme.colorScheme.primaryContainer,
+ child: const Icon(Icons.videocam_outlined),
+ ),
+ title: Text(L10n.of(context).recordAVideo),
+ contentPadding: const EdgeInsets.all(0),
),
),
- )
- : SizedBox(
- height: height,
- child: TextButton(
- onPressed: controller.sendAgainAction,
- child: Row(
- children: [
- Text(L10n.of(context).tryToSendAgain),
- const SizedBox(width: 4),
- const Icon(Icons.send_outlined, size: 16),
- ],
+ PopupMenuItem(
+ value: 'camera',
+ child: ListTile(
+ leading: CircleAvatar(
+ backgroundColor:
+ theme.colorScheme.onPrimaryContainer,
+ foregroundColor:
+ theme.colorScheme.primaryContainer,
+ child: const Icon(Icons.camera_alt_outlined),
+ ),
+ title: Text(L10n.of(context).takeAPhoto),
+ contentPadding: const EdgeInsets.all(0),
),
),
- )
- : const SizedBox.shrink(),
- ]
- : [
- const SizedBox(width: 4),
- AnimatedContainer(
- duration: FluffyThemes.animationDuration,
- curve: FluffyThemes.animationCurve,
- width: controller.sendController.text.isNotEmpty ? 0 : height,
- height: height,
- alignment: Alignment.center,
- decoration: const BoxDecoration(),
- clipBehavior: Clip.hardEdge,
- child: PopupMenuButton(
- icon: const Icon(Icons.add_circle_outline),
- iconColor: theme.colorScheme.onPrimaryContainer,
- onSelected: controller.onAddPopupMenuButtonSelected,
- itemBuilder: (BuildContext context) =>
- >[
- if (PlatformInfos.isMobile)
- PopupMenuItem(
- value: 'location',
- child: ListTile(
- leading: CircleAvatar(
- backgroundColor:
- theme.colorScheme.onPrimaryContainer,
- foregroundColor: theme.colorScheme.primaryContainer,
- child: const Icon(Icons.gps_fixed_outlined),
- ),
- title: Text(L10n.of(context).shareLocation),
- contentPadding: const EdgeInsets.all(0),
- ),
- ),
- // PopupMenuItem(
- // value: 'image',
- // child: ListTile(
- // leading: CircleAvatar(
- // backgroundColor: theme.colorScheme.onPrimaryContainer,
- // foregroundColor: theme.colorScheme.primaryContainer,
- // child: const Icon(Icons.photo_outlined),
- // ),
- // title: Text(L10n.of(context).sendImage),
- // contentPadding: const EdgeInsets.all(0),
- // ),
- // ),
- // PopupMenuItem(
- // value: 'video',
- // child: ListTile(
- // leading: CircleAvatar(
- // backgroundColor: theme.colorScheme.onPrimaryContainer,
- // foregroundColor: theme.colorScheme.primaryContainer,
- // child: const Icon(Icons.video_camera_back_outlined),
- // ),
- // title: Text(L10n.of(context).sendVideo),
- // contentPadding: const EdgeInsets.all(0),
- // ),
- // ),
- PopupMenuItem(
- value: 'file',
- child: ListTile(
- leading: CircleAvatar(
- backgroundColor: theme.colorScheme.onPrimaryContainer,
- foregroundColor: theme.colorScheme.primaryContainer,
- child: const Icon(Icons.attachment_outlined),
- ),
- title: Text(L10n.of(context).sendFile),
- contentPadding: const EdgeInsets.all(0),
+ ],
),
),
- ],
- ),
- ),
- if (PlatformInfos.isMobile)
- AnimatedContainer(
- duration: FluffyThemes.animationDuration,
- curve: FluffyThemes.animationCurve,
- width: controller.sendController.text.isNotEmpty ? 0 : height,
- height: height,
- alignment: Alignment.center,
- decoration: const BoxDecoration(),
- clipBehavior: Clip.hardEdge,
- child: PopupMenuButton(
- icon: const Icon(Icons.camera_alt_outlined),
- onSelected: controller.onAddPopupMenuButtonSelected,
- iconColor: theme.colorScheme.onPrimaryContainer,
- itemBuilder: (context) => [
- PopupMenuItem(
- value: 'camera-video',
- child: ListTile(
- leading: CircleAvatar(
- backgroundColor:
- theme.colorScheme.onPrimaryContainer,
- foregroundColor: theme.colorScheme.primaryContainer,
- child: const Icon(Icons.videocam_outlined),
- ),
- title: Text(L10n.of(context).recordAVideo),
- contentPadding: const EdgeInsets.all(0),
+ Container(
+ height: height,
+ width: height,
+ alignment: Alignment.center,
+ child: IconButton(
+ tooltip: L10n.of(context).emojis,
+ color: theme.colorScheme.onPrimaryContainer,
+ icon: PageTransitionSwitcher(
+ transitionBuilder: (
+ Widget child,
+ Animation primaryAnimation,
+ Animation secondaryAnimation,
+ ) {
+ return SharedAxisTransition(
+ animation: primaryAnimation,
+ secondaryAnimation: secondaryAnimation,
+ transitionType: SharedAxisTransitionType.scaled,
+ fillColor: Colors.transparent,
+ child: child,
+ );
+ },
+ child: Icon(
+ controller.showEmojiPicker
+ ? Icons.keyboard
+ : Icons.add_reaction_outlined,
+ key: ValueKey(controller.showEmojiPicker),
),
),
- PopupMenuItem(
- value: 'camera',
- child: ListTile(
- leading: CircleAvatar(
- backgroundColor:
- theme.colorScheme.onPrimaryContainer,
- foregroundColor: theme.colorScheme.primaryContainer,
- child: const Icon(Icons.camera_alt_outlined),
- ),
- title: Text(L10n.of(context).takeAPhoto),
- contentPadding: const EdgeInsets.all(0),
- ),
- ),
- ],
- ),
- ),
- Container(
- height: height,
- width: height,
- alignment: Alignment.center,
- child: IconButton(
- tooltip: L10n.of(context).emojis,
- color: theme.colorScheme.onPrimaryContainer,
- icon: PageTransitionSwitcher(
- transitionBuilder: (
- Widget child,
- Animation primaryAnimation,
- Animation secondaryAnimation,
- ) {
- return SharedAxisTransition(
- animation: primaryAnimation,
- secondaryAnimation: secondaryAnimation,
- transitionType: SharedAxisTransitionType.scaled,
- fillColor: Colors.transparent,
- child: child,
- );
- },
- child: Icon(
- controller.showEmojiPicker
- ? Icons.keyboard
- : Icons.add_reaction_outlined,
- key: ValueKey(controller.showEmojiPicker),
+ onPressed: controller.emojiPickerAction,
),
),
- onPressed: controller.emojiPickerAction,
- ),
- ),
- if (Matrix.of(context).isMultiAccount &&
- Matrix.of(context).hasComplexBundles &&
- Matrix.of(context).currentBundle!.length > 1)
- Container(
- width: height,
- height: height,
- alignment: Alignment.center,
- child: _ChatAccountPicker(controller),
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.symmetric(vertical: 0.0),
- child: InputBar(
- room: controller.room,
- minLines: 1,
- maxLines: 8,
- autofocus: !PlatformInfos.isMobile,
- keyboardType: TextInputType.multiline,
- textInputAction:
- AppConfig.sendOnEnter == true && PlatformInfos.isMobile
+ if (Matrix.of(context).isMultiAccount &&
+ Matrix.of(context).hasComplexBundles &&
+ Matrix.of(context).currentBundle!.length > 1)
+ Container(
+ height: height,
+ width: height,
+ alignment: Alignment.center,
+ child: _ChatAccountPicker(controller),
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(vertical: 0.0),
+ child: InputBar(
+ room: controller.room,
+ minLines: 1,
+ maxLines: 8,
+ autofocus: !PlatformInfos.isMobile,
+ keyboardType: TextInputType.multiline,
+ textInputAction: AppConfig.sendOnEnter == true &&
+ PlatformInfos.isMobile
? TextInputAction.send
: null,
- onSubmitted: controller.onInputBarSubmitted,
- onSubmitImage: controller.sendImageFromClipBoard,
- focusNode: controller.inputFocus,
- controller: controller.sendController,
- decoration: InputDecoration(
- contentPadding: const EdgeInsets.only(
- left: 6.0,
- right: 6.0,
- bottom: 6.0,
- top: 3.0,
+ onSubmitted: controller.onInputBarSubmitted,
+ onSubmitImage: controller.sendImageFromClipBoard,
+ focusNode: controller.inputFocus,
+ controller: controller.sendController,
+ decoration: InputDecoration(
+ contentPadding: const EdgeInsets.only(
+ left: 6.0,
+ right: 6.0,
+ bottom: 6.0,
+ top: 3.0,
+ ),
+ counter: const SizedBox.shrink(),
+ hintText: L10n.of(context).writeAMessage,
+ hintMaxLines: 1,
+ border: InputBorder.none,
+ enabledBorder: InputBorder.none,
+ filled: false,
+ ),
+ onChanged: controller.onInputBarChanged,
),
- hintText: L10n.of(context).writeAMessage,
- hintMaxLines: 1,
- border: InputBorder.none,
- enabledBorder: InputBorder.none,
- filled: false,
),
- onChanged: controller.onInputBarChanged,
),
- ),
- ),
- Container(
- height: height,
- width: height,
- alignment: Alignment.center,
- child: PlatformInfos.platformCanRecord &&
- controller.sendController.text.isEmpty
- ? FloatingActionButton.small(
- tooltip: L10n.of(context).voiceMessage,
- onPressed: controller.voiceMessageAction,
- elevation: 0,
- heroTag: null,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(height),
- ),
- backgroundColor: theme.bubbleColor,
- foregroundColor: theme.onBubbleColor,
- child: const Icon(Icons.mic_none_outlined),
- )
- : FloatingActionButton.small(
- tooltip: L10n.of(context).send,
- onPressed: controller.send,
- elevation: 0,
- heroTag: null,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(height),
- ),
- backgroundColor: theme.bubbleColor,
- foregroundColor: theme.onBubbleColor,
- child: const Icon(Icons.send_outlined),
- ),
- ),
- ],
+ Container(
+ height: height,
+ width: height,
+ alignment: Alignment.center,
+ child: PlatformInfos.platformCanRecord &&
+ controller.sendController.text.isEmpty
+ ? IconButton(
+ tooltip: L10n.of(context).voiceMessage,
+ onPressed: () =>
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text(
+ L10n.of(context)
+ .longPressToRecordVoiceMessage,
+ ),
+ ),
+ ),
+ onLongPress: () => recordingViewModel
+ .startRecording(controller.room),
+ style: IconButton.styleFrom(
+ backgroundColor: theme.bubbleColor,
+ foregroundColor: theme.onBubbleColor,
+ ),
+ icon: const Icon(Icons.mic_none_outlined),
+ )
+ : IconButton(
+ tooltip: L10n.of(context).send,
+ onPressed: controller.send,
+ style: IconButton.styleFrom(
+ backgroundColor: theme.bubbleColor,
+ foregroundColor: theme.onBubbleColor,
+ ),
+ icon: const Icon(Icons.send_outlined),
+ ),
+ ),
+ ],
+ );
+ },
);
}
}
@@ -368,6 +375,7 @@ class _ChatAccountPicker extends StatelessWidget {
child: FutureBuilder(
future: controller.sendingClient.fetchOwnProfile(),
builder: (context, snapshot) => PopupMenuButton(
+ useRootNavigator: true,
onSelected: (mxid) => _popupMenuButtonSelected(mxid, context),
itemBuilder: (BuildContext context) => clients
.map(
@@ -399,4 +407,4 @@ class _ChatAccountPicker extends StatelessWidget {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart
index 696c4e6..4567fc4 100644
--- a/lib/pages/chat/chat_view.dart
+++ b/lib/pages/chat/chat_view.dart
@@ -15,7 +15,6 @@ import 'package:extera_next/pages/chat/chat_app_bar_title.dart';
import 'package:extera_next/pages/chat/chat_event_list.dart';
import 'package:extera_next/pages/chat/encryption_button.dart';
import 'package:extera_next/pages/chat/pinned_events.dart';
-import 'package:extera_next/pages/chat/reactions_picker.dart';
import 'package:extera_next/pages/chat/reply_display.dart';
import 'package:extera_next/utils/account_config.dart';
import 'package:extera_next/utils/localized_exception_extension.dart';
diff --git a/lib/pages/chat/input_bar.dart b/lib/pages/chat/input_bar.dart
index aab1457..accdd8e 100644
--- a/lib/pages/chat/input_bar.dart
+++ b/lib/pages/chat/input_bar.dart
@@ -372,14 +372,14 @@ class InputBar extends StatelessWidget {
if (suggestion['type'] == 'user') {
insertText = '${suggestion['mention']!} ';
startText = replaceText.replaceAllMapped(
- RegExp(r'(\s|^)(@[-\w]+)$'),
- (Match m) => '${m[1]}$insertText',
+ RegExp(r'(?:\s|^)@([^ \[\]]+)$', unicode: true),
+ (Match m) => '$insertText',
);
}
if (suggestion['type'] == 'room') {
insertText = '${suggestion['mxid']!} ';
startText = replaceText.replaceAllMapped(
- RegExp(r'(\s|^)(#[-\w]+)$'),
+ RegExp(r'(\s|^)(#[-\w]+)$', unicode: true),
(Match m) => '${m[1]}$insertText',
);
}
diff --git a/lib/pages/chat/recording_dialog.dart b/lib/pages/chat/recording_dialog.dart
deleted file mode 100644
index 03ba75c..0000000
--- a/lib/pages/chat/recording_dialog.dart
+++ /dev/null
@@ -1,256 +0,0 @@
-import 'dart:async';
-
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter/material.dart';
-
-import 'package:extera_next/generated/l10n/l10n.dart';
-import 'package:path/path.dart' as path_lib;
-import 'package:path_provider/path_provider.dart';
-import 'package:record/record.dart';
-import 'package:wakelock_plus/wakelock_plus.dart';
-
-import 'package:extera_next/config/app_config.dart';
-import 'package:extera_next/config/setting_keys.dart';
-import 'package:extera_next/utils/platform_infos.dart';
-import 'package:extera_next/widgets/matrix.dart';
-import 'events/audio_player.dart';
-
-class RecordingDialog extends StatefulWidget {
- const RecordingDialog({
- super.key,
- });
-
- @override
- RecordingDialogState createState() => RecordingDialogState();
-}
-
-class RecordingDialogState extends State {
- Timer? _recorderSubscription;
- Duration _duration = Duration.zero;
-
- bool error = false;
-
- final _audioRecorder = AudioRecorder();
- final List amplitudeTimeline = [];
-
- String? fileName;
-
- Future startRecording() async {
- final store = Matrix.of(context).store;
- try {
- final codec = kIsWeb
- // Web seems to create webm instead of ogg when using opus encoder
- // which does not play on iOS right now. So we use wav for now:
- ? AudioEncoder.wav
- // Everywhere else we use opus if supported by the platform:
- : await _audioRecorder.isEncoderSupported(AudioEncoder.opus)
- ? AudioEncoder.opus
- : AudioEncoder.aacLc;
- fileName =
- 'recording${DateTime.now().microsecondsSinceEpoch}.${codec.fileExtension}';
- String? path;
- if (!kIsWeb) {
- final tempDir = await getTemporaryDirectory();
- path = path_lib.join(tempDir.path, fileName);
- }
-
- final result = await _audioRecorder.hasPermission();
- if (result != true) {
- setState(() => error = true);
- return;
- }
- await WakelockPlus.enable();
-
- await _audioRecorder.start(
- RecordConfig(
- bitRate: AppSettings.audioRecordingBitRate.getItem(store),
- sampleRate: AppSettings.audioRecordingSamplingRate.getItem(store),
- numChannels: AppSettings.audioRecordingNumChannels.getItem(store),
- autoGain: AppSettings.audioRecordingAutoGain.getItem(store),
- echoCancel: AppSettings.audioRecordingEchoCancel.getItem(store),
- noiseSuppress: AppSettings.audioRecordingNoiseSuppress.getItem(store),
- encoder: codec,
- ),
- path: path ?? '',
- );
- setState(() => _duration = Duration.zero);
- _recorderSubscription?.cancel();
- _recorderSubscription =
- Timer.periodic(const Duration(milliseconds: 100), (_) async {
- final amplitude = await _audioRecorder.getAmplitude();
- var value = 100 + amplitude.current * 2;
- value = value < 1 ? 1 : value;
- amplitudeTimeline.add(value);
- setState(() {
- _duration += const Duration(milliseconds: 100);
- });
- });
- } catch (_) {
- setState(() => error = true);
- rethrow;
- }
- }
-
- @override
- void initState() {
- super.initState();
- startRecording();
- }
-
- @override
- void dispose() {
- WakelockPlus.disable();
- _recorderSubscription?.cancel();
- _audioRecorder.stop();
- super.dispose();
- }
-
- void _stopAndSend() async {
- _recorderSubscription?.cancel();
- final path = await _audioRecorder.stop();
-
- if (path == null) throw ('Recording failed!');
- const waveCount = AudioPlayerWidget.wavesCount;
- final step = amplitudeTimeline.length < waveCount
- ? 1
- : (amplitudeTimeline.length / waveCount).round();
- final waveform = [];
- for (var i = 0; i < amplitudeTimeline.length; i += step) {
- waveform.add((amplitudeTimeline[i] / 100 * 1024).round());
- }
- Navigator.of(context, rootNavigator: false).pop(
- RecordingResult(
- path: path,
- duration: _duration.inMilliseconds,
- waveform: waveform,
- fileName: fileName,
- ),
- );
- }
-
- @override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
-
- const maxDecibalWidth = 64.0;
- final time =
- '${_duration.inMinutes.toString().padLeft(2, '0')}:${(_duration.inSeconds % 60).toString().padLeft(2, '0')}';
- final content = error
- ? Text(L10n.of(context).oopsSomethingWentWrong)
- : Row(
- children: [
- Container(
- width: 16,
- height: 16,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(32),
- color: Colors.red,
- ),
- ),
- Expanded(
- child: Row(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.end,
- children: amplitudeTimeline.reversed
- .take(26)
- .toList()
- .reversed
- .map(
- (amplitude) => Container(
- margin: const EdgeInsets.only(left: 2),
- width: 4,
- decoration: BoxDecoration(
- color: theme.colorScheme.primary,
- borderRadius:
- BorderRadius.circular(AppConfig.borderRadius),
- ),
- height: maxDecibalWidth * (amplitude / 100),
- ),
- )
- .toList(),
- ),
- ),
- const SizedBox(width: 8),
- SizedBox(
- width: 48,
- child: Text(time),
- ),
- ],
- );
- if (PlatformInfos.isCupertinoStyle) {
- return CupertinoAlertDialog(
- content: content,
- actions: [
- CupertinoDialogAction(
- onPressed: () => Navigator.of(context, rootNavigator: false).pop(),
- child: Text(
- L10n.of(context).cancel,
- style: TextStyle(
- color: theme.textTheme.bodyMedium?.color?.withAlpha(150),
- ),
- ),
- ),
- if (error != true)
- CupertinoDialogAction(
- onPressed: _stopAndSend,
- child: Text(L10n.of(context).send),
- ),
- ],
- );
- }
- return AlertDialog(
- content: content,
- actions: [
- TextButton(
- onPressed: () => Navigator.of(context, rootNavigator: false).pop(),
- child: Text(
- L10n.of(context).cancel,
- style: TextStyle(
- color: theme.colorScheme.error,
- ),
- ),
- ),
- if (error != true)
- TextButton(
- onPressed: _stopAndSend,
- child: Text(L10n.of(context).send),
- ),
- ],
- );
- }
-}
-
-class RecordingResult {
- final String path;
- final int duration;
- final List waveform;
- final String? fileName;
-
- const RecordingResult({
- required this.path,
- required this.duration,
- required this.waveform,
- required this.fileName,
- });
-}
-
-extension on AudioEncoder {
- String get fileExtension {
- switch (this) {
- case AudioEncoder.aacLc:
- case AudioEncoder.aacEld:
- case AudioEncoder.aacHe:
- return 'm4a';
- case AudioEncoder.opus:
- return 'ogg';
- case AudioEncoder.wav:
- return 'wav';
- case AudioEncoder.amrNb:
- case AudioEncoder.amrWb:
- case AudioEncoder.flac:
- case AudioEncoder.pcm16bits:
- throw UnsupportedError('Not yet used');
- }
- }
-}
diff --git a/lib/pages/chat/recording_input_row.dart b/lib/pages/chat/recording_input_row.dart
new file mode 100644
index 0000000..b90fb0b
--- /dev/null
+++ b/lib/pages/chat/recording_input_row.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart';
+
+import 'package:extera_next/config/themes.dart';
+
+import 'package:extera_next/generated/l10n/l10n.dart';
+
+import 'package:extera_next/pages/chat/recording_view_model.dart';
+
+class RecordingInputRow extends StatelessWidget {
+ final RecordingViewModelState state;
+
+ final Future Function(String, int, List, String?) onSend;
+
+ const RecordingInputRow({
+ required this.state,
+ required this.onSend,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ const maxDecibalWidth = 36.0;
+
+ final time =
+ '${state.duration.inMinutes.toString().padLeft(2, '0')}:${(state.duration.inSeconds % 60).toString().padLeft(2, '0')}';
+
+ return Row(
+ children: [
+ IconButton(
+ tooltip: L10n.of(context).cancel,
+ icon: const Icon(Icons.delete_outlined),
+ color: theme.colorScheme.error,
+ onPressed: state.cancel,
+ ),
+ if (state.isPaused)
+ IconButton(
+ tooltip: L10n.of(context).resume,
+ icon: const Icon(Icons.play_circle_outline_outlined),
+ onPressed: state.resume,
+ )
+ else
+ IconButton(
+ tooltip: L10n.of(context).pause,
+ icon: const Icon(Icons.pause_circle_outline_outlined),
+ onPressed: state.pause,
+ ),
+ Text(time),
+ const SizedBox(width: 8),
+ Expanded(
+ child: LayoutBuilder(
+ builder: (context, constraints) {
+ const width = 4;
+
+ return Row(
+ mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: state.amplitudeTimeline.reversed
+ .take((constraints.maxWidth / (width + 2)).floor())
+ .toList()
+ .reversed
+ .map(
+ (amplitude) => Container(
+ margin: const EdgeInsets.only(left: 2),
+ width: width.toDouble(),
+ decoration: BoxDecoration(
+ color: theme.colorScheme.primary,
+ borderRadius: BorderRadius.circular(2),
+ ),
+ height: maxDecibalWidth * (amplitude / 100),
+ ),
+ )
+ .toList(),
+ );
+ },
+ ),
+ ),
+ IconButton(
+ style: IconButton.styleFrom(
+ disabledBackgroundColor: theme.bubbleColor.withAlpha(128),
+ backgroundColor: theme.bubbleColor,
+ foregroundColor: theme.onBubbleColor,
+ ),
+ tooltip: L10n.of(context).sendAudio,
+ icon: state.isSending
+ ? const SizedBox.square(
+ dimension: 24,
+ child: CircularProgressIndicator.adaptive(),
+ )
+ : const Icon(Icons.send_outlined),
+ onPressed: state.isSending ? null : () => state.stopAndSend(onSend),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/pages/chat/recording_view_model.dart b/lib/pages/chat/recording_view_model.dart
new file mode 100644
index 0000000..0054385
--- /dev/null
+++ b/lib/pages/chat/recording_view_model.dart
@@ -0,0 +1,230 @@
+import 'dart:async';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+
+import 'package:device_info_plus/device_info_plus.dart';
+import 'package:matrix/matrix.dart';
+import 'package:path/path.dart' as path_lib;
+import 'package:path_provider/path_provider.dart';
+import 'package:record/record.dart';
+import 'package:wakelock_plus/wakelock_plus.dart';
+
+import 'package:extera_next/config/setting_keys.dart';
+import 'package:extera_next/generated/l10n/l10n.dart';
+import 'package:extera_next/utils/platform_infos.dart';
+import 'package:extera_next/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
+import 'package:extera_next/widgets/matrix.dart';
+import 'events/audio_player.dart';
+
+class RecordingViewModel extends StatefulWidget {
+ final Widget Function(BuildContext, RecordingViewModelState) builder;
+
+ const RecordingViewModel({
+ required this.builder,
+ super.key,
+ });
+
+ @override
+ RecordingViewModelState createState() => RecordingViewModelState();
+}
+
+class RecordingViewModelState extends State {
+ Timer? _recorderSubscription;
+ Duration duration = Duration.zero;
+
+ bool error = false;
+ bool isSending = false;
+
+ bool get isRecording => _audioRecorder != null;
+
+ AudioRecorder? _audioRecorder;
+ final List amplitudeTimeline = [];
+
+ String? fileName;
+
+ bool isPaused = false;
+
+ Future startRecording(Room room) async {
+ room.client.getConfig(); // Preload server file configuration.
+ if (PlatformInfos.isAndroid) {
+ final info = await DeviceInfoPlugin().androidInfo;
+ if (info.version.sdkInt < 19) {
+ showOkAlertDialog(
+ context: context,
+ title: L10n.of(context).unsupportedAndroidVersion,
+ message: L10n.of(context).unsupportedAndroidVersionLong,
+ okLabel: L10n.of(context).close,
+ );
+ return;
+ }
+ }
+
+ // TODO: add permission request
+ if (await AudioRecorder().hasPermission() == false) return;
+
+ final store = Matrix.of(context).store;
+
+ final audioRecorder = _audioRecorder ??= AudioRecorder();
+ setState(() {});
+
+ try {
+ final codec = kIsWeb
+ // Web seems to create webm instead of ogg when using opus encoder
+ // which does not play on iOS right now. So we use wav for now:
+ ? AudioEncoder.wav
+ // Everywhere else we use opus if supported by the platform:
+ : await audioRecorder.isEncoderSupported(AudioEncoder.opus)
+ ? AudioEncoder.opus
+ : AudioEncoder.aacLc;
+ fileName =
+ 'recording${DateTime.now().microsecondsSinceEpoch}.${codec.fileExtension}';
+ String? path;
+ if (!kIsWeb) {
+ final tempDir = await getTemporaryDirectory();
+ path = path_lib.join(tempDir.path, fileName);
+ }
+
+ final result = await audioRecorder.hasPermission();
+ if (result != true) {
+ setState(() => error = true);
+ return;
+ }
+ await WakelockPlus.enable();
+
+ await audioRecorder.start(
+ RecordConfig(
+ bitRate: AppSettings.audioRecordingBitRate.getItem(store),
+ sampleRate: AppSettings.audioRecordingSamplingRate.getItem(store),
+ numChannels: AppSettings.audioRecordingNumChannels.getItem(store),
+ autoGain: AppSettings.audioRecordingAutoGain.getItem(store),
+ echoCancel: AppSettings.audioRecordingEchoCancel.getItem(store),
+ noiseSuppress: AppSettings.audioRecordingNoiseSuppress.getItem(store),
+ encoder: codec,
+ ),
+ path: path ?? '',
+ );
+ setState(() => duration = Duration.zero);
+ _subscribe();
+ } catch (_) {
+ setState(() => error = true);
+ rethrow;
+ }
+ }
+
+ @override
+ void dispose() {
+ _reset();
+ super.dispose();
+ }
+
+ void _subscribe() {
+ _recorderSubscription?.cancel();
+ _recorderSubscription =
+ Timer.periodic(const Duration(milliseconds: 100), (_) async {
+ final amplitude = await _audioRecorder!.getAmplitude();
+ var value = 100 + amplitude.current * 2;
+ value = value < 1 ? 1 : value;
+ amplitudeTimeline.add(value);
+ setState(() {
+ duration += const Duration(milliseconds: 100);
+ });
+ });
+ }
+
+ void _reset() {
+ WakelockPlus.disable();
+ _recorderSubscription?.cancel();
+ _audioRecorder?.stop();
+ _audioRecorder = null;
+ isSending = false;
+ error = false;
+ fileName = null;
+ duration = Duration.zero;
+ amplitudeTimeline.clear();
+ isPaused = false;
+ }
+
+ void cancel() {
+ setState(() {
+ _reset();
+ });
+ }
+
+ void pause() {
+ _audioRecorder?.pause();
+ _recorderSubscription?.cancel();
+ setState(() {
+ isPaused = true;
+ });
+ }
+
+ void resume() {
+ _audioRecorder?.resume();
+ _subscribe();
+ setState(() {
+ isPaused = false;
+ });
+ }
+
+ void stopAndSend(
+ Future Function(
+ String path,
+ int duration,
+ List waveform,
+ String? fileName,
+ ) onSend,
+ ) async {
+ _recorderSubscription?.cancel();
+ final path = await _audioRecorder?.stop();
+
+ if (path == null) throw ('Recording failed!');
+ const waveCount = AudioPlayerWidget.wavesCount;
+ final step = amplitudeTimeline.length < waveCount
+ ? 1
+ : (amplitudeTimeline.length / waveCount).round();
+ final waveform = [];
+ for (var i = 0; i < amplitudeTimeline.length; i += step) {
+ waveform.add((amplitudeTimeline[i] / 100 * 1024).round());
+ }
+
+ setState(() {
+ isSending = true;
+ });
+ try {
+ await onSend(path, duration.inMilliseconds, waveform, fileName);
+ } catch (e, s) {
+ Logs().e('Unable to send voice message', e, s);
+ setState(() {
+ isSending = false;
+ });
+ return;
+ }
+
+ cancel();
+ }
+
+ @override
+ Widget build(BuildContext context) => widget.builder(context, this);
+}
+
+extension on AudioEncoder {
+ String get fileExtension {
+ switch (this) {
+ case AudioEncoder.aacLc:
+ case AudioEncoder.aacEld:
+ case AudioEncoder.aacHe:
+ return 'm4a';
+ case AudioEncoder.opus:
+ return 'ogg';
+ case AudioEncoder.wav:
+ return 'wav';
+ case AudioEncoder.amrNb:
+ case AudioEncoder.amrWb:
+ case AudioEncoder.flac:
+ case AudioEncoder.pcm16bits:
+ throw UnsupportedError('Not yet used');
+ }
+ }
+}
diff --git a/lib/pages/chat/recovered_event_dialog.dart b/lib/pages/chat/recovered_event_dialog.dart
index abb52b9..9758ff6 100644
--- a/lib/pages/chat/recovered_event_dialog.dart
+++ b/lib/pages/chat/recovered_event_dialog.dart
@@ -1,6 +1,5 @@
import 'package:extera_next/config/themes.dart';
import 'package:extera_next/pages/chat/events/message.dart';
-import 'package:extera_next/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
diff --git a/lib/pages/chat/send_file_dialog.dart b/lib/pages/chat/send_file_dialog.dart
index 193f3a1..d3a34ca 100644
--- a/lib/pages/chat/send_file_dialog.dart
+++ b/lib/pages/chat/send_file_dialog.dart
@@ -10,7 +10,6 @@ import 'package:extera_next/generated/l10n/l10n.dart';
import 'package:matrix/matrix.dart';
import 'package:mime/mime.dart';
-import 'package:extera_next/config/app_config.dart';
import 'package:extera_next/utils/localized_exception_extension.dart';
import 'package:extera_next/utils/matrix_sdk_extensions/matrix_file_extension.dart';
import 'package:extera_next/utils/other_party_can_receive.dart';
diff --git a/lib/pages/chat/translated_event_dialog.dart b/lib/pages/chat/translated_event_dialog.dart
index c1e412c..337701f 100644
--- a/lib/pages/chat/translated_event_dialog.dart
+++ b/lib/pages/chat/translated_event_dialog.dart
@@ -1,6 +1,5 @@
import 'package:extera_next/config/themes.dart';
import 'package:extera_next/pages/chat/events/message.dart';
-import 'package:extera_next/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart
index f930ed9..f5f4ccc 100644
--- a/lib/pages/chat_details/chat_details_view.dart
+++ b/lib/pages/chat_details/chat_details_view.dart
@@ -207,8 +207,9 @@ class ChatDetailsView extends StatelessWidget {
),
],
),
- Divider(color: theme.dividerColor),
- if (!room.canChangeStateEvent(EventTypes.RoomTopic))
+ if (room.canChangeStateEvent(EventTypes.RoomTopic) ||
+ room.topic.isNotEmpty) ...[
+ Divider(color: theme.dividerColor),
ListTile(
title: Text(
L10n.of(context).chatDescription,
@@ -217,53 +218,46 @@ class ChatDetailsView extends StatelessWidget {
fontWeight: FontWeight.bold,
),
),
- )
- else
+ trailing:
+ room.canChangeStateEvent(EventTypes.RoomTopic)
+ ? IconButton(
+ onPressed: controller.setTopicAction,
+ tooltip:
+ L10n.of(context).setChatDescription,
+ icon: const Icon(Icons.edit_outlined),
+ )
+ : null,
+ ),
Padding(
- padding: const EdgeInsets.all(16.0),
- child: TextButton.icon(
- onPressed: controller.setTopicAction,
- label: Text(L10n.of(context).setChatDescription),
- icon: const Icon(Icons.edit_outlined),
- style: TextButton.styleFrom(
- iconColor:
- theme.colorScheme.onSecondaryContainer,
- backgroundColor:
- theme.colorScheme.secondaryContainer,
- foregroundColor:
- theme.colorScheme.onSecondaryContainer,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 16.0,
+ ),
+ child: SelectableLinkify(
+ text: room.topic.isEmpty
+ ? L10n.of(context).noChatDescriptionYet
+ : room.topic,
+ textScaleFactor:
+ MediaQuery.textScalerOf(context).scale(1),
+ options: const LinkifyOptions(humanize: false),
+ linkStyle: const TextStyle(
+ color: Colors.blueAccent,
+ decorationColor: Colors.blueAccent,
),
+ style: TextStyle(
+ fontSize: 14,
+ fontStyle: room.topic.isEmpty
+ ? FontStyle.italic
+ : FontStyle.normal,
+ color: theme.textTheme.bodyMedium!.color,
+ decorationColor:
+ theme.textTheme.bodyMedium!.color,
+ ),
+ onOpen: (url) =>
+ UrlLauncher(context, url.url).launchUrl(),
),
),
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 16.0,
- ),
- child: SelectableLinkify(
- text: room.topic.isEmpty
- ? L10n.of(context).noChatDescriptionYet
- : room.topic,
- textScaleFactor:
- MediaQuery.textScalerOf(context).scale(1),
- options: const LinkifyOptions(humanize: false),
- linkStyle: const TextStyle(
- color: Colors.blueAccent,
- decorationColor: Colors.blueAccent,
- ),
- style: TextStyle(
- fontSize: 14,
- fontStyle: room.topic.isEmpty
- ? FontStyle.italic
- : FontStyle.normal,
- color: theme.textTheme.bodyMedium!.color,
- decorationColor:
- theme.textTheme.bodyMedium!.color,
- ),
- onOpen: (url) =>
- UrlLauncher(context, url.url).launchUrl(),
- ),
- ),
- const SizedBox(height: 16),
+ const SizedBox(height: 16),
+ ],
Divider(color: theme.dividerColor),
ListTile(
leading: CircleAvatar(
@@ -366,4 +360,4 @@ class ChatDetailsView extends StatelessWidget {
},
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/pages/download_manager/download_manager.dart b/lib/pages/download_manager/download_manager.dart
index 1c48902..359b9f4 100644
--- a/lib/pages/download_manager/download_manager.dart
+++ b/lib/pages/download_manager/download_manager.dart
@@ -27,33 +27,33 @@ class Download {
try {
final mx = Matrix.of(context).client;
// final directory = await getDownloadsDirectory();
- downloadPath =
- "/sdcard/Download/Extera";
+ downloadPath = "/sdcard/Download/Extera";
httpUrl = (await Uri.parse(url).getDownloadUri(mx)).toString();
if (downloadPath != null) {
// Create Dio instance
final dio = Dio();
-
+
ct = CancelToken();
// Download the file
- response = dio.download(
- httpUrl,
- "$downloadPath/$name",
- onReceiveProgress: (received, total) {
- receivedBytes = received;
- totalBytes = total;
- progress = (receivedBytes / totalBytes) * 100;
- print("Download progress: $progress%");
- },
- options: Options(
- responseType: ResponseType.bytes,
- headers: {'authorization': "Bearer ${mx.accessToken}"}
- ),
- cancelToken: ct
- );
+ response = dio.download(httpUrl, "$downloadPath/$name",
+ onReceiveProgress: (received, total) {
+ receivedBytes = received;
+ totalBytes = total;
+ progress = (receivedBytes / totalBytes) * 100;
+ if (progress == 100) {
+ Provider.of(context)
+ .downloads
+ .remove(this);
+ }
+ print("Download progress: $progress%");
+ },
+ options: Options(
+ responseType: ResponseType.bytes,
+ headers: {'authorization': "Bearer ${mx.accessToken}"}),
+ cancelToken: ct);
print("Download completed and saved to $downloadPath/$name");
}
} catch (e) {
@@ -63,6 +63,7 @@ class Download {
void cancel() async {
ct.cancel();
+ Provider.of(context).downloads.remove(this);
}
}
diff --git a/lib/utils/file_selector.dart b/lib/utils/file_selector.dart
index e6edfbc..49b95fd 100644
--- a/lib/utils/file_selector.dart
+++ b/lib/utils/file_selector.dart
@@ -13,37 +13,18 @@ Future> selectFiles(
FileSelectorType type = FileSelectorType.any,
bool allowMultiple = false,
}) async {
- if (!PlatformInfos.isLinux) {
- final result = await AppLock.of(context).pauseWhile(
- showFutureLoadingDialog(
- context: context,
- future: () => FilePicker.platform.pickFiles(
- compressionQuality: 0,
- allowMultiple: allowMultiple,
- type: type.filePickerType,
- allowedExtensions: type.extensions,
- ),
+ final result = await AppLock.of(context).pauseWhile(
+ showFutureLoadingDialog(
+ context: context,
+ future: () => FilePicker.platform.pickFiles(
+ compressionQuality: 0,
+ allowMultiple: allowMultiple,
+ type: type.filePickerType,
+ allowedExtensions: type.extensions,
),
- );
- return result.result?.xFiles ?? [];
- }
-
- if (allowMultiple) {
- return await AppLock.of(context).pauseWhile(
- openFiles(
- confirmButtonText: title,
- acceptedTypeGroups: type.groups,
- ),
- );
- }
- final file = await AppLock.of(context).pauseWhile(
- openFile(
- confirmButtonText: title,
- acceptedTypeGroups: type.groups,
),
);
- if (file == null) return [];
- return [file];
+ return result.result?.xFiles ?? [];
}
enum FileSelectorType {
diff --git a/lib/widgets/avatar_page_header.dart b/lib/widgets/avatar_page_header.dart
new file mode 100644
index 0000000..d62e541
--- /dev/null
+++ b/lib/widgets/avatar_page_header.dart
@@ -0,0 +1,105 @@
+import 'package:flutter/material.dart';
+
+import 'package:extera_next/config/themes.dart';
+
+class AvatarPageHeader extends StatelessWidget {
+ final Widget avatar;
+
+ final void Function()? onAvatarEdit;
+
+ final Widget? textButtonLeft, textButtonRight;
+
+ final List iconButtons;
+
+ const AvatarPageHeader({
+ super.key,
+ required this.avatar,
+ this.onAvatarEdit,
+ this.iconButtons = const [],
+ this.textButtonLeft,
+ this.textButtonRight,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final theme = Theme.of(context);
+
+ final onAvatarEdit = this.onAvatarEdit;
+
+ return Center(
+ child: ConstrainedBox(
+ constraints: const BoxConstraints(maxWidth: FluffyThemes.columnWidth),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ spacing: 8.0,
+ children: [
+ Stack(
+ children: [
+ avatar,
+ if (onAvatarEdit != null)
+ Positioned(
+ bottom: 0,
+ right: 0,
+ child: FloatingActionButton.small(
+ elevation: 2,
+ onPressed: onAvatarEdit,
+ heroTag: null,
+ child: const Icon(Icons.camera_alt_outlined),
+ ),
+ ),
+ ],
+ ),
+ TextButtonTheme(
+ data: TextButtonThemeData(
+ style: TextButton.styleFrom(
+ disabledForegroundColor: theme.colorScheme.onSurface,
+ foregroundColor: theme.colorScheme.onSurface,
+ textStyle: const TextStyle(fontWeight: FontWeight.normal),
+ ),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
+ child: LayoutBuilder(
+ builder: (context, constraints) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ ConstrainedBox(
+ constraints: BoxConstraints(
+ maxWidth: constraints.maxWidth / 2,
+ ),
+ child: textButtonLeft,
+ ),
+ ConstrainedBox(
+ constraints: BoxConstraints(
+ maxWidth: constraints.maxWidth / 2,
+ ),
+ child: textButtonRight,
+ ),
+ ],
+ );
+ },
+ ),
+ ),
+ ),
+ IconButtonTheme(
+ data: IconButtonThemeData(
+ style: IconButton.styleFrom(
+ backgroundColor: theme.colorScheme.surfaceContainer,
+ iconSize: 24,
+ padding: const EdgeInsets.all(16),
+ ),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: iconButtons,
+ ),
+ ),
+ const SizedBox(height: 0.0),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart
index a1b4569..05c5426 100644
--- a/lib/widgets/chat_settings_popup_menu.dart
+++ b/lib/widgets/chat_settings_popup_menu.dart
@@ -10,7 +10,7 @@ import 'package:extera_next/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog
import 'package:extera_next/widgets/future_loading_dialog.dart';
import 'matrix.dart';
-enum ChatPopupMenuActions { details, mute, unmute, leave, search }
+enum ChatPopupMenuActions { details, mute, unmute, emote, leave, search }
class ChatSettingsPopupMenu extends StatefulWidget {
final Room room;
@@ -31,6 +31,17 @@ class ChatSettingsPopupMenuState extends State {
super.dispose();
}
+ void goToEmoteSettings() async {
+ final room = widget.room;
+ if ((room.states['im.ponies.room_emotes'] ?? {})
+ .keys
+ .any((String s) => s.isNotEmpty)) {
+ context.push('/rooms/${room.id}/details/multiple_emotes');
+ } else {
+ context.push('/rooms/${room.id}/details/emotes');
+ }
+ }
+
@override
Widget build(BuildContext context) {
notificationChangeSub ??= Matrix.of(context)
@@ -73,6 +84,9 @@ class ChatSettingsPopupMenuState extends State {
}
}
break;
+ case ChatPopupMenuActions.emote:
+ goToEmoteSettings();
+ break;
case ChatPopupMenuActions.mute:
await showFutureLoadingDialog(
context: context,
diff --git a/pubspec.lock b/pubspec.lock
deleted file mode 100644
index 873cac5..0000000
--- a/pubspec.lock
+++ /dev/null
@@ -1,2377 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- _fe_analyzer_shared:
- dependency: transitive
- description:
- name: _fe_analyzer_shared
- sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
- url: "https://pub.dev"
- source: hosted
- version: "67.0.0"
- analyzer:
- dependency: transitive
- description:
- name: analyzer
- sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
- url: "https://pub.dev"
- source: hosted
- version: "6.4.1"
- animations:
- dependency: "direct main"
- description:
- name: animations
- sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
- url: "https://pub.dev"
- source: hosted
- version: "2.0.11"
- ansicolor:
- dependency: transitive
- description:
- name: ansicolor
- sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.3"
- app_links:
- dependency: "direct main"
- description:
- name: app_links
- sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8"
- url: "https://pub.dev"
- source: hosted
- version: "6.4.1"
- app_links_linux:
- dependency: transitive
- description:
- name: app_links_linux
- sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
- url: "https://pub.dev"
- source: hosted
- version: "1.0.3"
- app_links_platform_interface:
- dependency: transitive
- description:
- name: app_links_platform_interface
- sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- app_links_web:
- dependency: transitive
- description:
- name: app_links_web
- sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
- url: "https://pub.dev"
- source: hosted
- version: "1.0.4"
- archive:
- dependency: "direct main"
- description:
- name: archive
- sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
- url: "https://pub.dev"
- source: hosted
- version: "4.0.7"
- args:
- dependency: transitive
- description:
- name: args
- sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
- url: "https://pub.dev"
- source: hosted
- version: "2.7.0"
- async:
- dependency: "direct main"
- description:
- name: async
- sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
- url: "https://pub.dev"
- source: hosted
- version: "2.13.0"
- audio_session:
- dependency: transitive
- description:
- name: audio_session
- sha256: "2b7fff16a552486d078bfc09a8cde19f426dc6d6329262b684182597bec5b1ac"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.25"
- badges:
- dependency: "direct main"
- description:
- name: badges
- sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- barbecue:
- dependency: transitive
- description:
- name: barbecue
- sha256: e3a0afaf9005e466887d6c87411a2ddd8d72fc46db3caabf278ee600f1e2f92c
- url: "https://pub.dev"
- source: hosted
- version: "0.4.0"
- base58check:
- dependency: transitive
- description:
- name: base58check
- sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- blurhash_dart:
- dependency: "direct main"
- description:
- name: blurhash_dart
- sha256: "43955b6c2e30a7d440028d1af0fa185852f3534b795cc6eb81fbf397b464409f"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.1"
- boolean_selector:
- dependency: transitive
- description:
- name: boolean_selector
- sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- build_cli_annotations:
- dependency: transitive
- description:
- name: build_cli_annotations
- sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- canonical_json:
- dependency: transitive
- description:
- name: canonical_json
- sha256: d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- charcode:
- dependency: transitive
- description:
- name: charcode
- sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- checked_yaml:
- dependency: transitive
- description:
- name: checked_yaml
- sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.4"
- chewie:
- dependency: "direct main"
- description:
- name: chewie
- sha256: "44bcfc5f0dfd1de290c87c9d86a61308b3282a70b63435d5557cfd60f54a69ca"
- url: "https://pub.dev"
- source: hosted
- version: "1.13.0"
- cli_config:
- dependency: transitive
- description:
- name: cli_config
- sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- cli_util:
- dependency: transitive
- description:
- name: cli_util
- sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
- url: "https://pub.dev"
- source: hosted
- version: "0.4.2"
- clock:
- dependency: transitive
- description:
- name: clock
- sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- collection:
- dependency: "direct main"
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- colorize:
- dependency: transitive
- description:
- name: colorize
- sha256: "584746cd6ba1cba0633b6720f494fe6f9601c4170f0666c1579d2aa2a61071ba"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.0"
- console:
- dependency: transitive
- description:
- name: console
- sha256: e04e7824384c5b39389acdd6dc7d33f3efe6b232f6f16d7626f194f6a01ad69a
- url: "https://pub.dev"
- source: hosted
- version: "4.1.0"
- convert:
- dependency: transitive
- description:
- name: convert
- sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- coverage:
- dependency: transitive
- description:
- name: coverage
- sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
- url: "https://pub.dev"
- source: hosted
- version: "1.15.0"
- cross_file:
- dependency: "direct main"
- description:
- name: cross_file
- sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.4+2"
- crypto:
- dependency: transitive
- description:
- name: crypto
- sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.6"
- csslib:
- dependency: transitive
- description:
- name: csslib
- sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.2"
- cupertino_icons:
- dependency: "direct main"
- description:
- name: cupertino_icons
- sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
- url: "https://pub.dev"
- source: hosted
- version: "1.0.8"
- dart_webrtc:
- dependency: transitive
- description:
- name: dart_webrtc
- sha256: "51bcda4ba5d7dd9e65a309244ce3ac0b58025e6e1f6d7442cee4cd02134ef65f"
- url: "https://pub.dev"
- source: hosted
- version: "1.6.0"
- dbus:
- dependency: transitive
- description:
- name: dbus
- sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.11"
- desktop_drop:
- dependency: "direct main"
- description:
- name: desktop_drop
- sha256: d55a010fe46c8e8fcff4ea4b451a9ff84a162217bdb3b2a0aa1479776205e15d
- url: "https://pub.dev"
- source: hosted
- version: "0.4.4"
- desktop_notifications:
- dependency: "direct main"
- description:
- name: desktop_notifications
- sha256: "6d92694ad6e9297a862c5ff7dd6b8ff64c819972557754769f819d2209612927"
- url: "https://pub.dev"
- source: hosted
- version: "0.6.3"
- device_info_plus:
- dependency: "direct main"
- description:
- name: device_info_plus
- sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
- url: "https://pub.dev"
- source: hosted
- version: "10.1.2"
- device_info_plus_platform_interface:
- dependency: transitive
- description:
- name: device_info_plus_platform_interface
- sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
- url: "https://pub.dev"
- source: hosted
- version: "7.0.3"
- dio:
- dependency: "direct main"
- description:
- name: dio
- sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9
- url: "https://pub.dev"
- source: hosted
- version: "5.9.0"
- dio_web_adapter:
- dependency: transitive
- description:
- name: dio_web_adapter
- sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.1"
- dynamic_color:
- dependency: "direct main"
- description:
- name: dynamic_color
- sha256: "43a5a6679649a7731ab860334a5812f2067c2d9ce6452cf069c5e0c25336c17c"
- url: "https://pub.dev"
- source: hosted
- version: "1.8.1"
- emoji_picker_flutter:
- dependency: "direct main"
- description:
- name: emoji_picker_flutter
- sha256: "08567e6f914d36c32091a96cf2f51d2558c47aa2bd47a590dc4f50e42e0965f6"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- emojis:
- dependency: "direct main"
- description:
- name: emojis
- sha256: "2e4d847c3f1e2670f30dc355909ce6fa7808b4e626c34a4dd503a360995a38bf"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.9"
- fake_async:
- dependency: transitive
- description:
- name: fake_async
- sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- ffi:
- dependency: transitive
- description:
- name: ffi
- sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- file:
- dependency: transitive
- description:
- name: file
- sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- file_picker:
- dependency: "direct main"
- description:
- name: file_picker
- sha256: f2d9f173c2c14635cc0e9b14c143c49ef30b4934e8d1d274d6206fcb0086a06f
- url: "https://pub.dev"
- source: hosted
- version: "10.3.3"
- file_selector:
- dependency: "direct main"
- description:
- name: file_selector
- sha256: "5f1d15a7f17115038f433d1b0ea57513cc9e29a9d5338d166cb0bef3fa90a7a0"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.4"
- file_selector_android:
- dependency: transitive
- description:
- name: file_selector_android
- sha256: "1ce58b609289551f8ec07265476720e77d19764339cc1d8e4df3c4d34dac6499"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.1+17"
- file_selector_ios:
- dependency: transitive
- description:
- name: file_selector_ios
- sha256: fe9f52123af16bba4ad65bd7e03defbbb4b172a38a8e6aaa2a869a0c56a5f5fb
- url: "https://pub.dev"
- source: hosted
- version: "0.5.3+2"
- file_selector_linux:
- dependency: transitive
- description:
- name: file_selector_linux
- sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.3+2"
- file_selector_macos:
- dependency: transitive
- description:
- name: file_selector_macos
- sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.4+4"
- file_selector_platform_interface:
- dependency: transitive
- description:
- name: file_selector_platform_interface
- sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
- url: "https://pub.dev"
- source: hosted
- version: "2.6.2"
- file_selector_web:
- dependency: transitive
- description:
- name: file_selector_web
- sha256: c4c0ea4224d97a60a7067eca0c8fd419e708ff830e0c83b11a48faf566cec3e7
- url: "https://pub.dev"
- source: hosted
- version: "0.9.4+2"
- file_selector_windows:
- dependency: transitive
- description:
- name: file_selector_windows
- sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.3+4"
- fixnum:
- dependency: transitive
- description:
- name: fixnum
- sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_cache_manager:
- dependency: "direct main"
- description:
- name: flutter_cache_manager
- sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
- url: "https://pub.dev"
- source: hosted
- version: "3.4.1"
- flutter_driver:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_foreground_task:
- dependency: "direct main"
- description:
- name: flutter_foreground_task
- sha256: "6cf10a27f5e344cd2ecad0752d3a5f4ec32846d82fda8753b3fe2480ebb832a3"
- url: "https://pub.dev"
- source: hosted
- version: "6.5.0"
- flutter_highlighter:
- dependency: "direct main"
- description:
- name: flutter_highlighter
- sha256: "93173afd47a9ada53f3176371755e7ea4a1065362763976d06d6adfb4d946e10"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.1"
- flutter_keyboard_visibility:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility
- sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8"
- url: "https://pub.dev"
- source: hosted
- version: "6.0.0"
- flutter_keyboard_visibility_linux:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility_linux
- sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- flutter_keyboard_visibility_macos:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility_macos
- sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- flutter_keyboard_visibility_platform_interface:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility_platform_interface
- sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- flutter_keyboard_visibility_web:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility_web
- sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- flutter_keyboard_visibility_windows:
- dependency: transitive
- description:
- name: flutter_keyboard_visibility_windows
- sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- flutter_linkify:
- dependency: "direct main"
- description:
- name: flutter_linkify
- sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073"
- url: "https://pub.dev"
- source: hosted
- version: "6.0.0"
- flutter_lints:
- dependency: "direct dev"
- description:
- name: flutter_lints
- sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- flutter_local_notifications:
- dependency: "direct main"
- description:
- name: flutter_local_notifications
- sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
- url: "https://pub.dev"
- source: hosted
- version: "17.2.4"
- flutter_local_notifications_linux:
- dependency: transitive
- description:
- name: flutter_local_notifications_linux
- sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
- url: "https://pub.dev"
- source: hosted
- version: "4.0.1"
- flutter_local_notifications_platform_interface:
- dependency: transitive
- description:
- name: flutter_local_notifications_platform_interface
- sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
- url: "https://pub.dev"
- source: hosted
- version: "7.2.0"
- flutter_localizations:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_map:
- dependency: "direct main"
- description:
- name: flutter_map
- sha256: "87cc8349b8fa5dccda5af50018c7374b6645334a0d680931c1fe11bce88fa5bb"
- url: "https://pub.dev"
- source: hosted
- version: "6.2.1"
- flutter_native_splash:
- dependency: "direct dev"
- description:
- name: flutter_native_splash
- sha256: "8321a6d11a8d13977fa780c89de8d257cce3d841eecfb7a4cadffcc4f12d82dc"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.6"
- flutter_new_badger:
- dependency: "direct main"
- description:
- name: flutter_new_badger
- sha256: d3742ace8009663db1ac6ba0377b092f479c35deb33e05514ba05cc0b0a5aaaa
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- flutter_openssl_crypto:
- dependency: "direct main"
- description:
- name: flutter_openssl_crypto
- sha256: "293b4fcda13ab0710645a16e82f3d5b7de19bfc0ab2d06bcdb87637222eda5e1"
- url: "https://pub.dev"
- source: hosted
- version: "0.5.0"
- flutter_plugin_android_lifecycle:
- dependency: transitive
- description:
- name: flutter_plugin_android_lifecycle
- sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31
- url: "https://pub.dev"
- source: hosted
- version: "2.0.30"
- flutter_rust_bridge:
- dependency: "direct main"
- description:
- name: flutter_rust_bridge
- sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e"
- url: "https://pub.dev"
- source: hosted
- version: "2.11.1"
- flutter_secure_storage:
- dependency: "direct main"
- description:
- name: flutter_secure_storage
- sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
- url: "https://pub.dev"
- source: hosted
- version: "9.2.4"
- flutter_secure_storage_linux:
- dependency: transitive
- description:
- name: flutter_secure_storage_linux
- sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
- url: "https://pub.dev"
- source: hosted
- version: "1.2.3"
- flutter_secure_storage_macos:
- dependency: transitive
- description:
- name: flutter_secure_storage_macos
- sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
- flutter_secure_storage_platform_interface:
- dependency: transitive
- description:
- name: flutter_secure_storage_platform_interface
- sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- flutter_secure_storage_web:
- dependency: transitive
- description:
- name: flutter_secure_storage_web
- sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
- url: "https://pub.dev"
- source: hosted
- version: "1.2.1"
- flutter_secure_storage_windows:
- dependency: transitive
- description:
- name: flutter_secure_storage_windows
- sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- flutter_shortcuts_new:
- dependency: "direct main"
- description:
- name: flutter_shortcuts_new
- sha256: "16ee1c8a9bc9586b5117ebb774a8ff6b396f856743e97251eb483c4dc5769d7f"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- flutter_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_typeahead:
- dependency: "direct main"
- description:
- path: "."
- ref: main
- resolved-ref: "3e209e67aa6e780cba61ced06cf49d2babbbcaa4"
- url: "https://github.com/famedly/flutter_typeahead.git"
- source: git
- version: "5.2.0"
- flutter_vodozemac:
- dependency: "direct main"
- description:
- name: flutter_vodozemac
- sha256: "54cd3790b6dfdc1afce928f8c46f7eeea9e4f8326f077400894935926f202057"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- flutter_web_auth_2:
- dependency: "direct main"
- description:
- path: flutter_web_auth_2
- ref: "3.x-without-v1"
- resolved-ref: "48682f19576001e50104a602d891343850adb67f"
- url: "https://github.com/ThexXTURBOXx/flutter_web_auth_2.git"
- source: git
- version: "3.1.2-without-v1"
- flutter_web_auth_2_platform_interface:
- dependency: transitive
- description:
- name: flutter_web_auth_2_platform_interface
- sha256: e8669e262005a8354389ba2971f0fc1c36188481234ff50d013aaf993f30f739
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- flutter_web_plugins:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- flutter_webrtc:
- dependency: "direct main"
- description:
- name: flutter_webrtc
- sha256: b832dc76c0d1577f14aaf35e9c38d4ed7667cbc89c492b7bf4505d8d5f62e08b
- url: "https://pub.dev"
- source: hosted
- version: "0.12.12+hotfix.1"
- frontend_server_client:
- dependency: transitive
- description:
- name: frontend_server_client
- sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
- url: "https://pub.dev"
- source: hosted
- version: "4.0.0"
- fuchsia_remote_debug_protocol:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- geolocator:
- dependency: "direct main"
- description:
- name: geolocator
- sha256: f62bcd90459e63210bbf9c35deb6a51c521f992a78de19a1fe5c11704f9530e2
- url: "https://pub.dev"
- source: hosted
- version: "13.0.4"
- geolocator_android:
- dependency: transitive
- description:
- name: geolocator_android
- sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d
- url: "https://pub.dev"
- source: hosted
- version: "4.6.2"
- geolocator_apple:
- dependency: transitive
- description:
- name: geolocator_apple
- sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22
- url: "https://pub.dev"
- source: hosted
- version: "2.3.13"
- geolocator_platform_interface:
- dependency: transitive
- description:
- name: geolocator_platform_interface
- sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67"
- url: "https://pub.dev"
- source: hosted
- version: "4.2.6"
- geolocator_web:
- dependency: transitive
- description:
- name: geolocator_web
- sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172
- url: "https://pub.dev"
- source: hosted
- version: "4.1.3"
- geolocator_windows:
- dependency: transitive
- description:
- name: geolocator_windows
- sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.5"
- get_it:
- dependency: transitive
- description:
- name: get_it
- sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b
- url: "https://pub.dev"
- source: hosted
- version: "8.2.0"
- glob:
- dependency: transitive
- description:
- name: glob
- sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
- url: "https://pub.dev"
- source: hosted
- version: "2.1.3"
- go_router:
- dependency: "direct main"
- description:
- name: go_router
- sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3
- url: "https://pub.dev"
- source: hosted
- version: "14.8.1"
- gtk:
- dependency: transitive
- description:
- name: gtk
- sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
- url: "https://pub.dev"
- source: hosted
- version: "2.1.0"
- handy_window:
- dependency: "direct main"
- description:
- name: handy_window
- sha256: "56b813e58a68b0ee2ab22051400b8b1f1b5cfe88b8cd32288623defb3926245a"
- url: "https://pub.dev"
- source: hosted
- version: "0.4.0"
- highlight:
- dependency: transitive
- description:
- name: highlight
- sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.0"
- highlight_selectable:
- dependency: "direct main"
- description:
- name: highlight_selectable
- sha256: c9a9c8741bd5ba2150f1ba2c713f4ea2d6dfd6b700d66ca11675882a75c4db20
- url: "https://pub.dev"
- source: hosted
- version: "0.1.4"
- highlighter:
- dependency: transitive
- description:
- name: highlighter
- sha256: "92180c72b9da8758e1acf39a45aa305a97dcfe2fdc8f3d1d2947c23f2772bfbc"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.1"
- hive:
- dependency: "direct main"
- description:
- name: hive
- sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.3"
- hive_flutter:
- dependency: "direct main"
- description:
- name: hive_flutter
- sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- html:
- dependency: "direct main"
- description:
- name: html
- sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602"
- url: "https://pub.dev"
- source: hosted
- version: "0.15.6"
- html_unescape:
- dependency: transitive
- description:
- name: html_unescape
- sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- http:
- dependency: "direct main"
- description:
- name: http
- sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
- url: "https://pub.dev"
- source: hosted
- version: "1.5.0"
- http_multi_server:
- dependency: transitive
- description:
- name: http_multi_server
- sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
- url: "https://pub.dev"
- source: hosted
- version: "3.2.2"
- http_parser:
- dependency: transitive
- description:
- name: http_parser
- sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
- url: "https://pub.dev"
- source: hosted
- version: "4.1.2"
- image:
- dependency: "direct main"
- description:
- name: image
- sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
- url: "https://pub.dev"
- source: hosted
- version: "4.5.4"
- image_picker:
- dependency: "direct main"
- description:
- name: image_picker
- sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.0"
- image_picker_android:
- dependency: transitive
- description:
- name: image_picker_android
- sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e"
- url: "https://pub.dev"
- source: hosted
- version: "0.8.13+1"
- image_picker_for_web:
- dependency: transitive
- description:
- name: image_picker_for_web
- sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- image_picker_ios:
- dependency: transitive
- description:
- name: image_picker_ios
- sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
- url: "https://pub.dev"
- source: hosted
- version: "0.8.13"
- image_picker_linux:
- dependency: transitive
- description:
- name: image_picker_linux
- sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.2"
- image_picker_macos:
- dependency: transitive
- description:
- name: image_picker_macos
- sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
- url: "https://pub.dev"
- source: hosted
- version: "0.2.2"
- image_picker_platform_interface:
- dependency: transitive
- description:
- name: image_picker_platform_interface
- sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
- url: "https://pub.dev"
- source: hosted
- version: "2.11.0"
- image_picker_windows:
- dependency: transitive
- description:
- name: image_picker_windows
- sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
- url: "https://pub.dev"
- source: hosted
- version: "0.2.2"
- import_sorter:
- dependency: "direct dev"
- description:
- name: import_sorter
- sha256: eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836
- url: "https://pub.dev"
- source: hosted
- version: "4.6.0"
- integration_test:
- dependency: "direct dev"
- description: flutter
- source: sdk
- version: "0.0.0"
- intl:
- dependency: "direct main"
- description:
- name: intl
- sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
- url: "https://pub.dev"
- source: hosted
- version: "0.20.2"
- io:
- dependency: transitive
- description:
- name: io
- sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
- url: "https://pub.dev"
- source: hosted
- version: "0.6.7"
- json_annotation:
- dependency: transitive
- description:
- name: json_annotation
- sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
- url: "https://pub.dev"
- source: hosted
- version: "4.9.0"
- just_audio:
- dependency: "direct main"
- description:
- name: just_audio
- sha256: f978d5b4ccea08f267dae0232ec5405c1b05d3f3cd63f82097ea46c015d5c09e
- url: "https://pub.dev"
- source: hosted
- version: "0.9.46"
- just_audio_platform_interface:
- dependency: transitive
- description:
- name: just_audio_platform_interface
- sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a"
- url: "https://pub.dev"
- source: hosted
- version: "4.6.0"
- just_audio_web:
- dependency: transitive
- description:
- name: just_audio_web
- sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663"
- url: "https://pub.dev"
- source: hosted
- version: "0.4.16"
- latlong2:
- dependency: "direct main"
- description:
- name: latlong2
- sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.1"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
- url: "https://pub.dev"
- source: hosted
- version: "11.0.2"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.10"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- license_checker:
- dependency: "direct dev"
- description:
- name: license_checker
- sha256: eea27638e42bc98fd91a6a8187eb57e5617e2c3c8b313a5d51b14bec7a8685e1
- url: "https://pub.dev"
- source: hosted
- version: "1.6.0"
- linkify:
- dependency: "direct main"
- description:
- name: linkify
- sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.0"
- lints:
- dependency: transitive
- description:
- name: lints
- sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
- url: "https://pub.dev"
- source: hosted
- version: "3.0.0"
- lists:
- dependency: transitive
- description:
- name: lists
- sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- logger:
- dependency: transitive
- description:
- name: logger
- sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3
- url: "https://pub.dev"
- source: hosted
- version: "2.6.2"
- logging:
- dependency: transitive
- description:
- name: logging
- sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- markdown:
- dependency: transitive
- description:
- name: markdown
- sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
- url: "https://pub.dev"
- source: hosted
- version: "7.3.0"
- matcher:
- dependency: transitive
- description:
- name: matcher
- sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
- url: "https://pub.dev"
- source: hosted
- version: "0.12.17"
- material:
- dependency: "direct main"
- description:
- name: material
- sha256: "7f3a2edadf60e3a8771b843baff931d4b2e7205d015059c3abe315344f23dfa4"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0+2"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
- url: "https://pub.dev"
- source: hosted
- version: "0.11.1"
- matrix:
- dependency: "direct main"
- description:
- path: "."
- ref: main
- resolved-ref: "58c4cf19d010d9ae193e9df10bd1f8fdf02277b0"
- url: "https://git.extera.xyz/OfficialDakari/matrix-dart-sdk.git"
- source: git
- version: "2.0.1"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
- url: "https://pub.dev"
- source: hosted
- version: "1.16.0"
- mgrs_dart:
- dependency: transitive
- description:
- name: mgrs_dart
- sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- mime:
- dependency: "direct main"
- description:
- name: mime
- sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.6"
- msix:
- dependency: "direct dev"
- description:
- name: msix
- sha256: f88033fcb9e0dd8de5b18897cbebbd28ea30596810f4a7c86b12b0c03ace87e5
- url: "https://pub.dev"
- source: hosted
- version: "3.16.12"
- native_imaging:
- dependency: "direct main"
- description:
- name: native_imaging
- sha256: "93573afdcab070011d78a40fc1f69b61967f1f8485d2b81a7a2ee585a85f4c04"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- nested:
- dependency: transitive
- description:
- name: nested
- sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- node_preamble:
- dependency: transitive
- description:
- name: node_preamble
- sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- opus_caf_converter_dart:
- dependency: "direct main"
- description:
- name: opus_caf_converter_dart
- sha256: e08156066916f790a54df305e103d6dec4d853ec23147e6a02eda3c06f67ba1a
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- package_config:
- dependency: transitive
- description:
- name: package_config
- sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- package_info_plus:
- dependency: "direct main"
- description:
- name: package_info_plus
- sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968"
- url: "https://pub.dev"
- source: hosted
- version: "8.3.1"
- package_info_plus_platform_interface:
- dependency: transitive
- description:
- name: package_info_plus_platform_interface
- sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
- url: "https://pub.dev"
- source: hosted
- version: "3.2.1"
- pana:
- dependency: transitive
- description:
- name: pana
- sha256: "3fc3fe8e7a9fd4827fa4d625a423eec95d305b2bc3538a3adf7fd6c49217af97"
- url: "https://pub.dev"
- source: hosted
- version: "0.21.45"
- pasteboard:
- dependency: "direct main"
- description:
- name: pasteboard
- sha256: "1c8b6a8b3f1d12e55d4e9404433cda1b4abe66db6b17bc2d2fb5965772c04674"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- path:
- dependency: "direct main"
- description:
- name: path
- sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
- url: "https://pub.dev"
- source: hosted
- version: "1.9.1"
- path_provider:
- dependency: "direct main"
- description:
- name: path_provider
- sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.5"
- path_provider_android:
- dependency: transitive
- description:
- name: path_provider_android
- sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.18"
- path_provider_foundation:
- dependency: transitive
- description:
- name: path_provider_foundation
- sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.2"
- path_provider_linux:
- dependency: transitive
- description:
- name: path_provider_linux
- sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
- url: "https://pub.dev"
- source: hosted
- version: "2.2.1"
- path_provider_platform_interface:
- dependency: transitive
- description:
- name: path_provider_platform_interface
- sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- path_provider_windows:
- dependency: transitive
- description:
- name: path_provider_windows
- sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- permission_handler:
- dependency: "direct main"
- description:
- name: permission_handler
- sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
- url: "https://pub.dev"
- source: hosted
- version: "11.4.0"
- permission_handler_android:
- dependency: transitive
- description:
- name: permission_handler_android
- sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
- url: "https://pub.dev"
- source: hosted
- version: "12.1.0"
- permission_handler_apple:
- dependency: transitive
- description:
- name: permission_handler_apple
- sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023
- url: "https://pub.dev"
- source: hosted
- version: "9.4.7"
- permission_handler_html:
- dependency: transitive
- description:
- name: permission_handler_html
- sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
- url: "https://pub.dev"
- source: hosted
- version: "0.1.3+5"
- permission_handler_platform_interface:
- dependency: transitive
- description:
- name: permission_handler_platform_interface
- sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
- url: "https://pub.dev"
- source: hosted
- version: "4.3.0"
- permission_handler_windows:
- dependency: transitive
- description:
- name: permission_handler_windows
- sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.1"
- petitparser:
- dependency: transitive
- description:
- name: petitparser
- sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
- url: "https://pub.dev"
- source: hosted
- version: "7.0.1"
- platform:
- dependency: transitive
- description:
- name: platform
- sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.6"
- plugin_platform_interface:
- dependency: transitive
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- pointer_interceptor:
- dependency: transitive
- description:
- name: pointer_interceptor
- sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523"
- url: "https://pub.dev"
- source: hosted
- version: "0.10.1+2"
- pointer_interceptor_ios:
- dependency: transitive
- description:
- name: pointer_interceptor_ios
- sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917
- url: "https://pub.dev"
- source: hosted
- version: "0.10.1"
- pointer_interceptor_platform_interface:
- dependency: transitive
- description:
- name: pointer_interceptor_platform_interface
- sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506"
- url: "https://pub.dev"
- source: hosted
- version: "0.10.0+1"
- pointer_interceptor_web:
- dependency: transitive
- description:
- name: pointer_interceptor_web
- sha256: "460b600e71de6fcea2b3d5f662c92293c049c4319e27f0829310e5a953b3ee2a"
- url: "https://pub.dev"
- source: hosted
- version: "0.10.3"
- polylabel:
- dependency: transitive
- description:
- name: polylabel
- sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- pool:
- dependency: transitive
- description:
- name: pool
- sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.2"
- posix:
- dependency: transitive
- description:
- name: posix
- sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
- url: "https://pub.dev"
- source: hosted
- version: "6.0.3"
- pretty_qr_code:
- dependency: "direct main"
- description:
- name: pretty_qr_code
- sha256: "2291db3f68d70a3dcd46c6bd599f30991ae4c02f27f36215fbb3f4865a609259"
- url: "https://pub.dev"
- source: hosted
- version: "3.5.0"
- process:
- dependency: transitive
- description:
- name: process
- sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.3"
- proj4dart:
- dependency: transitive
- description:
- name: proj4dart
- sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e
- url: "https://pub.dev"
- source: hosted
- version: "2.1.0"
- provider:
- dependency: "direct main"
- description:
- name: provider
- sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
- url: "https://pub.dev"
- source: hosted
- version: "6.1.5+1"
- pub_semver:
- dependency: transitive
- description:
- name: pub_semver
- sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- pubspec_parse:
- dependency: transitive
- description:
- name: pubspec_parse
- sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
- url: "https://pub.dev"
- source: hosted
- version: "1.5.0"
- punycode:
- dependency: "direct main"
- description:
- name: punycode
- sha256: "39b874cc1f78b94e57db17e74b3f2ba2a96e25c0bebdcc8a571614dccda0ff0c"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- qr:
- dependency: transitive
- description:
- name: qr
- sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- qr_code_scanner_plus:
- dependency: "direct main"
- description:
- name: qr_code_scanner_plus
- sha256: a0f1ac8e13299b3db2646635f252fe2ec67222b848b24ed34d11052faf080bfa
- url: "https://pub.dev"
- source: hosted
- version: "2.0.12"
- qr_image:
- dependency: "direct main"
- description:
- name: qr_image
- sha256: c3cd2ac2c6cd6b14604c97b45c477b18988b6518f72120fa04418fc54e3b0d76
- url: "https://pub.dev"
- source: hosted
- version: "1.0.0"
- random_string:
- dependency: transitive
- description:
- name: random_string
- sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.1"
- receive_sharing_intent:
- dependency: "direct main"
- description:
- name: receive_sharing_intent
- sha256: ec76056e4d258ad708e76d85591d933678625318e411564dcb9059048ca3a593
- url: "https://pub.dev"
- source: hosted
- version: "1.8.1"
- record:
- dependency: "direct main"
- description:
- name: record
- sha256: "6bad72fb3ea6708d724cf8b6c97c4e236cf9f43a52259b654efeb6fd9b737f1f"
- url: "https://pub.dev"
- source: hosted
- version: "6.1.2"
- record_android:
- dependency: transitive
- description:
- name: record_android
- sha256: f05677eeed074898327f890f232f9eb49cd99d1c20d0daaf22b5612f4b2301bb
- url: "https://pub.dev"
- source: hosted
- version: "1.4.3"
- record_ios:
- dependency: transitive
- description:
- name: record_ios
- sha256: "765b42ac1be019b1674ddd809b811fc721fe5a93f7bb1da7803f0d16772fd6d7"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.4"
- record_linux:
- dependency: transitive
- description:
- name: record_linux
- sha256: "235b1f1fb84e810f8149cc0c2c731d7d697f8d1c333b32cb820c449bf7bb72d8"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.1"
- record_macos:
- dependency: transitive
- description:
- name: record_macos
- sha256: "842ea4b7e95f4dd237aacffc686d1b0ff4277e3e5357865f8d28cd28bc18ed95"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- record_platform_interface:
- dependency: transitive
- description:
- name: record_platform_interface
- sha256: b0065fdf1ec28f5a634d676724d388a77e43ce7646fb049949f58c69f3fcb4ed
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- record_web:
- dependency: transitive
- description:
- name: record_web
- sha256: "4f0adf20c9ccafcc02d71111fd91fba1ca7b17a7453902593e5a9b25b74a5c56"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.0"
- record_windows:
- dependency: transitive
- description:
- name: record_windows
- sha256: "223258060a1d25c62bae18282c16783f28581ec19401d17e56b5205b9f039d78"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.7"
- retry:
- dependency: transitive
- description:
- name: retry
- sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.2"
- rxdart:
- dependency: transitive
- description:
- name: rxdart
- sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
- url: "https://pub.dev"
- source: hosted
- version: "0.28.0"
- safe_url_check:
- dependency: transitive
- description:
- name: safe_url_check
- sha256: "49a3e060a7869cbafc8f4845ca1ecbbaaa53179980a32f4fdfeab1607e90f41d"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.2"
- scroll_to_index:
- dependency: "direct main"
- description:
- name: scroll_to_index
- sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176
- url: "https://pub.dev"
- source: hosted
- version: "3.0.1"
- sdp_transform:
- dependency: transitive
- description:
- name: sdp_transform
- sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.2"
- share_plus:
- dependency: "direct main"
- description:
- name: share_plus
- sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da
- url: "https://pub.dev"
- source: hosted
- version: "10.1.4"
- share_plus_platform_interface:
- dependency: transitive
- description:
- name: share_plus_platform_interface
- sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b
- url: "https://pub.dev"
- source: hosted
- version: "5.0.2"
- shared_preferences:
- dependency: "direct main"
- description:
- name: shared_preferences
- sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.3"
- shared_preferences_android:
- dependency: transitive
- description:
- name: shared_preferences_android
- sha256: bd14436108211b0d4ee5038689a56d4ae3620fd72fd6036e113bf1345bc74d9e
- url: "https://pub.dev"
- source: hosted
- version: "2.4.13"
- shared_preferences_foundation:
- dependency: transitive
- description:
- name: shared_preferences_foundation
- sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.4"
- shared_preferences_linux:
- dependency: transitive
- description:
- name: shared_preferences_linux
- sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_platform_interface:
- dependency: transitive
- description:
- name: shared_preferences_platform_interface
- sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shared_preferences_web:
- dependency: transitive
- description:
- name: shared_preferences_web
- sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
- url: "https://pub.dev"
- source: hosted
- version: "2.4.3"
- shared_preferences_windows:
- dependency: transitive
- description:
- name: shared_preferences_windows
- sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- shelf:
- dependency: transitive
- description:
- name: shelf
- sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
- url: "https://pub.dev"
- source: hosted
- version: "1.4.2"
- shelf_packages_handler:
- dependency: transitive
- description:
- name: shelf_packages_handler
- sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.2"
- shelf_static:
- dependency: transitive
- description:
- name: shelf_static
- sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
- url: "https://pub.dev"
- source: hosted
- version: "1.1.3"
- shelf_web_socket:
- dependency: transitive
- description:
- name: shelf_web_socket
- sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.0"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- slugify:
- dependency: "direct main"
- description:
- name: slugify
- sha256: b272501565cb28050cac2d96b7bf28a2d24c8dae359280361d124f3093d337c3
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- source_map_stack_trace:
- dependency: transitive
- description:
- name: source_map_stack_trace
- sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
- url: "https://pub.dev"
- source: hosted
- version: "2.1.2"
- source_maps:
- dependency: transitive
- description:
- name: source_maps
- sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
- url: "https://pub.dev"
- source: hosted
- version: "0.10.13"
- source_span:
- dependency: transitive
- description:
- name: source_span
- sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
- url: "https://pub.dev"
- source: hosted
- version: "1.10.1"
- sprintf:
- dependency: transitive
- description:
- name: sprintf
- sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
- url: "https://pub.dev"
- source: hosted
- version: "7.0.0"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
- url: "https://pub.dev"
- source: hosted
- version: "2.4.2"
- sqflite_android:
- dependency: transitive
- description:
- name: sqflite_android
- sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
- url: "https://pub.dev"
- source: hosted
- version: "2.5.6"
- sqflite_common_ffi:
- dependency: "direct main"
- description:
- name: sqflite_common_ffi
- sha256: "9faa2fedc5385ef238ce772589f7718c24cdddd27419b609bb9c6f703ea27988"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.6"
- sqflite_darwin:
- dependency: transitive
- description:
- name: sqflite_darwin
- sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.2"
- sqflite_platform_interface:
- dependency: transitive
- description:
- name: sqflite_platform_interface
- sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- sqlcipher_flutter_libs:
- dependency: "direct main"
- description:
- name: sqlcipher_flutter_libs
- sha256: dd1fcc74d5baf3c36ad53e2652b2d06c9f8747494a3ccde0076e88b159dfe622
- url: "https://pub.dev"
- source: hosted
- version: "0.6.8"
- sqlite3:
- dependency: transitive
- description:
- name: sqlite3
- sha256: "5c225083e72ea56c96d94ba1dd14fb89c8bb7731c8496ee840ab77be9bb67ae2"
- url: "https://pub.dev"
- source: hosted
- version: "2.9.1"
- stack_trace:
- dependency: transitive
- description:
- name: stack_trace
- sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
- url: "https://pub.dev"
- source: hosted
- version: "1.12.1"
- stream_channel:
- dependency: transitive
- description:
- name: stream_channel
- sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.4"
- string_scanner:
- dependency: transitive
- description:
- name: string_scanner
- sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
- url: "https://pub.dev"
- source: hosted
- version: "1.4.1"
- string_validator:
- dependency: transitive
- description:
- name: string_validator
- sha256: "50dd8ecf91db6a732f4a851eeae81ee12406eedc62d0da72f2d91a04a2d10dd8"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- swipe_to_action:
- dependency: "direct main"
- description:
- name: swipe_to_action
- sha256: "05289a2bff6a0227deeff382afa1c46643d1f077e678d78f76440e153ea1ef7d"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- sync_http:
- dependency: transitive
- description:
- name: sync_http
- sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.1"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
- url: "https://pub.dev"
- source: hosted
- version: "3.4.0"
- tar:
- dependency: transitive
- description:
- name: tar
- sha256: "22f67e2d77b51050436620b2a5de521c58ca6f0b75af1d9ab3c8cae2eae58fcd"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.5"
- term_glyph:
- dependency: transitive
- description:
- name: term_glyph
- sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.2"
- test:
- dependency: transitive
- description:
- name: test
- sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb"
- url: "https://pub.dev"
- source: hosted
- version: "1.26.2"
- test_api:
- dependency: transitive
- description:
- name: test_api
- sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.6"
- test_core:
- dependency: transitive
- description:
- name: test_core
- sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a"
- url: "https://pub.dev"
- source: hosted
- version: "0.6.11"
- timezone:
- dependency: transitive
- description:
- name: timezone
- sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
- url: "https://pub.dev"
- source: hosted
- version: "0.9.4"
- tint:
- dependency: transitive
- description:
- name: tint
- sha256: "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.1"
- tor_detector_web:
- dependency: "direct main"
- description:
- name: tor_detector_web
- sha256: c4acbd6c0fecd2cd0e8fe00b1a37332422e041021a42488dfddcb3e7ec809b3f
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- translations_cleaner:
- dependency: "direct dev"
- description:
- name: translations_cleaner
- sha256: "060f4a8cd782e271509719741dd3540fe81ddaad49bd79e1d8fc4598299a6b84"
- url: "https://pub.dev"
- source: hosted
- version: "0.0.5"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- unicode:
- dependency: transitive
- description:
- name: unicode
- sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.1"
- unifiedpush:
- dependency: "direct main"
- description:
- name: unifiedpush
- sha256: "6dbed5a6305ca33f1865c7a3d814ae39476b79a2d23ca76a5708f023f405730f"
- url: "https://pub.dev"
- source: hosted
- version: "5.0.2"
- unifiedpush_android:
- dependency: transitive
- description:
- name: unifiedpush_android
- sha256: "7443dece0a850ae956514f809983eb2b39fc518c2c7d24dbfe817198bec89134"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.0"
- unifiedpush_platform_interface:
- dependency: transitive
- description:
- name: unifiedpush_platform_interface
- sha256: dd588d78a8b2bfc10430e30035526e98caa543d0b7364a6344b5eb4815721c6d
- url: "https://pub.dev"
- source: hosted
- version: "2.0.2"
- unifiedpush_ui:
- dependency: "direct main"
- description:
- name: unifiedpush_ui
- sha256: cf86f0214f37debd41f25c0425c8489df85e27f9f8784fed571eb7a86d39ba11
- url: "https://pub.dev"
- source: hosted
- version: "0.1.0"
- universal_html:
- dependency: "direct main"
- description:
- name: universal_html
- sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.4"
- universal_io:
- dependency: transitive
- description:
- name: universal_io
- sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
- url: "https://pub.dev"
- source: hosted
- version: "2.2.2"
- unorm_dart:
- dependency: transitive
- description:
- name: unorm_dart
- sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
- url: "https://pub.dev"
- source: hosted
- version: "0.2.0"
- url_launcher:
- dependency: "direct main"
- description:
- name: url_launcher
- sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8
- url: "https://pub.dev"
- source: hosted
- version: "6.3.2"
- url_launcher_android:
- dependency: transitive
- description:
- name: url_launcher_android
- sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e"
- url: "https://pub.dev"
- source: hosted
- version: "6.3.20"
- url_launcher_ios:
- dependency: transitive
- description:
- name: url_launcher_ios
- sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7
- url: "https://pub.dev"
- source: hosted
- version: "6.3.4"
- url_launcher_linux:
- dependency: transitive
- description:
- name: url_launcher_linux
- sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
- url: "https://pub.dev"
- source: hosted
- version: "3.2.1"
- url_launcher_macos:
- dependency: transitive
- description:
- name: url_launcher_macos
- sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f
- url: "https://pub.dev"
- source: hosted
- version: "3.2.3"
- url_launcher_platform_interface:
- dependency: transitive
- description:
- name: url_launcher_platform_interface
- sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
- url: "https://pub.dev"
- source: hosted
- version: "2.3.2"
- url_launcher_web:
- dependency: transitive
- description:
- name: url_launcher_web
- sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.1"
- url_launcher_windows:
- dependency: transitive
- description:
- name: url_launcher_windows
- sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.4"
- uuid:
- dependency: transitive
- description:
- name: uuid
- sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
- url: "https://pub.dev"
- source: hosted
- version: "4.5.1"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
- video_compress:
- dependency: "direct main"
- description:
- name: video_compress
- sha256: "31bc5cdb9a02ba666456e5e1907393c28e6e0e972980d7d8d619a7beda0d4f20"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.4"
- video_player:
- dependency: "direct main"
- description:
- name: video_player
- sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a"
- url: "https://pub.dev"
- source: hosted
- version: "2.10.0"
- video_player_android:
- dependency: transitive
- description:
- name: video_player_android
- sha256: "6cfe0b1e102522eda1e139b82bf00602181c5844fd2885340f595fb213d74842"
- url: "https://pub.dev"
- source: hosted
- version: "2.8.14"
- video_player_avfoundation:
- dependency: transitive
- description:
- name: video_player_avfoundation
- sha256: f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd
- url: "https://pub.dev"
- source: hosted
- version: "2.8.4"
- video_player_platform_interface:
- dependency: transitive
- description:
- name: video_player_platform_interface
- sha256: cf2a1d29a284db648fd66cbd18aacc157f9862d77d2cc790f6f9678a46c1db5a
- url: "https://pub.dev"
- source: hosted
- version: "6.4.0"
- video_player_web:
- dependency: transitive
- description:
- name: video_player_web
- sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
- url: "https://pub.dev"
- source: hosted
- version: "2.4.0"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
- url: "https://pub.dev"
- source: hosted
- version: "15.0.0"
- vodozemac:
- dependency: "direct main"
- description:
- name: vodozemac
- sha256: "95cac62ffab94db99e134c8f9aac198f8131a4eed0bed76a6cfc9c72add229b9"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- wakelock_plus:
- dependency: "direct main"
- description:
- name: wakelock_plus
- sha256: "61713aa82b7f85c21c9f4cd0a148abd75f38a74ec645fcb1e446f882c82fd09b"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.3"
- wakelock_plus_platform_interface:
- dependency: transitive
- description:
- name: wakelock_plus_platform_interface
- sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- watcher:
- dependency: transitive
- description:
- name: watcher
- sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.4"
- web:
- dependency: transitive
- description:
- name: web
- sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
- web_socket:
- dependency: transitive
- description:
- name: web_socket
- sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
- url: "https://pub.dev"
- source: hosted
- version: "1.0.1"
- web_socket_channel:
- dependency: transitive
- description:
- name: web_socket_channel
- sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
- url: "https://pub.dev"
- source: hosted
- version: "3.0.3"
- webdriver:
- dependency: transitive
- description:
- name: webdriver
- sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
- url: "https://pub.dev"
- source: hosted
- version: "3.1.0"
- webkit_inspection_protocol:
- dependency: transitive
- description:
- name: webkit_inspection_protocol
- sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
- url: "https://pub.dev"
- source: hosted
- version: "1.2.1"
- webrtc_interface:
- dependency: "direct main"
- description:
- name: webrtc_interface
- sha256: "2e604a31703ad26781782fb14fa8a4ee621154ee2c513d2b9938e486fa695233"
- url: "https://pub.dev"
- source: hosted
- version: "1.3.0"
- win32:
- dependency: "direct overridden"
- description:
- name: win32
- sha256: "015002c060f1ae9f41a818f2d5640389cc05283e368be19dc8d77cecb43c40c9"
- url: "https://pub.dev"
- source: hosted
- version: "5.5.3"
- win32_registry:
- dependency: transitive
- description:
- name: win32_registry
- sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.5"
- window_to_front:
- dependency: transitive
- description:
- name: window_to_front
- sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee"
- url: "https://pub.dev"
- source: hosted
- version: "0.0.3"
- wkt_parser:
- dependency: transitive
- description:
- name: wkt_parser
- sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13"
- url: "https://pub.dev"
- source: hosted
- version: "2.0.0"
- xdg_directories:
- dependency: transitive
- description:
- name: xdg_directories
- sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
- url: "https://pub.dev"
- source: hosted
- version: "1.1.0"
- xml:
- dependency: transitive
- description:
- name: xml
- sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
- url: "https://pub.dev"
- source: hosted
- version: "6.6.1"
- yaml:
- dependency: transitive
- description:
- name: yaml
- sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
- url: "https://pub.dev"
- source: hosted
- version: "3.1.3"
-sdks:
- dart: ">=3.8.0 <4.0.0"
- flutter: ">=3.32.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index f3d5167..cd0cccd 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -26,8 +26,8 @@ dependencies:
emoji_picker_flutter: ^3.1.0
emojis: ^0.9.9
#fcm_shared_isolate: ^0.2.0
- file_picker: ^10.2.1
- file_selector: ^1.0.3
+ file_picker: ^10.3.3
+ file_selector: ^1.0.4
flutter:
sdk: flutter
flutter_cache_manager: ^3.4.1
@@ -104,7 +104,7 @@ dependencies:
dev_dependencies:
flutter_lints: ^3.0.0
- flutter_native_splash: ^2.0.3+1
+ flutter_native_splash: ^2.4.6
flutter_test:
sdk: flutter
import_sorter: ^4.6.0