diff --git a/examples/automations/python/requirements.txt b/examples/automations/python/requirements.txt index 164a425a7..64e140fb1 100644 --- a/examples/automations/python/requirements.txt +++ b/examples/automations/python/requirements.txt @@ -1,31 +1,31 @@ -bcrypt==4.1.2 ; python_version >= "3.8" and python_version < "4.0" \ - --hash=sha256:02d9ef8915f72dd6daaef40e0baeef8a017ce624369f09754baf32bb32dba25f \ - --hash=sha256:1c28973decf4e0e69cee78c68e30a523be441972c826703bb93099868a8ff5b5 \ - --hash=sha256:2a298db2a8ab20056120b45e86c00a0a5eb50ec4075b6142db35f593b97cb3fb \ - --hash=sha256:33313a1200a3ae90b75587ceac502b048b840fc69e7f7a0905b5f87fac7a1258 \ - --hash=sha256:3566a88234e8de2ccae31968127b0ecccbb4cddb629da744165db72b58d88ca4 \ - --hash=sha256:387e7e1af9a4dd636b9505a465032f2f5cb8e61ba1120e79a0e1cd0b512f3dfc \ - --hash=sha256:44290ccc827d3a24604f2c8bcd00d0da349e336e6503656cb8192133e27335e2 \ - --hash=sha256:57fa9442758da926ed33a91644649d3e340a71e2d0a5a8de064fb621fd5a3326 \ - --hash=sha256:68e3c6642077b0c8092580c819c1684161262b2e30c4f45deb000c38947bf483 \ - --hash=sha256:69057b9fc5093ea1ab00dd24ede891f3e5e65bee040395fb1e66ee196f9c9b4a \ - --hash=sha256:6cad43d8c63f34b26aef462b6f5e44fdcf9860b723d2453b5d391258c4c8e966 \ - --hash=sha256:71b8be82bc46cedd61a9f4ccb6c1a493211d031415a34adde3669ee1b0afbb63 \ - --hash=sha256:732b3920a08eacf12f93e6b04ea276c489f1c8fb49344f564cca2adb663b3e4c \ - --hash=sha256:9800ae5bd5077b13725e2e3934aa3c9c37e49d3ea3d06318010aa40f54c63551 \ - --hash=sha256:a97e07e83e3262599434816f631cc4c7ca2aa8e9c072c1b1a7fec2ae809a1d2d \ - --hash=sha256:ac621c093edb28200728a9cca214d7e838529e557027ef0581685909acd28b5e \ - --hash=sha256:b8df79979c5bae07f1db22dcc49cc5bccf08a0380ca5c6f391cbb5790355c0b0 \ - --hash=sha256:b90e216dc36864ae7132cb151ffe95155a37a14e0de3a8f64b49655dd959ff9c \ - --hash=sha256:ba4e4cc26610581a6329b3937e02d319f5ad4b85b074846bf4fef8a8cf51e7bb \ - --hash=sha256:ba55e40de38a24e2d78d34c2d36d6e864f93e0d79d0b6ce915e4335aa81d01b1 \ - --hash=sha256:be3ab1071662f6065899fe08428e45c16aa36e28bc42921c4901a191fda6ee42 \ - --hash=sha256:d75fc8cd0ba23f97bae88a6ec04e9e5351ff3c6ad06f38fe32ba50cbd0d11946 \ - --hash=sha256:e51c42750b7585cee7892c2614be0d14107fad9581d1738d954a262556dd1aab \ - --hash=sha256:ea505c97a5c465ab8c3ba75c0805a102ce526695cd6818c6de3b1a38f6f60da1 \ - --hash=sha256:eb3bd3321517916696233b5e0c67fd7d6281f0ef48e66812db35fc963a422a1c \ - --hash=sha256:f70d9c61f9c4ca7d57f3bfe88a5ccf62546ffbadf3681bb1e268d9d2e41c91a7 \ - --hash=sha256:fbe188b878313d01b7718390f31528be4010fed1faa798c5a1d0469c9c48c369 +bcrypt==4.1.3 ; python_version >= "3.8" and python_version < "4.0" \ + --hash=sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64 \ + --hash=sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf \ + --hash=sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05 \ + --hash=sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c \ + --hash=sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15 \ + --hash=sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991 \ + --hash=sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623 \ + --hash=sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834 \ + --hash=sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08 \ + --hash=sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a \ + --hash=sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74 \ + --hash=sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455 \ + --hash=sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3 \ + --hash=sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73 \ + --hash=sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611 \ + --hash=sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2 \ + --hash=sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d \ + --hash=sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286 \ + --hash=sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978 \ + --hash=sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d \ + --hash=sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc \ + --hash=sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6 \ + --hash=sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed \ + --hash=sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650 \ + --hash=sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84 \ + --hash=sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1 \ + --hash=sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a cffi==1.16.0 ; python_version >= "3.8" and python_version < "4.0" \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ @@ -79,39 +79,39 @@ cffi==1.16.0 ; python_version >= "3.8" and python_version < "4.0" \ --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 -cryptography==42.0.5 ; python_version >= "3.8" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.6 ; python_version >= "3.8" and python_version < "4.0" \ + --hash=sha256:00c0faa5b021457848d031ecff041262211cc1e2bce5f6e6e6c8108018f6b44a \ + --hash=sha256:073104df012fc815eed976cd7d0a386c8725d0d0947cf9c37f6c36a6c20feb1b \ + --hash=sha256:076c92b08dd1ab88108bc84545187e10d3693a9299c593f98c4ea195a0b0ead7 \ + --hash=sha256:089aeb297ff89615934b22c7631448598495ffd775b7d540a55cfee35a677bf4 \ + --hash=sha256:3b750279f3e7715df6f68050707a0cee7cbe81ba2eeb2f21d081bd205885ffed \ + --hash=sha256:43e521f21c2458038d72e8cdfd4d4d9f1d00906a7b6636c4272e35f650d1699b \ + --hash=sha256:4bdb39ecbf05626e4bfa1efd773bb10346af297af14fb3f4c7cb91a1d2f34a46 \ + --hash=sha256:5967e3632f42b0c0f9dc2c9da88c79eabdda317860b246d1fbbde4a8bbbc3b44 \ + --hash=sha256:65d529c31bd65d54ce6b926a01e1b66eacf770b7e87c0622516a840e400ec732 \ + --hash=sha256:6981acac509cc9415344cb5bfea8130096ea6ebcc917e75503143a1e9e829160 \ + --hash=sha256:81dbe47e28b703bc4711ac74a64ef8b758a0cf056ce81d08e39116ab4bc126fa \ + --hash=sha256:8b90c57b3cd6128e0863b894ce77bd36fcb5f430bf2377bc3678c2f56e232316 \ + --hash=sha256:9184aff0856261ecb566a3eb26a05dfe13a292c85ce5c59b04e4aa09e5814187 \ + --hash=sha256:945a43ebf036dd4b43ebfbbd6b0f2db29ad3d39df824fb77476ca5777a9dde33 \ + --hash=sha256:97eeacae9aa526ddafe68b9202a535f581e21d78f16688a84c8dcc063618e121 \ + --hash=sha256:9f1a3bc2747166b0643b00e0b56cd9b661afc9d5ff963acaac7a9c7b2b1ef638 \ + --hash=sha256:9ff75b88a4d273c06d968ad535e6cb6a039dd32db54fe36f05ed62ac3ef64a44 \ + --hash=sha256:aeb6f56b004e898df5530fa873e598ec78eb338ba35f6fa1449970800b1d97c2 \ + --hash=sha256:b16b90605c62bcb3aa7755d62cf5e746828cfc3f965a65211849e00c46f8348d \ + --hash=sha256:b99831397fdc6e6e0aa088b060c278c6e635d25c0d4d14bdf045bf81792fda0a \ + --hash=sha256:bc954251edcd8a952eeaec8ae989fec7fe48109ab343138d537b7ea5bb41071a \ + --hash=sha256:c05230d8aaaa6b8ab3ab41394dc06eb3d916131df1c9dcb4c94e8f041f704b74 \ + --hash=sha256:d16a310c770cc49908c500c2ceb011f2840674101a587d39fa3ea828915b7e83 \ + --hash=sha256:d93080d2b01b292e7ee4d247bf93ed802b0100f5baa3fa5fd6d374716fa480d4 \ + --hash=sha256:e1f5f15c5ddadf6ee4d1d624a2ae940f14bd74536230b0056ccb28bb6248e42a \ + --hash=sha256:e3442601d276bd9e961d618b799761b4e5d892f938e8a4fe1efbe2752be90455 \ + --hash=sha256:e85f433230add2aa26b66d018e21134000067d210c9c68ef7544ba65fc52e3eb \ + --hash=sha256:eecca86813c6a923cabff284b82ff4d73d9e91241dc176250192c3a9b9902a54 \ + --hash=sha256:f1e933b238978ccfa77b1fee0a297b3c04983f4cb84ae1c33b0ea4ae08266cc9 \ + --hash=sha256:f4cece02478d73dacd52be57a521d168af64ae03d2a567c0c4eb6f189c3b9d79 \ + --hash=sha256:f567a82b7c2b99257cca2a1c902c1b129787278ff67148f188784245c7ed5495 \ + --hash=sha256:f987a244dfb0333fbd74a691c36000a2569eaf7c7cc2ac838f85f59f0588ddc9 paramiko==3.4.0 ; python_version >= "3.8" and python_version < "4.0" \ --hash=sha256:43f0b51115a896f9c00f59618023484cb3a14b98bbceab43394a39c6739b7ee7 \ --hash=sha256:aac08f26a31dc4dffd92821527d1682d99d52f9ef6851968114a8728f3c274d3 diff --git a/packages/dart/sshnoports/bundles/universal.sh b/packages/dart/sshnoports/bundles/universal.sh index f1b86089c..8bf8b9e31 100755 --- a/packages/dart/sshnoports/bundles/universal.sh +++ b/packages/dart/sshnoports/bundles/universal.sh @@ -76,6 +76,14 @@ is_systemd_available() { [ -d /run/systemd/system ] } +check_cmd() { + set +e + command -v "$1" > /dev/null 2>&1 + exitcode=$? + set -e + return $exitcode +} + sedi() { if is_darwin; then sed -i '' "$@" @@ -337,28 +345,42 @@ Environment: EOL } +downloader() { + if check_cmd curl; then + curl -sSfL "$1" -o "$2" + elif check_cmd wget; then + wget "$1" -q -O "$2" + else + >&2 echo + >&2 echo "Couldn't find curl or wget to download package" + >&2 echo "Please install one of them" + >&2 echo "Also how did you download this script???" + >&2 echo + exit 1 + fi +} + get_download_url() { unset download_urls - download_urls=$( - curl -fsSL "https://api.github.com/repos/atsign-foundation/noports/releases/$(norm_version $sshnp_version)" | - grep browser_download_url | - cut -d\" -f4 - ) + release_prefix="https://api.github.com/repos/atsign-foundation/noports/releases/" + release_info=$(downloader "$release_prefix$(norm_version $sshnp_version)" - ) + exitcode=$? + if [ $exitcode != 0 ]; then exit $exitcode; fi + download_urls=$(echo "$release_info" | grep browser_download_url | cut -d\" -f4) if [ -z "$download_urls" ]; then - echo "Failed to get download url for sshnoports" + >&2 echo "Failed to get download url for sshnoports" exit 1 fi - echo "$download_urls" | - grep "$platform_name" | grep "$system_arch" | - cut -d\" -f4 + echo "$download_urls" | grep "$platform_name" | + grep "$system_arch" | cut -d\" -f4 } download_archive() { read -r download_url echo "Downloading archive from $download_url" - curl -sL "$download_url" -o "$archive_path" + downloader "$download_url" "$archive_path" if [ ! -f "$archive_path" ]; then echo "Failed to download archive" exit 1 @@ -368,9 +390,19 @@ download_archive() { unpack_archive() { case "$archive_ext" in zip) + if ! check_cmd unzip; then + >&2 echo "ERROR: unzip not found" + >&2 echo "Please install unzip and make it available on the PATH" + exit 1 + fi unzip -qo "$archive_path" -d "$extract_path" ;; tgz | tar.gz) + if ! check_cmd tar; then + >&2 echo "ERROR: tar not available" + >&2 echo "Please install tar and make it available on the PATH" + exit 1 + fi mkdir -p "$extract_path" tar -zxf "$archive_path" -C "$extract_path" ;; @@ -653,17 +685,17 @@ device() { if ! $no_sudo && is_systemd_available; then suggest_sudo fi - if command -v tmux >/dev/null 2>&1; then + if check_cmd tmux; then device_install_type="tmux" else - if ! command -v cron >/dev/null 2>&1; then - echo "ERROR: crontab not available" - echo "Please install cron and make it available on the PATH" + if ! check_cmd cron; then + >&2 echo "ERROR: crontab not available" + >&2 echo "Please install cron and make it available on the PATH" exit 1 fi - if ! command -v nohup >/dev/null 2>&1; then - echo "ERROR: nohup not available" - echo "Please install nohup and make it available on the PATH" + if ! check_cmd nohup; then + >&2 echo "ERROR: nohup not available" + >&2 echo "Please install nohup and make it available on the PATH" exit 1 fi device_install_type="headless" diff --git a/packages/dart/sshnoports/lib/src/version.dart b/packages/dart/sshnoports/lib/src/version.dart index d603e0da8..4a0591bf6 100644 --- a/packages/dart/sshnoports/lib/src/version.dart +++ b/packages/dart/sshnoports/lib/src/version.dart @@ -1,2 +1,3 @@ // Generated code. Do not modify. const packageVersion = '5.1.0'; + diff --git a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-hdpi/launcher_icon.png index f2356c2c1..8b0e7459c 100644 Binary files a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-hdpi/launcher_icon.png and b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-mdpi/launcher_icon.png index f5e49bd27..bb27a9721 100644 Binary files a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-mdpi/launcher_icon.png and b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png index b50c3932e..05268656b 100644 Binary files a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png and b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png index 89511a7e2..b0e2eda17 100644 Binary files a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png and b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png index eddc952a1..254cac6f6 100644 Binary files a/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png and b/packages/dart/sshnp_flutter/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFont-Regular.ttf b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFont-Regular.ttf new file mode 100644 index 000000000..0c3ba4499 Binary files /dev/null and b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFont-Regular.ttf differ diff --git a/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontMono-Regular.ttf b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontMono-Regular.ttf new file mode 100644 index 000000000..e3d6996a8 Binary files /dev/null and b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontMono-Regular.ttf differ diff --git a/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontPropo-Regular.ttf b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontPropo-Regular.ttf new file mode 100644 index 000000000..e2874322c Binary files /dev/null and b/packages/dart/sshnp_flutter/assets/fonts/0xProtoNerdFontPropo-Regular.ttf differ diff --git a/packages/dart/sshnp_flutter/assets/fonts/GeistMonoNerdFont-Regular.otf b/packages/dart/sshnp_flutter/assets/fonts/GeistMonoNerdFont-Regular.otf new file mode 100644 index 000000000..b8567a032 Binary files /dev/null and b/packages/dart/sshnp_flutter/assets/fonts/GeistMonoNerdFont-Regular.otf differ diff --git a/packages/dart/sshnp_flutter/assets/fonts/IosevkaTermNerdFontPropo-Regular.ttf b/packages/dart/sshnp_flutter/assets/fonts/IosevkaTermNerdFontPropo-Regular.ttf new file mode 100644 index 000000000..e2c998c0d Binary files /dev/null and b/packages/dart/sshnp_flutter/assets/fonts/IosevkaTermNerdFontPropo-Regular.ttf differ diff --git a/packages/dart/sshnp_flutter/assets/images/app_logo.png b/packages/dart/sshnp_flutter/assets/images/app_logo.png index 963292e55..d28ae1731 100644 Binary files a/packages/dart/sshnp_flutter/assets/images/app_logo.png and b/packages/dart/sshnp_flutter/assets/images/app_logo.png differ diff --git a/packages/dart/sshnp_flutter/assets/images/app_logo.svg b/packages/dart/sshnp_flutter/assets/images/app_logo.svg index f65cf30ef..39263d07e 100644 --- a/packages/dart/sshnp_flutter/assets/images/app_logo.svg +++ b/packages/dart/sshnp_flutter/assets/images/app_logo.svg @@ -1,5 +1,5 @@ - - + + diff --git a/packages/dart/sshnp_flutter/assets/images/getting_started_empty_state.svg b/packages/dart/sshnp_flutter/assets/images/getting_started_empty_state.svg new file mode 100644 index 000000000..704100973 --- /dev/null +++ b/packages/dart/sshnp_flutter/assets/images/getting_started_empty_state.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/dart/sshnp_flutter/assets/images/logo.svg b/packages/dart/sshnp_flutter/assets/images/logo.svg index eff570ee6..1ce7e2656 100644 --- a/packages/dart/sshnp_flutter/assets/images/logo.svg +++ b/packages/dart/sshnp_flutter/assets/images/logo.svg @@ -1,4 +1,13 @@ - - - + + + + + + + + + + + + diff --git a/packages/dart/sshnp_flutter/assets/images/noports_light.svg b/packages/dart/sshnp_flutter/assets/images/noports_light.svg index 58b59f921..d6a85f3bf 100644 --- a/packages/dart/sshnp_flutter/assets/images/noports_light.svg +++ b/packages/dart/sshnp_flutter/assets/images/noports_light.svg @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/packages/dart/sshnp_flutter/assets/images/onboarding_bg.png b/packages/dart/sshnp_flutter/assets/images/onboarding_bg.png index 89249ce97..ab9d81f51 100644 Binary files a/packages/dart/sshnp_flutter/assets/images/onboarding_bg.png and b/packages/dart/sshnp_flutter/assets/images/onboarding_bg.png differ diff --git a/packages/dart/sshnp_flutter/ios/Podfile.lock b/packages/dart/sshnp_flutter/ios/Podfile.lock index aa4ca6bc9..06dc75ca9 100644 --- a/packages/dart/sshnp_flutter/ios/Podfile.lock +++ b/packages/dart/sshnp_flutter/ios/Podfile.lock @@ -56,7 +56,7 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - permission_handler_apple (9.1.1): + - permission_handler_apple (9.3.0): - Flutter - qr_code_scanner (0.2.0): - Flutter @@ -150,21 +150,21 @@ SPEC CHECKSUMS: device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: ce3938a0df3cc1ef404671531facef740d03f920 + file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de file_selector_ios: b6a6c6667913d571590169ef946afbafe3b52688 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_keychain: 01aabf894ffe8b01adfda1d9df21c210c1b4b452 MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c - permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + permission_handler_apple: 036b856153a2b1f61f21030ff725f3e6fece2b78 qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 - webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36 + webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index e825c14d7..0c324edad 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index d47846999..1a56d8be7 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 6d8fb6d0d..bcc5a8ba2 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index beb451b81..7a10f28bc 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 26451a7ad..15f8c22a1 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 7d554b7e4..cf28c579d 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 444010e0a..68d889f42 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 6d8fb6d0d..bcc5a8ba2 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 4f438e63d..5df71f728 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 26ab61d7a..f6981be49 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png index 94de1cca1..aa43ccefd 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png index 160ac6022..4442f8181 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png index b917dcbae..bf9fe4e40 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png index bbbc809d6..03f101da7 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 26ab61d7a..f6981be49 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index e7974a6e1..4a60708ed 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png index ed449cb92..92f22a018 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png index 542b6ebfe..32cbbc19c 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index b0568f392..d06a21bcb 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index b46220097..19e53bd8c 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 2b1ff1cd4..22cca0033 100644 Binary files a/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/packages/dart/sshnp_flutter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/packages/dart/sshnp_flutter/lib/l10n/app_en.arb b/packages/dart/sshnp_flutter/lib/l10n/app_en.arb index 97004ce25..7e34395eb 100644 --- a/packages/dart/sshnp_flutter/lib/l10n/app_en.arb +++ b/packages/dart/sshnp_flutter/lib/l10n/app_en.arb @@ -5,7 +5,7 @@ "addKey" : "Add Key", "addNewConnection" : "Add New Connection", "addNewConnectionDescription" : "To create a new connection as fast as possible, only fill in required fields, the rest will auto populate by default. You can always change your configurations later.", - "advancedConfiguration": "Advanced \nConfiguration", + "advancedConfiguration": "Advanced Configuration", "atKeysFilePath" : "atKeys File", "authenticateClientToRvd" : "Authenticate Client to Socket Rendezvous", "authenticateClientToRvdTooltip" : "When true, client will authenticate itself to rvd", @@ -19,7 +19,7 @@ "closeButton" : "Close", "commands": "Commands", "connect" : "Connect", - "connectionConfiguration" : "Connection\nConfiguration", + "connectionConfiguration" : "Connection Configuration", "contactUs" : "Contact Us", "copiedToClipboard": "Copied to Clipboard", "corruptedPrivateKey" : "Status: Private Key is corrupted", @@ -43,6 +43,9 @@ "failed": "Failed", "faq" : "FAQ", "from" : "From", + "getStartedTitle" : "Get Started!", + "getStartedSubtitle" : "Create your first connection", + "getStartedNoConnections" : "You currently have no connections", "homeDirectory" : "Home Directory", "homeDirectoryHint" : "The home directory on this host", "host" : "SR Address (atSign) *", @@ -113,7 +116,7 @@ "support" : "Support", "supportDescription" : "Our team of experts is here to help! Select your preferred method below", "sourcePort" : "Source Port", - "socketRendezvousConfiguration" : "Socket Rendezvous\nConfiguration", + "socketRendezvousConfiguration" : "Socket Rendezvous Configuration", "srvdAtsign" : "SR Address (atSign)", "srvdAtsignTooltip" : "atSign of the socket rendezvous", "sshAlgorithm" : "SSH Algorithm", diff --git a/packages/dart/sshnp_flutter/lib/main.dart b/packages/dart/sshnp_flutter/lib/main.dart index 0699cee80..6de31462d 100644 --- a/packages/dart/sshnp_flutter/lib/main.dart +++ b/packages/dart/sshnp_flutter/lib/main.dart @@ -31,5 +31,6 @@ Future main() async { await AuthenticationRepository().checkKeyChainFirstRun(); PlatformUtility platformUtility = PlatformUtility.current(); await platformUtility.configurePlatform(); + runApp(ProviderScope(child: platformUtility.app)); } diff --git a/packages/dart/sshnp_flutter/lib/src/controllers/terminal_session_controller.dart b/packages/dart/sshnp_flutter/lib/src/controllers/terminal_session_controller.dart index aa9307dda..6faa8ca3e 100644 --- a/packages/dart/sshnp_flutter/lib/src/controllers/terminal_session_controller.dart +++ b/packages/dart/sshnp_flutter/lib/src/controllers/terminal_session_controller.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:developer'; -import 'package:dartssh2/dartssh2.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:noports_core/sshnp_foundation.dart'; @@ -148,16 +148,23 @@ class TerminalSessionFamilyController extends FamilyNotifier _closeSession() async { if (state.shell != null && state.shell is SSHSessionAsSshnpRemoteProcess) { - (state.shell as SSHSessionAsSshnpRemoteProcess).sshSession.kill(SSHSignal.KILL); + try { + await (state.shell as SSHSessionAsSshnpRemoteProcess).sshSession.stdin.close().catchError((e) { + log('Failed to close stdin : $e'); + }); + (state.shell as SSHSessionAsSshnpRemoteProcess).sshSession.close(); + } catch (e) { + log('Failed to close SSH Session : $e'); + } } state.isRunning = false; } void dispose() { /// 1. Set the session to disposed - if (state.isRunning) _killProcess(); + if (state.isRunning) _closeSession(); // 2. Find a new session to set as the active one final terminalList = ref.read(terminalSessionListController); diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/home_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/home_screen.dart index e7fff2726..dc762d605 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/home_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/home_screen.dart @@ -27,8 +27,8 @@ class _HomeScreenState extends ConsumerState { @override Widget build(BuildContext context) { return const ResponsiveWidget( - mobileScreen: HomeScreenMobile(), - tabletScreen: HomeScreenDesktop(), + smallScreen: HomeScreenMobile(), + mediumScreen: HomeScreenDesktop(), largeScreen: HomeScreenDesktop(), ); } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/onboarding_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/onboarding_screen.dart index 35478e820..36689eb6b 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/onboarding_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/onboarding_screen.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:at_app_flutter/at_app_flutter.dart'; import 'package:at_contacts_flutter/utils/init_contacts_service.dart'; import 'package:at_onboarding_flutter/at_onboarding_flutter.dart'; @@ -22,7 +24,12 @@ class OnboardingScreen extends StatefulWidget { class _OnboardingScreenState extends State { @override Widget build(BuildContext context) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; + final headlineLarge = Theme.of(context).textTheme.headlineLarge!; + log(bodySmall.fontSize!.toFont.toString()); + // * load the AtClientPreference in the background Future futurePreference = loadAtClientPreference(); return Scaffold( @@ -39,133 +46,132 @@ class _OnboardingScreenState extends State { fit: BoxFit.cover, ), ), - Positioned( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: SvgPicture.asset( - 'assets/images/onboarding_bg_overlay.svg', - fit: BoxFit.cover, - ), - ), Center( child: Builder( builder: (context) => SizedBox( - width: 367, - height: 255, + width: MediaQuery.of(context).size.width * 0.55, + // height: MediaQuery.of(context).size.height * 0.55, child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Sizes.p12), ), - child: Padding( - padding: - const EdgeInsets.only(top: Sizes.p30, bottom: Sizes.p10, left: Sizes.p30, right: Sizes.p30), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset( - 'assets/images/app_logo.svg', - fit: BoxFit.cover, - height: Sizes.p38, - ), - Text( - strings.welcomeTo, - style: Theme.of(context).textTheme.headlineLarge!.copyWith( + child: Wrap(children: [ + Center( + child: Padding( + padding: + const EdgeInsets.only(top: Sizes.p30, bottom: Sizes.p30, left: Sizes.p30, right: Sizes.p30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + 'assets/images/app_logo.svg', + fit: BoxFit.cover, + height: Sizes.p38, + ), + Text( + strings.welcomeTo, + style: headlineLarge.copyWith( color: Colors.black, fontWeight: FontWeight.w700, - fontSize: 19, + fontSize: headlineLarge.fontSize!.toFont, ), - ), - Text( - strings.sshnpDesktopApp, - style: Theme.of(context).textTheme.headlineLarge!.copyWith( + ), + Text( + strings.sshnpDesktopApp, + style: headlineLarge.copyWith( color: kPrimaryColor, fontWeight: FontWeight.w700, - fontSize: 19, - ), - ), - Text( - strings.welcomeToDescription, - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black), - ), - gapH20, - Center( - child: ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: kPrimaryColor, - backgroundColor: kPrimaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(Sizes.p20), + fontSize: headlineLarge.fontSize!.toFont, ), - padding: const EdgeInsets.symmetric(horizontal: Sizes.p60, vertical: Sizes.p10), ), - onPressed: () async { - AtOnboardingResult onboardingResult = await AtOnboarding.onboard( - context: context, - config: AtOnboardingConfig( - atClientPreference: await futurePreference, - rootEnvironment: AtEnv.rootEnvironment, - domain: AtEnv.rootDomain, - appAPIKey: AtEnv.appApiKey, - theme: AtOnboardingTheme( - primaryColor: kPrimaryColor, + Text( + strings.welcomeToDescription, + style: bodySmall.copyWith(color: Colors.black, fontSize: bodySmall.fontSize!.toFont), + ), + gapH20, + Center( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: kPrimaryColor, + backgroundColor: kPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(Sizes.p20), ), + padding: const EdgeInsets.symmetric(horizontal: Sizes.p60, vertical: Sizes.p10), ), - ); - switch (onboardingResult.status) { - case AtOnboardingResultStatus.success: - await initializeContactsService(rootDomain: AtEnv.rootDomain); - if (context.mounted) { - context.replaceNamed(AppRoute.home.name); - } - await AuthenticationRepository().setFirstRun(true); - - break; - case AtOnboardingResultStatus.error: - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - backgroundColor: Colors.red, - content: Text('An error has occurred'), + onPressed: () async { + AtOnboardingResult onboardingResult = await AtOnboarding.onboard( + context: context, + config: AtOnboardingConfig( + atClientPreference: await futurePreference, + rootEnvironment: AtEnv.rootEnvironment, + domain: AtEnv.rootDomain, + appAPIKey: AtEnv.appApiKey, + theme: AtOnboardingTheme( + primaryColor: kPrimaryColor, ), - ); + ), + ); + switch (onboardingResult.status) { + case AtOnboardingResultStatus.success: + await initializeContactsService(rootDomain: AtEnv.rootDomain); + if (context.mounted) { + context.replaceNamed(AppRoute.home.name); + } + await AuthenticationRepository().setFirstRun(true); + + break; + case AtOnboardingResultStatus.error: + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + backgroundColor: Colors.red, + content: Text('An error has occurred'), + ), + ); + } + break; + case AtOnboardingResultStatus.cancel: + break; } - break; - case AtOnboardingResultStatus.cancel: - break; - } - }, - child: Text( - strings.onboardButtonDescription, - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.white), - textAlign: TextAlign.center, + }, + child: Text( + strings.onboardButtonDescription, + style: bodySmall.copyWith( + color: Colors.white, + fontSize: bodySmall.fontSize!.toFont, + ), + textAlign: TextAlign.center, + ), + ), ), - ), - ), - gapH10, - Center( - child: TextButton( - onPressed: () async { - await AtOnboarding.reset( - context: context, - config: AtOnboardingConfig( - atClientPreference: await futurePreference, - rootEnvironment: AtEnv.rootEnvironment, - domain: AtEnv.rootDomain, - appAPIKey: AtEnv.appApiKey, + gapH10, + Center( + child: TextButton( + onPressed: () async { + await AtOnboarding.reset( + context: context, + config: AtOnboardingConfig( + atClientPreference: await futurePreference, + rootEnvironment: AtEnv.rootEnvironment, + domain: AtEnv.rootDomain, + appAPIKey: AtEnv.appApiKey, + ), + ); + }, + child: Text( + 'Reset', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Colors.black, fontWeight: FontWeight.w700), ), - ); - }, - child: Text( - 'Reset', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black, fontWeight: FontWeight.w700), - ), - )) - ], + )) + ], + ), + ), ), - ), + ]), ), ), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/profile_editor_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/profile_editor_screen.dart index 18367a0e6..aa111e76f 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/profile_editor_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/profile_editor_screen.dart @@ -16,8 +16,8 @@ class _ProfileEditorScreenState extends State { @override Widget build(BuildContext context) { return const ResponsiveWidget( - mobileScreen: ProfileEditorScreenMobileView(), + smallScreen: ProfileEditorScreenMobileView(), largeScreen: ProfileEditorScreenDesktopView(), - tabletScreen: ProfileEditorScreenDesktopView()); + mediumScreen: ProfileEditorScreenDesktopView()); } } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/settings_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/settings_screen.dart index 1b841aed3..bc5a1c858 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/settings_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/settings_screen.dart @@ -11,6 +11,6 @@ class SettingsScreen extends StatelessWidget { @override Widget build(BuildContext context) { return const ResponsiveWidget( - mobileScreen: SettingsMobileView(), largeScreen: SettingsDesktopView(), tabletScreen: SettingsDesktopView()); + smallScreen: SettingsMobileView(), largeScreen: SettingsDesktopView(), mediumScreen: SettingsDesktopView()); } } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/support_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/support_screen.dart index 211cf969d..589160fdb 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/support_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/support_screen.dart @@ -11,9 +11,9 @@ class SupportScreen extends StatelessWidget { @override Widget build(BuildContext context) { return const ResponsiveWidget( - mobileScreen: SupportScreenMobileView(), + smallScreen: SupportScreenMobileView(), largeScreen: SupportScreenDesktopView(), - tabletScreen: SupportScreenDesktopView(), + mediumScreen: SupportScreenDesktopView(), ); } } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/screens/terminal_screen.dart b/packages/dart/sshnp_flutter/lib/src/presentation/screens/terminal_screen.dart index 3016eb226..87465709c 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/screens/terminal_screen.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/screens/terminal_screen.dart @@ -11,8 +11,8 @@ class TerminalScreen extends StatelessWidget { @override Widget build(BuildContext context) { return const ResponsiveWidget( - mobileScreen: TerminalScreenMobileView(), - tabletScreen: TerminalScreenDesktopView(), + smallScreen: TerminalScreenMobileView(), + mediumScreen: TerminalScreenDesktopView(), largeScreen: TerminalScreenDesktopView()); } } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/contact_tile/contact_list_tile.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/contact_tile/contact_list_tile.dart index e9b182793..9d14b9359 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/contact_tile/contact_list_tile.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/contact_tile/contact_list_tile.dart @@ -9,25 +9,34 @@ class ContactListTile extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); final contactRepo = ContactsService.getInstance(); + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; return FutureBuilder( future: contactRepo.getCurrentAtsignContactDetails(), builder: ((context, snapshot) { if (snapshot.hasData) { return SizedBox( - width: Sizes.p320, + width: Sizes.p244.toFont, child: ListTile( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(Sizes.p8), - ), - tileColor: kListTileColor, - leading: CircleAvatar( - backgroundColor: kPrimaryColor, - backgroundImage: snapshot.data!['image'] != null ? MemoryImage(snapshot.data!['image']) : null, - ), - title: Text(snapshot.data?['name'] ?? ''), - subtitle: Text(contactRepo.atClientManager.atClient.getCurrentAtSign() ?? ''), - ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(Sizes.p8.toFont), + ), + tileColor: kListTileColor, + leading: CircleAvatar( + radius: Sizes.p18.toFont, + backgroundColor: kPrimaryColor, + backgroundImage: snapshot.data!['image'] != null ? MemoryImage(snapshot.data!['image']) : null, + ), + title: Text( + snapshot.data?['name'] ?? '', + style: bodyMedium.copyWith(fontSize: bodyMedium.fontSize?.toFont), + ), + subtitle: Text( + contactRepo.atClientManager.atClient.getCurrentAtSign() ?? '', + style: bodySmall.copyWith(fontSize: bodySmall.fontSize?.toFont), + )), ); } else { return const ListTile( diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/custom_list_tile.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/custom_list_tile.dart index e7caf26c1..64d81ab8d 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/custom_list_tile.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/custom_list_tile.dart @@ -8,6 +8,7 @@ import 'package:sshnp_flutter/src/controllers/navigation_controller.dart'; import 'package:sshnp_flutter/src/presentation/screens/onboarding_screen.dart'; import 'package:sshnp_flutter/src/presentation/widgets/utility/custom_snack_bar.dart'; import 'package:sshnp_flutter/src/utility/constants.dart'; +import 'package:sshnp_flutter/src/utility/sizes.dart'; import 'package:url_launcher/url_launcher.dart'; import 'settings_actions/settings_switch_atsign_action.dart'; @@ -82,6 +83,13 @@ class CustomListTile extends StatelessWidget { this.type = CustomListTileType.resetAtsign, this.tileColor = kProfileBackgroundColor, super.key}); + const CustomListTile.feedback( + {this.iconData = Icons.feedback_outlined, + this.title = 'Feedback', + this.subtitle = 'Send us your feedback', + this.type = CustomListTileType.feedback, + this.tileColor = kProfileBackgroundColor, + super.key}); final IconData iconData; final String title; @@ -92,6 +100,9 @@ class CustomListTile extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; Future onTap() async { switch (type) { case CustomListTileType.email: @@ -155,24 +166,44 @@ class CustomListTile extends StatelessWidget { context.goNamed(AppRoute.onboarding.name); } } - break; + + case CustomListTileType.feedback: + final emailUri = Uri( + scheme: 'mailto', + path: 'info@noports.com', + query: 'subject=SSH No Ports Desktop Feedback', + ); + + if (!await launchUrl(emailUri)) { + CustomSnackBar.notification(content: 'No email client available'); + } } } return ListTile( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(Sizes.p10), + ), leading: FilledButton( - style: FilledButton.styleFrom(backgroundColor: kIconColorBackground), + style: FilledButton.styleFrom( + backgroundColor: kIconColorBackground, + // minimumSize: Size(64.toFont, 100.toFont), + ), onPressed: onTap, child: Icon( iconData, color: kIconColorDark, + // size: Sizes.p24.toFont, ), ), - title: Text(title), + title: Text( + title, + style: bodyMedium.copyWith(fontSize: bodyMedium.fontSize!.toFont), + ), subtitle: Text( subtitle, - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: kTextColorDark), + style: bodySmall.copyWith(color: kTextColorDark, fontSize: bodySmall.fontSize!.toFont), ), onTap: () async { await onTap(); @@ -191,4 +222,5 @@ enum CustomListTileType { switchAtsign, backupYourKey, resetAtsign, + feedback } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_action_callbacks.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_action_callbacks.dart index e8b18a03c..67566919e 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_action_callbacks.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_action_callbacks.dart @@ -18,20 +18,16 @@ class HomeScreenActionCallbacks { if (Platform.isMacOS || Platform.isLinux || Platform.isWindows) { return _importDesktop(ref, context); } - CustomSnackBar.error( - content: 'Unable to import profile:\nUnsupported platform'); + CustomSnackBar.error(content: 'Unable to import profile:\nUnsupported platform'); } - static Future _importDesktop( - WidgetRef ref, BuildContext context) async { + static Future _importDesktop(WidgetRef ref, BuildContext context) async { try { - final XFile? file = - await openFile(acceptedTypeGroups: [dotEnvTypeGroup]); + final XFile? file = await openFile(acceptedTypeGroups: [dotEnvTypeGroup]); if (file == null) return; if (context.mounted) { String initialName = ConfigFileRepository.toProfileName(file.path); - String? profileName = - await _getProfileNameFromUser(context, initialName: initialName); + String? profileName = await _getProfileNameFromUser(context, initialName: initialName); if (profileName == null) return; if (profileName.isEmpty) profileName = initialName; final lines = (await file.readAsString()).split('\n'); @@ -40,19 +36,16 @@ class HomeScreenActionCallbacks { .putConfig(SshnpParams.fromConfigLines(profileName, lines)); } } catch (e) { - CustomSnackBar.error( - content: 'Unable to import profile:\n${e.toString()}'); + CustomSnackBar.error(content: 'Unable to import profile:\n${e.toString()}'); } } - static Future _getProfileNameFromUser(BuildContext context, - {String? initialName}) async { + static Future _getProfileNameFromUser(BuildContext context, {String? initialName}) async { String? profileName; setProfileName(String? p) => profileName = p; await showDialog( context: context, - builder: (_) => - HomeScreenImportDialog(setProfileName, initialName: initialName), + builder: (_) => HomeScreenImportDialog(setProfileName, initialName: initialName), ); return profileName; } @@ -66,7 +59,7 @@ class HomeScreenActionCallbacks { ), ); - if (ResponsiveWidget.isMobileScreen(context)) { + if (ResponsiveWidget.isSmallScreen(context)) { context.goNamed( AppRoute.profileForm.name, ); diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_actions.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_actions.dart index acaf20163..19d0e6150 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_actions.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_actions.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:sshnp_flutter/src/presentation/widgets/home_screen_widgets/home_screen_actions/new_profile_action.dart'; -import 'package:sshnp_flutter/src/utility/sizes.dart'; + +import '../../../../utility/sizes.dart'; class HomeScreenActions extends StatelessWidget { const HomeScreenActions({super.key}); diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/new_profile_action.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/new_profile_action.dart index 0b77f5836..0ab1f3e90 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/new_profile_action.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_actions/new_profile_action.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sshnp_flutter/src/presentation/widgets/home_screen_widgets/home_screen_actions/home_screen_action_callbacks.dart'; +import 'package:sshnp_flutter/src/utility/sizes.dart'; class NewProfileAction extends ConsumerStatefulWidget { const NewProfileAction({super.key}); @@ -12,12 +13,15 @@ class NewProfileAction extends ConsumerStatefulWidget { class _NewProfileActionState extends ConsumerState { @override Widget build(BuildContext context) { + SizeConfig().init(context); return FilledButton( onPressed: () { // Change value to update to trigger the update functionality on the new connection form. HomeScreenActionCallbacks.newProfileAction(ref, context); }, - child: const Icon(Icons.add_circle_outline), + child: const Icon( + Icons.add_circle_outline, + ), ); } } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_core.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_core.dart index 74d1b63c1..58c95f6bd 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_core.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_core.dart @@ -45,7 +45,11 @@ class _HomeScreenCoreState extends ConsumerState { @override Widget build(BuildContext context) { final strings = AppLocalizations.of(context)!; + final bodyLarge = Theme.of(context).textTheme.bodyLarge!; + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; final profileNames = ref.watch(configListController); + + SizeConfig().init(context); return profileNames.when( loading: () => const Center( child: CircularProgressIndicator(), @@ -55,49 +59,89 @@ class _HomeScreenCoreState extends ConsumerState { }, data: (profiles) { if (profiles.isEmpty) { - return Center( + final emptyStateTextColor = bodyMedium.copyWith( + color: Colors.white30, + fontSize: bodyMedium.fontSize!.toFont, + ); + return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ gapH40, - Text( - 'Get Started!', - style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: kHomeScreenGreyText), - ), - gapH16, - GestureDetector( + // TODO: revisite uncommented code for pro version + // Text( + // 'Get Started!', + // style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: kHomeScreenGreyText), + // ), + // gapH16, + // EmptyStateAltWidget(ref: ref, strings: strings), + ListTile( + title: Text( + strings.getStartedTitle, + style: bodyLarge.copyWith(fontSize: bodyLarge.fontSize!.toFont), + ), + subtitle: Text( + strings.getStartedSubtitle, + style: bodyMedium.copyWith(fontWeight: FontWeight.normal, fontSize: bodyMedium.fontSize!.toFont), + ), + tileColor: kPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: Sizes.p36, + vertical: Sizes.p12, + ), + trailing: Icon( + Icons.add_circle_outline, + size: 24.toFont, + ), onTap: () => HomeScreenActionCallbacks.newProfileAction(ref, context), - child: Stack( - children: [ - // const NewProfileAction(), - SvgPicture.asset( - 'assets/images/empty_profile_bg.svg', - width: MediaQuery.of(context).size.width * 0.8, - height: MediaQuery.of(context).size.height * 0.68, - fit: BoxFit.cover, - ), - Positioned( - top: 60, - left: 88, - right: 88, - child: Text( - strings.createConnectionProfile, - style: Theme.of(context).textTheme.bodyLarge!.copyWith(fontSize: 18), - textAlign: TextAlign.center, - ), + ), + gapH24, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + strings.profileName('other'), + style: emptyStateTextColor, + ), + Padding( + padding: const EdgeInsets.only(right: Sizes.p36), + child: Text( + strings.commands, + style: emptyStateTextColor, ), - Positioned( - top: 100, - left: 88, - right: 88, - child: Text( - strings.createConnectionProfileDesc, - textAlign: TextAlign.center, + ), + ], + ), + const Divider(), + gapH20, + Container( + width: double.infinity, + height: MediaQuery.of(context).size.height * 0.4, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(Sizes.p10), + color: kProfileBackgroundColor, + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + strings.getStartedNoConnections, + style: emptyStateTextColor, ), - ), - ], + gapH20, + SvgPicture.asset( + 'assets/images/getting_started_empty_state.svg', + width: MediaQuery.of(context).size.width * 0.15, + height: MediaQuery.of(context).size.height * 0.15, + ) + ], + ), ), - ), + ) ], ), ); @@ -109,10 +153,16 @@ class _HomeScreenCoreState extends ConsumerState { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(strings.profileName('other')), + Text(strings.profileName('other'), + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), Padding( padding: const EdgeInsets.only(right: Sizes.p36), - child: Text(strings.commands), + child: Text(strings.commands, + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), ), ], ), @@ -129,6 +179,54 @@ class _HomeScreenCoreState extends ConsumerState { } } +class EmptyStateAltWidget extends StatelessWidget { + const EmptyStateAltWidget({ + super.key, + required this.ref, + required this.strings, + }); + + final WidgetRef ref; + final AppLocalizations strings; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => HomeScreenActionCallbacks.newProfileAction(ref, context), + child: Stack( + children: [ + // const NewProfileAction(), + SvgPicture.asset( + 'assets/images/empty_profile_bg.svg', + width: MediaQuery.of(context).size.width * 0.8, + height: MediaQuery.of(context).size.height * 0.68, + fit: BoxFit.cover, + ), + Positioned( + top: 60, + left: 88, + right: 88, + child: Text( + strings.createConnectionProfile, + style: Theme.of(context).textTheme.bodyLarge!.copyWith(fontSize: 18), + textAlign: TextAlign.center, + ), + ), + Positioned( + top: 100, + left: 88, + right: 88, + child: Text( + strings.createConnectionProfileDesc, + textAlign: TextAlign.center, + ), + ), + ], + ), + ); + } +} + class ProfileExpansionPanel extends StatefulWidget { const ProfileExpansionPanel({required this.items, super.key}); diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_desktop.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_desktop.dart index 46b5be59b..664d53d93 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_desktop.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/home_screen_widgets/home_screen_desktop.dart @@ -1,19 +1,26 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../../controllers/config_controller.dart'; import '../../../utility/sizes.dart'; import '../navigation/app_navigation_rail.dart'; import 'home_screen_actions/home_screen_actions.dart'; import 'home_screen_core.dart'; -class HomeScreenDesktop extends StatelessWidget { +class HomeScreenDesktop extends ConsumerWidget { const HomeScreenDesktop({ super.key, }); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; + final headlineLarge = Theme.of(context).textTheme.headlineLarge!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; + final profileNames = ref.watch(configListController); + return Scaffold( body: Row( mainAxisSize: MainAxisSize.min, @@ -21,7 +28,7 @@ class HomeScreenDesktop extends StatelessWidget { const AppNavigationRail(), Expanded( child: Padding( - padding: const EdgeInsets.only(left: Sizes.p36, right: Sizes.p36, top: Sizes.p21), + padding: const EdgeInsets.only(left: Sizes.p36, right: Sizes.p36, top: Sizes.p21, bottom: Sizes.p21), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -33,15 +40,15 @@ class HomeScreenDesktop extends StatelessWidget { children: [ Text( strings.connectionProfiles, - style: Theme.of(context).textTheme.headlineLarge, + style: headlineLarge.copyWith(fontSize: headlineLarge.fontSize!.toFont), ), Text( strings.currentConnectionsDescription, - style: Theme.of(context).textTheme.bodySmall, + style: bodySmall.copyWith(fontSize: bodySmall.fontSize!.toFont), ), ], ), - const HomeScreenActions(), + profileNames.value?.isNotEmpty == true ? const HomeScreenActions() : gapH8 ], ), gapH8, diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/navigation/app_navigation_rail.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/navigation/app_navigation_rail.dart index fa290d802..383bee212 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/navigation/app_navigation_rail.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/navigation/app_navigation_rail.dart @@ -45,7 +45,10 @@ class AppNavigationRail extends ConsumerWidget { child: NavigationRail( groupAlignment: -1, minWidth: 97, - leading: SvgPicture.asset('assets/images/logo.svg'), + leading: SvgPicture.asset( + 'assets/images/logo.svg', + height: Sizes.p36, + ), destinations: controller.routes.map((AppRoute route) { if (route == AppRoute.blank) { return NavigationRailDestination( diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_action_button.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_action_button.dart index 9f69e8396..8afd0a07d 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_action_button.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_action_button.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import '../../../../utility/sizes.dart'; + class ProfileActionButton extends StatelessWidget { final void Function() onPressed; final Widget icon; @@ -11,7 +13,9 @@ class ProfileActionButton extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); return IconButton( + iconSize: 24.toFont, onPressed: onPressed, icon: icon, ); diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_menu_button.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_menu_button.dart index a8940f15b..ca2e56f6f 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_menu_button.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_menu_button.dart @@ -15,8 +15,10 @@ class ProfileMenuButton extends ConsumerStatefulWidget { class _ProfileMenuBarState extends ConsumerState { @override Widget build(BuildContext context) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; return PopupMenuButton( + iconSize: 24.toFont, itemBuilder: (context) => [ // PopupMenuItem( // child: ProfileMenuItem( @@ -25,11 +27,21 @@ class _ProfileMenuBarState extends ConsumerState { // ProfileActionCallbacks.export(ref, context, widget.profileName), // ), PopupMenuItem( - child: ProfileMenuItem(const Icon(Icons.edit), strings.edit), + child: ProfileMenuItem( + Icon( + Icons.edit, + size: 20.toFont, + ), + strings.edit), onTap: () => ProfileActionCallbacks.edit(ref, context, widget.profileName), ), PopupMenuItem( - child: const ProfileMenuItem(Icon(Icons.delete_forever), 'Delete'), + child: ProfileMenuItem( + Icon( + Icons.delete_forever, + size: 20.toFont, + ), + 'Delete'), onTap: () => ProfileActionCallbacks.delete(context, widget.profileName), ), ], @@ -45,11 +57,16 @@ class ProfileMenuItem extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; return Row( children: [ icon, gapW12, - Text(text), + Text(text, + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), ], ); } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar.dart index 4704c4023..f0f6ceb44 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -23,31 +21,42 @@ class _ProfileBarState extends ConsumerState { @override Widget build(BuildContext context) { final strings = AppLocalizations.of(context)!; + SizeConfig().init(context); final controller = ref.watch(configFamilyController(widget.profileName)); - log('profileName: ${widget.profileName}'); + + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + return controller.when( loading: () => const LinearProgressIndicator(), error: (error, stackTrace) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(widget.profileName), + Text(widget.profileName, + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), gapW8, Expanded(child: Container()), - Text(strings.corruptedProfile), + Text(strings.corruptedProfile, + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), ProfileDeleteAction(widget.profileName), ], ); }, data: (profile) { - log('profile from profile_bar: ${profile.profileName}'); return Card( color: kProfileBarColor, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ gapW16, - Text(widget.profileName), + Text(widget.profileName, + style: bodyMedium.copyWith( + fontSize: bodyMedium.fontSize!.toFont, + )), gapW8, const Expanded(child: gap0), const ProfileBarStats(), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar_actions.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar_actions.dart index eac90aacc..9b115a42e 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar_actions.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_bar/profile_bar_actions.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:noports_core/sshnp.dart'; import 'package:sshnp_flutter/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_actions.dart'; +import 'package:sshnp_flutter/src/utility/sizes.dart'; class ProfileBarActions extends StatelessWidget { final SshnpParams params; @@ -12,6 +13,7 @@ class ProfileBarActions extends StatelessWidget { children: [ ProfileTerminalAction(params), ProfileMenuButton(params.profileName!), + gapW8, ], ); } diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_editor_screen_desktop_view.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_editor_screen_desktop_view.dart index b1da64c61..a8b24ad34 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_editor_screen_desktop_view.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_editor_screen_desktop_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../../../utility/constants.dart'; import '../../../utility/sizes.dart'; import '../navigation/app_navigation_rail.dart'; import 'profile_form/profile_form_desktop_view.dart'; @@ -12,36 +13,49 @@ class ProfileEditorScreenDesktopView extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; + final headlineLarge = Theme.of(context).textTheme.headlineLarge!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; return Scaffold( body: SafeArea( child: Row( children: [ const AppNavigationRail(), Expanded( - child: Padding( - padding: const EdgeInsets.only( - left: Sizes.p36, - top: Sizes.p21, - right: Sizes.p48, - ), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - strings.addNewConnection, - style: Theme.of(context).textTheme.headlineLarge, + child: Stack( + alignment: AlignmentDirectional.bottomStart, + children: [ + Container( + color: kDarkBarColor, + width: MediaQuery.of(context).size.width, + height: Sizes.p60, ), - gapH10, - const LinearProgressIndicator( - value: 0.5, + Padding( + padding: const EdgeInsets.only( + left: Sizes.p36, + top: Sizes.p21, + right: Sizes.p48, + ), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + strings.addNewConnection, + style: headlineLarge.copyWith(fontSize: headlineLarge.fontSize?.toFont), + ), + gapH10, + const LinearProgressIndicator( + value: 0.5, + ), + gapH10, + Text( + strings.addNewConnectionDescription, + style: bodySmall.copyWith(fontSize: bodySmall.fontSize?.toFont), + ), + gapH24, + const Expanded(child: ProfileFormDesktopView()) + ]), ), - gapH10, - Text( - strings.addNewConnectionDescription, - style: Theme.of(context).textTheme.bodySmall!, - ), - gapH16, - const Expanded(child: ProfileFormDesktopView()) - ]), + ], ), ), ], diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_dropdown_form_field.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_dropdown_form_field.dart index ba5cb4416..bcc58b815 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_dropdown_form_field.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_dropdown_form_field.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:sshnp_flutter/src/utility/constants.dart'; +import 'package:sshnp_flutter/src/utility/sizes.dart'; class CustomDropdownFormField extends StatelessWidget { const CustomDropdownFormField({ @@ -29,31 +30,40 @@ class CustomDropdownFormField extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final bodySmall = Theme.of(context).textTheme.bodySmall!; return SizedBox( - width: width, + width: width.toWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.grey, - ), + style: bodySmall.copyWith( + color: Colors.grey, + fontSize: bodySmall.fontSize?.toFont, + ), ), DropdownButtonFormField( value: initialValue, - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black), + style: bodySmall.copyWith( + color: Colors.black, + fontSize: bodySmall.fontSize?.toFont, + ), selectedItemBuilder: (context) => items .map((e) => Text( e.value.toString(), - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: kPrimaryColor), + style: bodySmall.copyWith( + color: kPrimaryColor, + // fontSize: bodySmall.fontSize?.toFont, + ), )) .toList(), dropdownColor: Colors.white, decoration: InputDecoration( isDense: true, hintText: hintText, - hintStyle: Theme.of(context).textTheme.bodySmall, + hintStyle: bodySmall.copyWith(fontSize: bodySmall.fontSize?.toFont), filled: true, fillColor: kProfileFormFieldColor, border: OutlineInputBorder( @@ -64,6 +74,7 @@ class CustomDropdownFormField extends StatelessWidget { message: tooltip, child: const Icon( Icons.question_mark_outlined, + color: kPrimaryColor, size: 12, ), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_switch_widget.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_switch_widget.dart index c66207732..af4068f14 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_switch_widget.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_switch_widget.dart @@ -19,14 +19,16 @@ class CustomSwitchWidget extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final bodySmall = Theme.of(context).textTheme.bodySmall!; return SizedBox( - width: kFieldDefaultWidth, + width: kFieldDefaultWidth.toWidth, child: Row( children: [ Expanded( child: Text( labelText, - style: Theme.of(context).textTheme.bodySmall, + style: bodySmall.copyWith(fontSize: bodySmall.fontSize?.toFont), )), gapW8, Switch( @@ -38,9 +40,10 @@ class CustomSwitchWidget extends StatelessWidget { gapW8, Tooltip( message: tooltip, - child: const Icon( + child: Icon( Icons.question_mark_outlined, - size: 12, + color: kPrimaryColor, + size: 12.toFont, ), ) ], diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_text_form_field.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_text_form_field.dart index c90b784c4..2b90a0147 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_text_form_field.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/custom_text_form_field.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:sshnp_flutter/src/utility/constants.dart'; +import '../../../../utility/sizes.dart'; + class CustomTextFormField extends StatefulWidget { const CustomTextFormField({ super.key, @@ -44,28 +46,37 @@ class _CustomTextFormFieldState extends State { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final bodySmall = Theme.of(context).textTheme.bodySmall!; return SizedBox( - width: widget.width, + width: widget.width.toWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.labelText, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.grey, - ), + style: bodySmall.copyWith( + color: Colors.grey, + fontSize: bodySmall.fontSize?.toFont, + ), ), TextFormField( initialValue: widget.initialValue, obscureText: widget.isPasswordField && !_isPasswordVisible, decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric( + vertical: 10.toFont, + horizontal: 10.toFont, + ), filled: true, fillColor: kProfileFormFieldColor, border: UnderlineInputBorder( borderRadius: BorderRadius.circular(2), ), hintText: widget.hintText, - hintStyle: Theme.of(context).textTheme.bodySmall, + hintStyle: bodySmall.copyWith( + fontSize: bodySmall.fontSize?.toFont, + ), suffixIcon: widget.isPasswordField ? InkWell( onTap: _setPasswordVisibility, @@ -73,9 +84,10 @@ class _CustomTextFormFieldState extends State { ) : Tooltip( message: widget.toolTip, - child: const Icon( + child: Icon( Icons.question_mark_outlined, - size: 12, + color: kPrimaryColor, + size: 12.toFont, ), ), errorMaxLines: 3, diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/profile_form_desktop_view.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/profile_form_desktop_view.dart index ff1438774..03bb3a5d8 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/profile_form_desktop_view.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/profile_screen_widgets/profile_form/profile_form_desktop_view.dart @@ -79,7 +79,17 @@ class _ProfileFormState extends ConsumerState { @override Widget build(BuildContext context) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; + final spacingHeight = SizedBox( + height: 20.toHeight, + ); + final spacingWidth = SizedBox( + width: 38.toWidth, + ); + final bodyLarge = Theme.of(context).textTheme.bodyLarge!; + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + currentProfile = ref.watch(currentConfigController); final privateKeyManagerListController = ref.watch(atPrivateKeyManagerListController); @@ -114,7 +124,7 @@ class _ProfileFormState extends ConsumerState { }, validator: FormValidator.validateProfileNameField, ), - gapW38, + spacingWidth, CustomTextFormField( hintText: strings.hostHintText, initialValue: oldConfig.host, @@ -128,7 +138,7 @@ class _ProfileFormState extends ConsumerState { ), ], ), - gapH10, + spacingHeight, Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -142,7 +152,7 @@ class _ProfileFormState extends ConsumerState { SshnpPartialParams(device: value!), ); }), - gapW38, + spacingWidth, CustomTextFormField( initialValue: oldConfig.sshnpdAtSign, labelText: strings.sshnpdAtSign, @@ -157,7 +167,8 @@ class _ProfileFormState extends ConsumerState { ], ), gapH20, - Text(strings.connectionConfiguration, style: Theme.of(context).textTheme.bodyLarge), + Text(strings.connectionConfiguration, + style: bodyLarge.copyWith(fontSize: bodyLarge.fontSize?.toFont)), gapH20, ProfileFormCard( largeScreenRightPadding: Sizes.p32, @@ -179,7 +190,7 @@ class _ProfileFormState extends ConsumerState { SshnpPartialParams(remoteUsername: value), ); }), - gapW38, + spacingWidth, CustomTextFormField( initialValue: oldConfig.tunnelUsername, labelText: strings.tunnelUsername, @@ -196,7 +207,7 @@ class _ProfileFormState extends ConsumerState { }), ], ), - gapH10, + spacingHeight, Row( mainAxisSize: MainAxisSize.min, children: [ @@ -210,7 +221,7 @@ class _ProfileFormState extends ConsumerState { ), validator: FormValidator.validateRequiredPortField, ), - gapW38, + spacingWidth, CustomTextFormField( initialValue: oldConfig.localPort.toString(), labelText: strings.localPort, @@ -227,7 +238,10 @@ class _ProfileFormState extends ConsumerState { ], ), gapH20, - Text(strings.sshKeyManagement('yes'), style: Theme.of(context).textTheme.bodyLarge), + Text( + strings.sshKeyManagement('other'), + style: bodyLarge.copyWith(fontSize: bodyLarge.fontSize?.toFont), + ), gapH16, ProfileFormCard(largeScreenRightPadding: Sizes.p32, formFields: [ Row( @@ -305,7 +319,7 @@ class _ProfileFormState extends ConsumerState { ), ]), gapH20, - Text(strings.advancedConfiguration, style: Theme.of(context).textTheme.bodyLarge), + Text(strings.advancedConfiguration, style: bodyLarge.copyWith(fontSize: bodyLarge.fontSize?.toFont)), gapH20, ProfileFormCard( largeScreenRightPadding: Sizes.p32, @@ -323,7 +337,7 @@ class _ProfileFormState extends ConsumerState { SshnpPartialParams(localSshOptions: value?.split(',')), ), ), - gapW38, + spacingWidth, CustomTextFormField( initialValue: oldConfig.rootDomain, labelText: strings.rootDomain, @@ -339,7 +353,8 @@ class _ProfileFormState extends ConsumerState { ], ), gapH20, - Text(strings.socketRendezvousConfiguration, style: Theme.of(context).textTheme.bodyLarge), + Text(strings.socketRendezvousConfiguration, + style: bodyLarge.copyWith(fontSize: bodyLarge.fontSize?.toFont)), gapH20, ProfileFormCard( largeScreenRightPadding: Sizes.p32, @@ -360,7 +375,7 @@ class _ProfileFormState extends ConsumerState { }); }, ), - gapW38, + spacingWidth, CustomSwitchWidget( labelText: strings.authenticateDeviceToRvd, value: newConfig.authenticateDeviceToRvd ?? oldConfig.authenticateDeviceToRvd, @@ -376,7 +391,7 @@ class _ProfileFormState extends ConsumerState { ), ], ), - gapH10, + spacingHeight, Row( mainAxisSize: MainAxisSize.min, children: [ @@ -398,11 +413,13 @@ class _ProfileFormState extends ConsumerState { ], ), gapH30, - SizedBox( - width: kFieldDefaultWidth + Sizes.p233, + Container( + color: kDarkBarColor, + width: MediaQuery.of(context).size.width, + height: Sizes.p60, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, children: [ ElevatedButton( onPressed: () { @@ -410,7 +427,7 @@ class _ProfileFormState extends ConsumerState { }, child: Text( strings.submit, - style: Theme.of(context).textTheme.labelLarge!.copyWith(color: Colors.white), + style: bodyMedium.copyWith(color: Colors.white, fontSize: bodyMedium.fontSize?.toFont), ), ), gapW8, @@ -419,12 +436,15 @@ class _ProfileFormState extends ConsumerState { ref.read(navigationRailController.notifier).setRoute(AppRoute.home); context.pushReplacementNamed(AppRoute.home.name); }, - child: Text(strings.cancel), + child: Text( + strings.cancel, + style: bodyMedium.copyWith(color: kPrimaryColor, fontSize: bodyMedium.fontSize?.toFont), + ), ), ], ), ), - gapH30, + // gapH30, ], ), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_desktop.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_desktop.dart index 713d953db..ac0b5a009 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_desktop.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_desktop.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -16,7 +18,12 @@ class SettingsDesktopView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + SizeConfig().init(context); final strings = AppLocalizations.of(context)!; + final headlineLarge = Theme.of(context).textTheme.headlineLarge!; + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; + final bodySmall = Theme.of(context).textTheme.bodySmall!; + log(headlineLarge.fontSize.toString()); final packageInfoController = ref.read(packageInfo); return Scaffold( body: SafeArea( @@ -28,41 +35,54 @@ class SettingsDesktopView extends ConsumerWidget { const AppNavigationRail(), Expanded( child: Padding( - padding: const EdgeInsets.only(left: Sizes.p36, top: Sizes.p21), + padding: const EdgeInsets.only(left: Sizes.p36, top: Sizes.p21, right: Sizes.p10), child: ListView( children: [ Padding( padding: const EdgeInsets.symmetric(vertical: Sizes.p20), child: Text( strings.settings, - style: Theme.of(context).textTheme.headlineLarge, + style: headlineLarge.copyWith( + fontSize: headlineLarge.fontSize!.toFont, + ), ), ), gapH20, - const Text('Account'), + Text( + 'Account', + style: bodyMedium.copyWith(fontSize: bodyMedium.fontSize!.toFont), + ), gapH16, const Align( alignment: Alignment.centerLeft, child: ContactListTile(), ), gapH36, - Align( - alignment: Alignment.centerLeft, - child: Container( - height: 180, - width: 540, - decoration: BoxDecoration( - color: kProfileBackgroundColor, - borderRadius: BorderRadius.circular(8), - ), - child: GridView.count(childAspectRatio: 202 / 60, crossAxisCount: 2, children: const [ - CustomListTile.keyManagement(), - CustomListTile.backUpYourKey(), - CustomListTile.switchAtsign(), - CustomListTile.resetAtsign(), - ])), + const Row( + children: [ + Flexible(child: CustomListTile.keyManagement()), + gapW12, + Flexible(child: CustomListTile.backUpYourKey()), + ], + ), + gapH20, + const Divider( + color: kProfileFormFieldColor, ), - Text('App Version ${packageInfoController.version} (${packageInfoController.buildNumber})'), + gapH20, + const Row( + children: [ + Flexible(child: CustomListTile.switchAtsign()), + gapW12, + Flexible(child: CustomListTile.resetAtsign()), + ], + ), + gapH40, + Text( + 'App Version ${packageInfoController.version} (${packageInfoController.buildNumber})', + style: bodyMedium.copyWith(fontSize: bodyMedium.fontSize!.toFont - 1.5, color: kTextColorDark), + ), + gapH20, ], ), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_mobile.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_mobile.dart index 9f7032320..1276cb08f 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_mobile.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/settings_screen_widgets/settings_screen_mobile.dart @@ -22,8 +22,7 @@ class SettingsMobileView extends StatelessWidget { style: Theme.of(context).textTheme.headlineLarge, )), body: Padding( - padding: const EdgeInsets.only( - left: Sizes.p36, right: Sizes.p36, top: Sizes.p21), + padding: const EdgeInsets.only(left: Sizes.p36, right: Sizes.p36, top: Sizes.p21), child: ListView( children: [ Text( diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/support_screen_widgets/support_screen_desktop_view.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/support_screen_widgets/support_screen_desktop_view.dart index 9251730b1..97cc2d285 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/support_screen_widgets/support_screen_desktop_view.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/support_screen_widgets/support_screen_desktop_view.dart @@ -13,6 +13,9 @@ class SupportScreenDesktopView extends StatelessWidget { @override Widget build(BuildContext context) { + SizeConfig().init(context); + final headlineLarge = Theme.of(context).textTheme.headlineLarge!; + final bodyMedium = Theme.of(context).textTheme.bodyMedium!; final strings = AppLocalizations.of(context)!; return Scaffold( body: SafeArea( @@ -31,17 +34,23 @@ class SupportScreenDesktopView extends StatelessWidget { padding: const EdgeInsets.only(top: Sizes.p20), child: Text( strings.support, - style: Theme.of(context).textTheme.headlineLarge, + style: headlineLarge.copyWith( + fontSize: headlineLarge.fontSize!.toFont, + ), ), ), Text( strings.supportDescription, - style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: kTextColorDark), + style: bodyMedium.copyWith( + color: kTextColorDark, + fontSize: bodyMedium.fontSize!.toFont, + ), ), gapH30, const Row( children: [ Flexible(child: CustomListTile.discord()), + gapW12, Flexible(child: CustomListTile.email()), ], ), @@ -53,9 +62,22 @@ class SupportScreenDesktopView extends StatelessWidget { const Row( children: [ Flexible(child: CustomListTile.faq()), + gapW12, Flexible(child: CustomListTile.privacyPolicy()), ], - ) + ), + gapH20, + const Divider( + color: kProfileFormFieldColor, + ), + gapH20, + const Row( + children: [ + Flexible(child: CustomListTile.feedback()), + gapW12, + Flexible(child: gap0), + ], + ), ], ), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/terminal_screen_widgets/terminal_screen_desktop_view.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/terminal_screen_widgets/terminal_screen_desktop_view.dart index 195ace652..bf01b1c63 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/terminal_screen_widgets/terminal_screen_desktop_view.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/terminal_screen_widgets/terminal_screen_desktop_view.dart @@ -1,8 +1,10 @@ +import 'dart:async'; import 'dart:developer'; -import 'package:at_onboarding_flutter/at_onboarding_flutter.dart'; +import 'package:at_onboarding_flutter/at_onboarding_flutter.dart' hide Intent; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -27,6 +29,7 @@ class TerminalScreenDesktopView extends ConsumerStatefulWidget { class _TerminalScreenDesktopViewState extends ConsumerState with TickerProviderStateMixin { final terminalController = TerminalController(); + double terminalFontSize = 14.0; @override void initState() { @@ -54,30 +57,46 @@ class _TerminalScreenDesktopViewState extends ConsumerState>(() async { + sshnp = Sshnp.dartPure( + params: SshnpParams.merge( + shellInfo['params'], + SshnpPartialParams( + verbose: kDebugMode, + idleTimeout: 30, + ), ), - ), - atClient: atClient, - identityKeyPair: keyPair, - ); - sshnp.progressStream?.listen((progress) { - sessionController.write(progress); - log(progress); - }); + atClient: atClient, + identityKeyPair: keyPair, + ); + + sshnp!.progressStream?.listen((progress) { + sessionController.write(progress); + log(progress); + }); - final result = await sshnp.run(); + return await sshnp!.run().catchError((e) { + CustomSnackBar.error(content: e.toString()); + throw 'Failed to start session'; + }); + }, (error, stack) { + log('Error: $error', error: error, stackTrace: stack); + sshnp = null; + CustomSnackBar.error(content: 'Failed to initialize SSH No Ports'); + throw error.toString(); + }); + if (sshnp == null || result == null) { + throw 'Failed to initialize SSH No Ports'; + } + log(result.toString()); if (result is SshnpError) { throw result; } if (result is SshnpCommand) { - if (sshnp.canRunShell) { - SshnpRemoteProcess shell = await sshnp.runShell(); + if (sshnp!.canRunShell) { + SshnpRemoteProcess shell = await sshnp!.runShell(); sessionController.startSession( shell, @@ -86,11 +105,12 @@ class _TerminalScreenDesktopViewState extends ConsumerState terminalList, int currentIndex) { + log('next tab called'); + log(tabController.index.toString()); + log(terminalList.length.toString()); + if (tabController.index < (terminalList.length - 1)) { + ref.read(terminalSessionController.notifier).setSession(terminalList[tabController.index + 1]); + tabController.index++; + log('current index is $currentIndex'); + log(tabController.index.toString()); + } + } + + void previousTabCallback(TabController tabController, List terminalList, int currentIndex) { + log('previous tab called'); + log(tabController.index.toString()); + if (tabController.index > 0) { + ref.read(terminalSessionController.notifier).setSession(terminalList[tabController.index - 1]); + + log(tabController.index.toString()); + } + } + + void increaseFontSize() { + log('a tab called'); + setState(() { + terminalFontSize++; + }); + } + + void decreaseFontSize() { + log('a tab called'); + setState(() { + terminalFontSize--; + }); + } + @override Widget build(BuildContext context) { final strings = AppLocalizations.of(context)!; @@ -133,6 +194,7 @@ class _TerminalScreenDesktopViewState extends ConsumerState{ + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.keyQ, + ): VoidCallbackIntent(() { + exitCallback(sessionId); + }), + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + LogicalKeyboardKey.arrowRight, + ): VoidCallbackIntent(() { + nextTabCallback(tabController, terminalList, currentIndex); + }), + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.keyL, + ): VoidCallbackIntent(() { + nextTabCallback(tabController, terminalList, currentIndex); + }), + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + LogicalKeyboardKey.arrowLeft, + ): VoidCallbackIntent(() { + previousTabCallback(tabController, terminalList, currentIndex); + }), + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.keyH, + ): VoidCallbackIntent(() { + previousTabCallback(tabController, terminalList, currentIndex); + }), + LogicalKeySet( + LogicalKeyboardKey.control, + LogicalKeyboardKey.equal, + ): VoidCallbackIntent(() { + increaseFontSize(); + }), + LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.minus): + VoidCallbackIntent(() { + decreaseFontSize(); + }), + }, + + // textStyle: + // TerminalStyle.fromTextStyle(const TextStyle(fontFamily: '0xProtoNerdFontMono')), + // textStyle: TerminalStyle.fromTextStyle(const TextStyle( + // fontFamily: 'GeistMonoNerdFont', + // // fontSize: 14, + // )), + textStyle: TerminalStyle.fromTextStyle( + TextStyle(fontFamily: 'IosevkaTermNerdFontPropo', fontSize: terminalFontSize + // fontSize: 14, + )), ); }).toList(), ), diff --git a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/utility/responsive_widget.dart b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/utility/responsive_widget.dart index cfc20f3e0..1e1393099 100644 --- a/packages/dart/sshnp_flutter/lib/src/presentation/widgets/utility/responsive_widget.dart +++ b/packages/dart/sshnp_flutter/lib/src/presentation/widgets/utility/responsive_widget.dart @@ -1,42 +1,93 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:sshnp_flutter/src/repository/navigation_repository.dart'; class ResponsiveWidget extends StatelessWidget { - final Widget? tabletScreen; - final Widget mobileScreen; + final Widget? smallScreen; + final Widget mediumScreen; final Widget? largeScreen; + final Widget? extraLargeScreen; - const ResponsiveWidget({super.key, required this.mobileScreen, this.tabletScreen, this.largeScreen}); + const ResponsiveWidget( + {super.key, this.smallScreen, required this.mediumScreen, this.largeScreen, this.extraLargeScreen}); + + // Device Size + + static const kSmallDeviceMinSize = 0; + static const kSmallDeviceMaxSize = 599; + static const kMediumDeviceMinSize = 600; + static const kMediumDeviceMaxSize = 839; + static const kLargeDeviceMinSize = 840; + static const kLargeDeviceMaxSize = 1439; + static const kExtraLargeDeviceMinSize = 1440; // medium size is 800,large is 1200 @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constraints) { - if (constraints.maxWidth < 600) { - return mobileScreen; - } else if (constraints.maxWidth >= 600 && constraints.maxWidth < 1200) { - return tabletScreen ?? mobileScreen; + if (constraints.maxWidth <= kSmallDeviceMaxSize) { + return smallScreen ?? mediumScreen; + } else if (constraints.maxWidth >= kMediumDeviceMinSize && constraints.maxWidth <= kMediumDeviceMaxSize) { + return mediumScreen; + } else if (constraints.maxWidth >= kLargeDeviceMinSize && constraints.maxWidth <= kLargeDeviceMaxSize) { + return largeScreen ?? mediumScreen; + } else if (constraints.maxWidth >= kExtraLargeDeviceMinSize) { + return extraLargeScreen ?? largeScreen ?? mediumScreen; } else { - return largeScreen ?? tabletScreen ?? mobileScreen; + return largeScreen ?? mediumScreen; } }); } + static BuildContext get _context => NavigationRepository.navKey.currentContext!; + static bool isExtraLargeScreen(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return width >= kExtraLargeDeviceMinSize; + } + static bool isLargeScreen(BuildContext context) { - return MediaQuery.of(context).size.width >= 1200; + final width = MediaQuery.of(context).size.width; + return width >= kLargeDeviceMinSize && width <= kLargeDeviceMaxSize; } - static bool isTabletScreen(BuildContext context) { - return MediaQuery.of(context).size.width >= 600 && MediaQuery.of(context).size.width < 1200; + static bool isLargerScreen() { + final context = NavigationRepository.navKey.currentContext!; + final width = MediaQuery.of(context).size.width; + return width >= kLargeDeviceMinSize; } - static bool isMobileScreen(BuildContext context) { - return MediaQuery.of(context).size.width < 600; + static bool isMediumScreen(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return width >= kMediumDeviceMinSize && width <= kMediumDeviceMaxSize; } - static bool isTabletLandscape(BuildContext context) { - return isTabletScreen(context) && MediaQuery.of(context).orientation == Orientation.landscape; + static bool isSmallScreen(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return width >= kSmallDeviceMinSize && width <= kSmallDeviceMaxSize; } - static bool isMobileLandscape(BuildContext context) { - return isTabletScreen(context) && MediaQuery.of(context).orientation == Orientation.landscape; + /// Get return the object based on the screen size + static T getResponsiveObject({ + T? small, + required T medium, + T? large, + T? extraLarge, + }) { + if (isExtraLargeScreen(_context)) { + return extraLarge ?? medium; + } else if (isLargeScreen(_context)) { + return large ?? medium; + } else if (isMediumScreen(_context)) { + return medium; + } else { + return small ?? medium; + } } + + // static bool isTabletLandscape(BuildContext context) { + // return isMediumScreen(context) && MediaQuery.of(context).orientation == Orientation.landscape; + // } + + // static bool isMobileLandscape(BuildContext context) { + // return isMediumScreen(context) && MediaQuery.of(context).orientation == Orientation.landscape; + // } } diff --git a/packages/dart/sshnp_flutter/lib/src/utility/constants.dart b/packages/dart/sshnp_flutter/lib/src/utility/constants.dart index 0c89dac77..ed3e6415d 100644 --- a/packages/dart/sshnp_flutter/lib/src/utility/constants.dart +++ b/packages/dart/sshnp_flutter/lib/src/utility/constants.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; const kPrimaryColor = Color(0xFFF05E3E); const kBackGroundColorDark = Color(0xFF222222); +const kDarkBarColor = Color(0xFF1E1E1E); const kProfileBarColor = Color(0xff3a3a3a); const kProfileBackgroundColor = Color(0xff262626); const kProfileFormFieldColor = Color(0xff303030); @@ -41,3 +42,13 @@ const XTypeGroup dotPrivateTypeGroup = XTypeGroup( // Form Field Constants const kFieldDefaultWidth = 192.0; const kFieldDefaultHeight = 33.0; + +// Device Size + +const kSmallDeviceMinSize = 0; +const kSmallDeviceMaxSize = 599; +const kMediumDeviceMinSize = 600; +const kMediumDeviceMaxSize = 839; +const kLargeDeviceMinSize = 840; +const kLargeDeviceMaxSize = 1439; +const kExtraLargeDeviceMinSize = 1440; diff --git a/packages/dart/sshnp_flutter/lib/src/utility/intents.dart b/packages/dart/sshnp_flutter/lib/src/utility/intents.dart new file mode 100644 index 000000000..00a0549f8 --- /dev/null +++ b/packages/dart/sshnp_flutter/lib/src/utility/intents.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; + +class ExitIntent extends VoidCallbackIntent { + final void Function() onExit; + const ExitIntent(this.onExit) : super(onExit); + // modify this class to call on exit +} diff --git a/packages/dart/sshnp_flutter/lib/src/utility/sizes.dart b/packages/dart/sshnp_flutter/lib/src/utility/sizes.dart index 650229a47..255771245 100644 --- a/packages/dart/sshnp_flutter/lib/src/utility/sizes.dart +++ b/packages/dart/sshnp_flutter/lib/src/utility/sizes.dart @@ -16,6 +16,7 @@ class Sizes { static const p21 = 21.0; static const p28 = 28.0; static const p24 = 24.0; + static const p26 = 26.0; static const p30 = 30.0; static const p32 = 32.0; static const p34 = 34.0; @@ -68,3 +69,127 @@ const gapH46 = SizedBox(height: Sizes.p46); const gapH60 = SizedBox(height: Sizes.p60); const kWindowsMinWindowSize = Size(684, 541); + +/// A class defined to get dimensions for the screen size displayed, +/// using the proportion of the designed screen size. +class SizeConfig { + SizeConfig._(); + + static final SizeConfig _instance = SizeConfig._(); + + factory SizeConfig() => _instance; + late MediaQueryData _mediaQueryData; + late double screenWidth; + late double screenHeight; + late double blockSizeHorizontal; + late double blockSizeVertical; + late double deviceTextFactor; + + late double _safeAreaHorizontal; + late double _safeAreaVertical; + late double safeBlockHorizontal; + late double safeBlockVertical; + + double? profileDrawerWidth; + late double refHeight; + late double refWidth; + + double textFactor = 1.0; + + bool isMobile(BuildContext context) => MediaQuery.of(context).size.width < 700; + + bool isTablet(BuildContext context) => + MediaQuery.of(context).size.width >= 700 && MediaQuery.of(context).size.width < 1200; + bool isDesktop(BuildContext context) => MediaQuery.of(context).size.width >= 1200; + + void init(BuildContext context) { + _mediaQueryData = MediaQuery.of(context); + screenWidth = _mediaQueryData.size.width; + screenHeight = _mediaQueryData.size.height; + refHeight = 505; + refWidth = 671; + + deviceTextFactor = _mediaQueryData.textScaler.scale(20) / 20; + + // print("height is::: $screenHeight"); + + if (screenHeight < 1200) { + blockSizeHorizontal = screenWidth / 100; + blockSizeVertical = screenHeight / 100; + + _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 100; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 100; + } else { + blockSizeHorizontal = screenWidth / 120; + blockSizeVertical = screenHeight / 120; + + _safeAreaHorizontal = _mediaQueryData.padding.left + _mediaQueryData.padding.right; + _safeAreaVertical = _mediaQueryData.padding.top + _mediaQueryData.padding.bottom; + safeBlockHorizontal = (screenWidth - _safeAreaHorizontal) / 120; + safeBlockVertical = (screenHeight - _safeAreaVertical) / 120; + } + if (screenWidth > 700) { + textFactor = 0.8; + } + } + + double getWidthRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refWidth) * 100; + double temp = res * blockSizeHorizontal; + // print("width$temp"); + + return temp; + } + + double getHeightRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refHeight) * 100; + double temp = res * blockSizeVertical; + return temp; + } + + double getFontRatio(double val) { + // if (screenWidth >= 1200 || (Platform.isLinux || Platform.isMacOS || Platform.isWindows)) { + // return val; + // } + double res = (val / refWidth) * 100; + double temp = 0.0; + if (screenWidth > screenHeight) { + temp = res * safeBlockHorizontal + (val * 0.150521609538003) * textFactor; + } else { + temp = res * safeBlockVertical + (val * 0.2473919523099851) * textFactor; + } + // print('$val,$temp,$refHeight,$refWidth'); + final maxSize = val + Sizes.p4; + if (temp > maxSize) { + return maxSize; + } else { + return temp; + } + + // var heightScale = (_mediaQueryData.size.height / refHeight); + // var widthScale = (_mediaQueryData.size.width / refWidth); + + // if (_mediaQueryData.size.height > refHeight || _mediaQueryData.size.width > refWidth) { + // heightScale = heightScale * 0.9; + // widthScale = widthScale * 0.9; + // } + // return val * heightScale * widthScale; + } +} + +/// A shorthand usage of the functions defined in [SizeConfig]. +extension SizeUtils on num { + double get toWidth => SizeConfig().getWidthRatio(toDouble()); + + double get toHeight => SizeConfig().getHeightRatio(toDouble()); + + double get toFont => SizeConfig().getFontRatio(toDouble()); +} diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png index 7bd86a8a8..38dad9769 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png index 432f9de37..a1b2b3f46 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png index 1b85cf16d..443f8960a 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png index 6d18ee962..09a3a1c1f 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index 50ed5f583..f834a5416 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png index f174332d1..0c3dd9187 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 97604f2ea..6b0ff9540 100644 Binary files a/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and b/packages/dart/sshnp_flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/packages/dart/sshnp_flutter/pubspec.lock b/packages/dart/sshnp_flutter/pubspec.lock index 0a2b3709e..7aec93804 100644 --- a/packages/dart/sshnp_flutter/pubspec.lock +++ b/packages/dart/sshnp_flutter/pubspec.lock @@ -792,10 +792,11 @@ packages: noports_core: dependency: "direct main" description: - path: "../noports_core" - relative: true - source: path - version: "6.0.6" + name: noports_core + sha256: "616afc599117dd9881aaf59893cbaacf1234a4e2e16e415e3a08b2d4b45eac05" + url: "https://pub.dev" + source: hosted + version: "6.0.2" openssh_ed25519: dependency: transitive description: @@ -861,7 +862,7 @@ packages: source: hosted version: "1.0.1" path_provider: - dependency: "direct main" + dependency: transitive description: name: path_provider sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b @@ -1008,10 +1009,10 @@ packages: dependency: transitive description: name: posix - sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + sha256: "3ad26924254fd2354b0e2b95fc8b45ac392ad87434f8e64807b3a1ac077f2256" url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "5.0.0" process: dependency: transitive description: diff --git a/packages/dart/sshnp_flutter/pubspec.yaml b/packages/dart/sshnp_flutter/pubspec.yaml index f94600b48..9069e912f 100644 --- a/packages/dart/sshnp_flutter/pubspec.yaml +++ b/packages/dart/sshnp_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: sshnp_flutter description: ssh to any remove device using atsign -version: 1.0.0+4 +version: 1.0.0+5 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: @@ -38,7 +38,6 @@ dependencies: package_info_plus: ^5.0.1 page_transition: ^2.0.9 path: ^1.8.3 - path_provider: ^2.1.1 shared_preferences: ^2.2.2 socket_connector: ^2.0.1 url_launcher: ^6.1.14 @@ -59,6 +58,25 @@ flutter: # - .env - assets/images/nav_icons/ - assets/images/ + + fonts: + - family: 0xProtoNerdFont + fonts: + - asset: assets/fonts/0xProtoNerdFontMono-Regular.ttf + - asset: assets/fonts/0xProtoNerdFont-Regular.ttf + - family: IosevkaTermNerdFontPropo + fonts: + # - asset: assets/fonts/IosevkaTermNerdFontPropo-Bold.ttf + # - asset: assets/fonts/IosevkaTermNerdFontPropo-BoldItalic.ttf + # - asset: assets/fonts/IosevkaTermNerdFontPropo-Italic.ttf + - asset: assets/fonts/IosevkaTermNerdFontPropo-Regular.ttf + - family: GeistMonoNerdFont + fonts: + # - asset: assets/fonts/GeistMonoNerdFont-Bold.ttf + # - asset: assets/fonts/GeistMonoNerdFont-BoldItalic.ttf + # - asset: assets/fonts/GeistMonoNerdFont-Italic.ttf + - asset: assets/fonts/GeistMonoNerdFont-Regular.otf + flutter_launcher_icons: android: "launcher_icon" ios: true @@ -77,6 +95,6 @@ msix_config: identity_name: "TheCompany.SSHNoPortsDesktop" publisher: CN=BBFE1D0B-F713-4C7F-B375-5EA851CBB1FF msix_version: 1.0.0.0 - logo_path: null + logo_path: "assets/images/app_logo.png" capabilities: internetClient store: true diff --git a/packages/dart/sshnp_flutter/windows/runner/resources/app_icon.ico b/packages/dart/sshnp_flutter/windows/runner/resources/app_icon.ico index 86a8ab742..5ee3431d1 100644 Binary files a/packages/dart/sshnp_flutter/windows/runner/resources/app_icon.ico and b/packages/dart/sshnp_flutter/windows/runner/resources/app_icon.ico differ diff --git a/packages/python/sshnpd/pyproject.toml b/packages/python/sshnpd/pyproject.toml index 0e1c7d014..34c1c8533 100644 --- a/packages/python/sshnpd/pyproject.toml +++ b/packages/python/sshnpd/pyproject.toml @@ -12,8 +12,8 @@ sshnpd = 'sshnpd:main' [tool.poetry.dependencies] python = "^3.10" -atsdk = "0.2.11" -bcrypt = "4.1.2" +atsdk = "0.2.12" +bcrypt = "4.1.3" paramiko = "3.4.0" PyNaCl = "1.5.0" setuptools = "69.5.1" diff --git a/packages/python/sshnpd/requirements.txt b/packages/python/sshnpd/requirements.txt index 31b305ca2..34f192a0a 100644 --- a/packages/python/sshnpd/requirements.txt +++ b/packages/python/sshnpd/requirements.txt @@ -1,34 +1,34 @@ -atsdk==0.2.11 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:4ccdbad4887a62cc8d0c273dd61bc1918974277c9ad8673af26fdc0e26c97bd8 \ - --hash=sha256:f4c6e9dc666aea5777f52869203b7cf4309c03f0d82e09ac77787f2471f8f393 -bcrypt==4.1.2 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:02d9ef8915f72dd6daaef40e0baeef8a017ce624369f09754baf32bb32dba25f \ - --hash=sha256:1c28973decf4e0e69cee78c68e30a523be441972c826703bb93099868a8ff5b5 \ - --hash=sha256:2a298db2a8ab20056120b45e86c00a0a5eb50ec4075b6142db35f593b97cb3fb \ - --hash=sha256:33313a1200a3ae90b75587ceac502b048b840fc69e7f7a0905b5f87fac7a1258 \ - --hash=sha256:3566a88234e8de2ccae31968127b0ecccbb4cddb629da744165db72b58d88ca4 \ - --hash=sha256:387e7e1af9a4dd636b9505a465032f2f5cb8e61ba1120e79a0e1cd0b512f3dfc \ - --hash=sha256:44290ccc827d3a24604f2c8bcd00d0da349e336e6503656cb8192133e27335e2 \ - --hash=sha256:57fa9442758da926ed33a91644649d3e340a71e2d0a5a8de064fb621fd5a3326 \ - --hash=sha256:68e3c6642077b0c8092580c819c1684161262b2e30c4f45deb000c38947bf483 \ - --hash=sha256:69057b9fc5093ea1ab00dd24ede891f3e5e65bee040395fb1e66ee196f9c9b4a \ - --hash=sha256:6cad43d8c63f34b26aef462b6f5e44fdcf9860b723d2453b5d391258c4c8e966 \ - --hash=sha256:71b8be82bc46cedd61a9f4ccb6c1a493211d031415a34adde3669ee1b0afbb63 \ - --hash=sha256:732b3920a08eacf12f93e6b04ea276c489f1c8fb49344f564cca2adb663b3e4c \ - --hash=sha256:9800ae5bd5077b13725e2e3934aa3c9c37e49d3ea3d06318010aa40f54c63551 \ - --hash=sha256:a97e07e83e3262599434816f631cc4c7ca2aa8e9c072c1b1a7fec2ae809a1d2d \ - --hash=sha256:ac621c093edb28200728a9cca214d7e838529e557027ef0581685909acd28b5e \ - --hash=sha256:b8df79979c5bae07f1db22dcc49cc5bccf08a0380ca5c6f391cbb5790355c0b0 \ - --hash=sha256:b90e216dc36864ae7132cb151ffe95155a37a14e0de3a8f64b49655dd959ff9c \ - --hash=sha256:ba4e4cc26610581a6329b3937e02d319f5ad4b85b074846bf4fef8a8cf51e7bb \ - --hash=sha256:ba55e40de38a24e2d78d34c2d36d6e864f93e0d79d0b6ce915e4335aa81d01b1 \ - --hash=sha256:be3ab1071662f6065899fe08428e45c16aa36e28bc42921c4901a191fda6ee42 \ - --hash=sha256:d75fc8cd0ba23f97bae88a6ec04e9e5351ff3c6ad06f38fe32ba50cbd0d11946 \ - --hash=sha256:e51c42750b7585cee7892c2614be0d14107fad9581d1738d954a262556dd1aab \ - --hash=sha256:ea505c97a5c465ab8c3ba75c0805a102ce526695cd6818c6de3b1a38f6f60da1 \ - --hash=sha256:eb3bd3321517916696233b5e0c67fd7d6281f0ef48e66812db35fc963a422a1c \ - --hash=sha256:f70d9c61f9c4ca7d57f3bfe88a5ccf62546ffbadf3681bb1e268d9d2e41c91a7 \ - --hash=sha256:fbe188b878313d01b7718390f31528be4010fed1faa798c5a1d0469c9c48c369 +atsdk==0.2.12 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:250cb6f665e19c8f9e8233849908a3739b8ecd5a4ca106f1ae879e234adf04ef \ + --hash=sha256:8db83ebeb8233076029a451fcadce4c34b28cbadc02061b0768fa5fef468c62d +bcrypt==4.1.3 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64 \ + --hash=sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf \ + --hash=sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05 \ + --hash=sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c \ + --hash=sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15 \ + --hash=sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991 \ + --hash=sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623 \ + --hash=sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834 \ + --hash=sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08 \ + --hash=sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a \ + --hash=sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74 \ + --hash=sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455 \ + --hash=sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3 \ + --hash=sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73 \ + --hash=sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611 \ + --hash=sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2 \ + --hash=sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d \ + --hash=sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286 \ + --hash=sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978 \ + --hash=sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d \ + --hash=sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc \ + --hash=sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6 \ + --hash=sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed \ + --hash=sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650 \ + --hash=sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84 \ + --hash=sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1 \ + --hash=sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a certifi==2024.2.2 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \ --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1 @@ -176,39 +176,39 @@ charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0" --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 -cryptography==42.0.5 ; python_version >= "3.10" and python_version < "4.0" \ - --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \ - --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \ - --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \ - --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \ - --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \ - --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \ - --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \ - --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \ - --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \ - --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \ - --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \ - --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \ - --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \ - --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \ - --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \ - --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \ - --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \ - --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \ - --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \ - --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \ - --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \ - --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \ - --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \ - --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \ - --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \ - --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \ - --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \ - --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \ - --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \ - --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \ - --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \ - --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7 +cryptography==42.0.6 ; python_version >= "3.10" and python_version < "4.0" \ + --hash=sha256:00c0faa5b021457848d031ecff041262211cc1e2bce5f6e6e6c8108018f6b44a \ + --hash=sha256:073104df012fc815eed976cd7d0a386c8725d0d0947cf9c37f6c36a6c20feb1b \ + --hash=sha256:076c92b08dd1ab88108bc84545187e10d3693a9299c593f98c4ea195a0b0ead7 \ + --hash=sha256:089aeb297ff89615934b22c7631448598495ffd775b7d540a55cfee35a677bf4 \ + --hash=sha256:3b750279f3e7715df6f68050707a0cee7cbe81ba2eeb2f21d081bd205885ffed \ + --hash=sha256:43e521f21c2458038d72e8cdfd4d4d9f1d00906a7b6636c4272e35f650d1699b \ + --hash=sha256:4bdb39ecbf05626e4bfa1efd773bb10346af297af14fb3f4c7cb91a1d2f34a46 \ + --hash=sha256:5967e3632f42b0c0f9dc2c9da88c79eabdda317860b246d1fbbde4a8bbbc3b44 \ + --hash=sha256:65d529c31bd65d54ce6b926a01e1b66eacf770b7e87c0622516a840e400ec732 \ + --hash=sha256:6981acac509cc9415344cb5bfea8130096ea6ebcc917e75503143a1e9e829160 \ + --hash=sha256:81dbe47e28b703bc4711ac74a64ef8b758a0cf056ce81d08e39116ab4bc126fa \ + --hash=sha256:8b90c57b3cd6128e0863b894ce77bd36fcb5f430bf2377bc3678c2f56e232316 \ + --hash=sha256:9184aff0856261ecb566a3eb26a05dfe13a292c85ce5c59b04e4aa09e5814187 \ + --hash=sha256:945a43ebf036dd4b43ebfbbd6b0f2db29ad3d39df824fb77476ca5777a9dde33 \ + --hash=sha256:97eeacae9aa526ddafe68b9202a535f581e21d78f16688a84c8dcc063618e121 \ + --hash=sha256:9f1a3bc2747166b0643b00e0b56cd9b661afc9d5ff963acaac7a9c7b2b1ef638 \ + --hash=sha256:9ff75b88a4d273c06d968ad535e6cb6a039dd32db54fe36f05ed62ac3ef64a44 \ + --hash=sha256:aeb6f56b004e898df5530fa873e598ec78eb338ba35f6fa1449970800b1d97c2 \ + --hash=sha256:b16b90605c62bcb3aa7755d62cf5e746828cfc3f965a65211849e00c46f8348d \ + --hash=sha256:b99831397fdc6e6e0aa088b060c278c6e635d25c0d4d14bdf045bf81792fda0a \ + --hash=sha256:bc954251edcd8a952eeaec8ae989fec7fe48109ab343138d537b7ea5bb41071a \ + --hash=sha256:c05230d8aaaa6b8ab3ab41394dc06eb3d916131df1c9dcb4c94e8f041f704b74 \ + --hash=sha256:d16a310c770cc49908c500c2ceb011f2840674101a587d39fa3ea828915b7e83 \ + --hash=sha256:d93080d2b01b292e7ee4d247bf93ed802b0100f5baa3fa5fd6d374716fa480d4 \ + --hash=sha256:e1f5f15c5ddadf6ee4d1d624a2ae940f14bd74536230b0056ccb28bb6248e42a \ + --hash=sha256:e3442601d276bd9e961d618b799761b4e5d892f938e8a4fe1efbe2752be90455 \ + --hash=sha256:e85f433230add2aa26b66d018e21134000067d210c9c68ef7544ba65fc52e3eb \ + --hash=sha256:eecca86813c6a923cabff284b82ff4d73d9e91241dc176250192c3a9b9902a54 \ + --hash=sha256:f1e933b238978ccfa77b1fee0a297b3c04983f4cb84ae1c33b0ea4ae08266cc9 \ + --hash=sha256:f4cece02478d73dacd52be57a521d168af64ae03d2a567c0c4eb6f189c3b9d79 \ + --hash=sha256:f567a82b7c2b99257cca2a1c902c1b129787278ff67148f188784245c7ed5495 \ + --hash=sha256:f987a244dfb0333fbd74a691c36000a2569eaf7c7cc2ac838f85f59f0588ddc9 idna==3.7 ; python_version >= "3.10" and python_version < "4.0" \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0