优化状态栏显示网络图标,优化IP信息更新不及时问题,实现注册码页面
Squashed commit of the following: commit 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 Merge: 2dba9f8e 964a81c3 Author: zkk <1007518571@qq.com> Date: Mon Mar 3 15:25:49 2025 +0800 Merge commit '964a81c37cd165b9f8df20db87fd915ba03d10b5' into release commit 964a81c37cd165b9f8df20db87fd915ba03d10b5 Author: zkk <1007518571@qq.com> Date: Fri Feb 28 16:27:57 2025 +0800 状态栏增加网络连接图标 commit 9c99cd91250c7aeb3d9728e540590299a1caf150 Author: zkk <1007518571@qq.com> Date: Fri Feb 28 16:20:52 2025 +0800 修复网络页面IP更新不及时的问题 commit 842a616c2558757d19b7553d23aee9f1daffdc80 Author: zkk <1007518571@qq.com> Date: Tue Feb 25 14:53:31 2025 +0800 注册码功能的实现 commit 2dba9f8ee2725847f31c891b19df6d9b81e03568 Merge: 03cd3722 18f05cc5 Author: zkk <1007518571@qq.com> Date: Fri Feb 14 15:21:36 2025 +0800 Merge commit '18f05cc52dfb7889853a4f84aad975309ab7dbbe' into release commit 18f05cc52dfb7889853a4f84aad975309ab7dbbe Author: zkk <1007518571@qq.com> Date: Wed Feb 5 10:59:00 2025 +0800 修复连接不了未加密网络的旧问题 commit 025a26209cbe15a0b7f5f1aba5166da63d6eaebf Author: zkk <1007518571@qq.com> Date: Fri Jan 24 15:48:52 2025 +0800 重构网络页面,解决卡顿问题 commit fdc851c4e66e3b872eb2564442f0c67369b9e3e2 Author: zkk <1007518571@qq.com> Date: Fri Jan 24 15:13:41 2025 +0800 优化菜单页面的点击效果和增加列表风格属性 commit e6cfa874208f8d98d0360fb073e4da15c935b202 Author: zkk <1007518571@qq.com> Date: Tue Jan 21 15:11:28 2025 +0800 优化进入工厂模式的方式为10s内点击5次 commit 03cd37229ee6c606e9814af602709d81b2c79bec Merge: cf7cafef adcbaa17 Author: zkk <1007518571@qq.com> Date: Fri Jan 17 14:38:18 2025 +0800 Merge commit 'adcbaa1795bffedc3000bc9e59eabba04d946dd4' into release commit adcbaa1795bffedc3000bc9e59eabba04d946dd4 Author: zkk <1007518571@qq.com> Date: Tue Jan 14 15:34:10 2025 +0800 实现探针偏移值校准保存前范围检测,避免保存错误值无法启动问题 commit cf7cafefbcd2274c9a481e58042d11db8cd79961 Merge: dc3478b4 8d259cea Author: zkk <1007518571@qq.com> Date: Tue Jan 7 17:26:59 2025 +0800 Merge commit '8d259ceadd5026cecc1dc61224d91aef4f3877b4' into release commit 8d259ceadd5026cecc1dc61224d91aef4f3877b4 Author: zkk <1007518571@qq.com> Date: Tue Jan 7 17:15:46 2025 +0800 实现 打印中恢复喷头温度 提示语的翻译 commit dd11c9683cb5af5407e650eea9b683b1066256c7 Author: zkk <1007518571@qq.com> Date: Tue Jan 7 16:52:04 2025 +0800 优化单个喷头时不显示喷头偏移菜单 commit c3ec7a81bbe1490b76202485d0502a4829a3cee5 Author: zkk <1007518571@qq.com> Date: Fri Jan 3 17:52:24 2025 +0800 修复屏幕耗材检测显示偶尔不准确的问题 commit 413bf6fc4a740f53d265c63abe7c51eaad483cb0 Author: zkk <1007518571@qq.com> Date: Fri Jan 3 15:00:54 2025 +0800 修复耗材检测弹窗异常问题 commit dc3478b48c7da1dbae120d1270c9ab64646d6647 Merge: 02c7556c 3bfc1aa7 Author: zkk <1007518571@qq.com> Date: Thu Jan 2 11:18:07 2025 +0800 Merge commit '3bfc1aa714e282d74b801155d830377ca58d8f59' into release commit 3bfc1aa714e282d74b801155d830377ca58d8f59 Author: zkk <1007518571@qq.com> Date: Thu Jan 2 11:17:15 2025 +0800 修复移轴页面移轴功能失效问题 commit 02c7556cdadf8de1ef3c54d2831920927cadbe30 Merge: 6bfa42e0 991003e6 Author: zkk <1007518571@qq.com> Date: Tue Dec 31 15:07:54 2024 +0800 Merge commit '991003e6cbea335eca73d3783aa1837059614724' into release commit 991003e6cbea335eca73d3783aa1837059614724 Author: zkk <1007518571@qq.com> Date: Tue Dec 31 15:03:34 2024 +0800 优化完整 简体中文和繁体中文的翻译 commit 1a177e90d09b9b9949bff2a1e3c6b12173420620 Author: zkk <1007518571@qq.com> Date: Tue Dec 31 14:10:03 2024 +0800 优化排除对象的英文语法错误 commit e8d509cb6c2883b1fadb5ab9f9ca658e61849055 Author: zkk <1007518571@qq.com> Date: Fri Dec 27 16:40:52 2024 +0800 优化耗材检测显示内容 commit 1b7670485a918cb334119175777525f768e670be Author: zkk <1007518571@qq.com> Date: Fri Dec 27 14:56:25 2024 +0800 完善断料自动切头功能描述 commit ecc0c3dd16442497e56f5f8ab3a0c6be00bd180e Author: zkk <1007518571@qq.com> Date: Fri Dec 27 13:40:01 2024 +0800 实现弹窗翻译功能 commit bc6d60fa183af50b7b16fea685139ca9d5df90ea Author: zkk <1007518571@qq.com> Date: Fri Dec 27 09:53:16 2024 +0800 优化不合理名称和不合理大小写 commit 2e650926bdba1c65baa506be1b1dd09621e8d8ea Author: zkk <1007518571@qq.com> Date: Thu Dec 26 15:06:11 2024 +0800 修复10寸屏幕偏移值微调页面出界问题 commit c481b551f777a3a6cadf7be3bfcab38448b51694 Author: zkk <1007518571@qq.com> Date: Wed Dec 25 15:28:26 2024 +0800 优化移轴设置页面没有返回按钮的问题 commit 2b3c9936bd693c8fc265d6352799f382680f4920 Author: zkk <1007518571@qq.com> Date: Wed Dec 25 10:05:04 2024 +0800 删除移动设置页面中轴反转的选项 commit 5e37d59497c54086d3f1e215cbabc03254857a58 Author: zkk <1007518571@qq.com> Date: Wed Dec 25 09:05:03 2024 +0800 优化选择语言标题 commit 5214c3697baac78bd0a465e33d6f4f3c1e30862e Author: zkk <1007518571@qq.com> Date: Tue Dec 24 10:57:41 2024 +0800 增加设置hostname功能 commit 3709a7465cc2e0d677ecc9979fb18144f7e0ec33 Author: zkk <1007518571@qq.com> Date: Tue Dec 24 10:43:46 2024 +0800 增加工厂设置中打包模式 commit 0c2a2618beb68d50601e433beef06122fb0ffd40 Author: zkk <1007518571@qq.com> Date: Mon Dec 23 16:25:37 2024 +0800 实现恢复出厂设置功能 commit e3a38f85613d53a4a063e835c34c701196010c6e Author: zkk <1007518571@qq.com> Date: Mon Dec 23 15:48:17 2024 +0800 一点格式化 commit 4e9e452e8bed4b53eaaae8f0a69142de8aa50611 Author: zkk <1007518571@qq.com> Date: Sat Dec 21 14:20:22 2024 +0800 优化探针偏移值校准时如果当前激活为第一个喷头时不会重复激活喷头 commit 3b85e8e8d59b0d4eae75f80d9e637fe9dc272cbe Merge: 882850db 10ec2029 Author: zkk <1007518571@qq.com> Date: Wed Dec 18 17:26:08 2024 +0800 Merge branch 'develop' of https://server.creatbot.com/Gitea/CreatBot/CreatBotKlipperScreen into develop commit 882850dbde648598e5f91281101d0ea01fd56d56 Author: zkk <1007518571@qq.com> Date: Wed Dec 18 17:21:16 2024 +0800 补充双喷头偏移校准页面二维码图片 commit 10ec2029eb73e66874d5a0ec492c016480641110 Author: ruipeng <1041589370@qq.com> Date: Wed Dec 18 17:17:18 2024 +0800 增加自动切换喷头开关选项 commit 3d6eed9d9526b77472ba7df29014b5768c594026 Author: zkk <1007518571@qq.com> Date: Mon Dec 16 16:33:34 2024 +0800 喷头偏移值校准功能的实现 commit 40ecbb3ea4827c9bac1aa271cccc958c94c1114a Author: zkk <1007518571@qq.com> Date: Fri Dec 13 09:20:00 2024 +0800 z探针校准时指定默认激活工具头为第一个头 commit bce3caa409618ef5bc2067865940d14a1441c0f8 Author: zkk <1007518571@qq.com> Date: Fri Dec 13 09:19:19 2024 +0800 优化z探针校准时候移动过慢问题 commit 6bfa42e036a521c8ff7db1bf8ccb65500eabb6ea Merge: 1a87ced3 4f3aa9aa Author: zkk <1007518571@qq.com> Date: Thu Dec 12 10:33:58 2024 +0800 Merge commit '4f3aa9aa4c581ae9e7a740bd37f9e80ba064c27f' into release commit 4f3aa9aa4c581ae9e7a740bd37f9e80ba064c27f Merge: e3fd413d 1a69b518 Author: zkk <1007518571@qq.com> Date: Thu Dec 12 10:30:00 2024 +0800 Merge branch 'develop' of https://server.creatbot.com/Gitea/CreatBot/CreatBotKlipperScreen into develop commit 1a69b5180de733f15550a1294a7221d6070306a0 Author: ruipeng <1041589370@qq.com> Date: Wed Dec 11 11:44:36 2024 +0800 新增D600pro2、D1000的V0版机型 commit e3fd413d6256414441e9fe653c1132b1799a5cb2 Author: zkk <1007518571@qq.com> Date: Tue Dec 10 14:34:13 2024 +0800 修复打印时没有修改z偏移值 仍提示保存z偏移的按钮的bug commit 594fb668fe94fe907c028bf65ecced43ea8660cb Author: zkk <1007518571@qq.com> Date: Tue Dec 10 14:25:04 2024 +0800 设置自适应调平选项默认为关闭状态 commit 1a87ced3f5725569a6b9a7ee5f5250044d01d852 Merge: 629416d1 6064a6e1 Author: zkk <1007518571@qq.com> Date: Fri Nov 29 10:18:32 2024 +0800 Merge branch 'develop' into release # Conflicts: # ks_includes/locales/KlipperScreen.pot resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.mo resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # ks_includes/locales/zh_CN/LC_MESSAGES/KlipperScreen.po resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.mo resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # ks_includes/locales/zh_TW/LC_MESSAGES/KlipperScreen.po resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # panels/factory_settings.py resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version # panels/network.py resolved by 69bcfa4bd00fc1af8da8df191b6a4d86309c7d23 version
This commit is contained in:
parent
bfd5ba6a3c
commit
f892315588
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-14 16:25+0800\n"
|
||||
"POT-Creation-Date: 2025-02-26 11:12+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -70,6 +70,9 @@ msgstr ""
|
||||
msgid "Accept"
|
||||
msgstr ""
|
||||
|
||||
msgid "Activate"
|
||||
msgstr ""
|
||||
|
||||
msgid "Adaptive Bed Leveling"
|
||||
msgstr ""
|
||||
|
||||
@ -234,9 +237,6 @@ msgstr ""
|
||||
msgid "Confirm factory reset?\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connected"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting"
|
||||
msgstr ""
|
||||
|
||||
@ -306,15 +306,24 @@ msgstr ""
|
||||
msgid "Do you want to recover %s?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Elapsed trial time:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Elapsed:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Emergency Stop"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable Registration Code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable screen power management"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enabled successfully"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
@ -462,9 +471,6 @@ msgstr ""
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hostname"
|
||||
msgstr ""
|
||||
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
@ -507,6 +513,18 @@ msgstr ""
|
||||
msgid "Job Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Key is empty"
|
||||
msgstr ""
|
||||
|
||||
msgid "Key is invalid"
|
||||
msgstr ""
|
||||
|
||||
msgid "Key is valid"
|
||||
msgstr ""
|
||||
|
||||
msgid "Key:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Klipper Restart"
|
||||
msgstr ""
|
||||
|
||||
@ -559,6 +577,9 @@ msgstr ""
|
||||
msgid "Leveling only in the actual print area"
|
||||
msgstr ""
|
||||
|
||||
msgid "License key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Limits"
|
||||
msgstr ""
|
||||
|
||||
@ -682,6 +703,9 @@ msgstr ""
|
||||
msgid "Not Inserted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not activated"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not all screens support this"
|
||||
msgstr ""
|
||||
|
||||
@ -745,12 +769,18 @@ msgstr ""
|
||||
msgid "Perform a full upgrade?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Permanent Activation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pins"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please ensure that the Probe Calibrate has been performed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enter a key to activate"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please enter a valid number"
|
||||
msgstr ""
|
||||
|
||||
@ -835,6 +865,9 @@ msgstr ""
|
||||
msgid "Refresh"
|
||||
msgstr ""
|
||||
|
||||
msgid "Remaining Time:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Remove network"
|
||||
msgstr ""
|
||||
|
||||
@ -844,6 +877,12 @@ msgstr ""
|
||||
msgid "Reprint"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset successfully"
|
||||
msgstr ""
|
||||
|
||||
msgid "Restart"
|
||||
msgstr ""
|
||||
|
||||
@ -923,6 +962,9 @@ msgstr ""
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
msgid "Serial Number:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
@ -944,6 +986,9 @@ msgstr ""
|
||||
msgid "Size"
|
||||
msgstr ""
|
||||
|
||||
msgid "Skip"
|
||||
msgstr ""
|
||||
|
||||
msgid "Slicer"
|
||||
msgstr ""
|
||||
|
||||
@ -983,15 +1028,15 @@ msgstr ""
|
||||
msgid "Start testing the Z offset value of the second nozzle?\n"
|
||||
msgstr ""
|
||||
|
||||
msgid "Starting WiFi Association"
|
||||
msgstr ""
|
||||
|
||||
msgid "Starting recovery for"
|
||||
msgstr ""
|
||||
|
||||
msgid "Starting update for"
|
||||
msgstr ""
|
||||
|
||||
msgid "State:"
|
||||
msgstr ""
|
||||
|
||||
msgid "System"
|
||||
msgstr ""
|
||||
|
||||
@ -1019,6 +1064,9 @@ msgstr ""
|
||||
msgid "The system will reboot!"
|
||||
msgstr ""
|
||||
|
||||
msgid "This device is not activated and is available for trial use only"
|
||||
msgstr ""
|
||||
|
||||
msgid "This operation is about to print the model"
|
||||
msgstr ""
|
||||
|
||||
@ -1037,6 +1085,15 @@ msgstr ""
|
||||
msgid "Total:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trial"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trial Time:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unknown Heater"
|
||||
msgstr ""
|
||||
|
||||
@ -1139,6 +1196,9 @@ msgid_plural "hours"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "license"
|
||||
msgstr ""
|
||||
|
||||
msgid "macros that use 'rename_existing' are hidden"
|
||||
msgstr ""
|
||||
|
||||
|
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: KlipperScreen\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-07 17:11+0800\n"
|
||||
"POT-Creation-Date: 2025-02-26 11:12+0800\n"
|
||||
"PO-Revision-Date: 2024-06-03 19:09+0000\n"
|
||||
"Last-Translator: wsj20050623 <2129426599@qq.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
|
||||
@ -63,7 +63,7 @@ msgid "ADXL Not Configured"
|
||||
msgstr "未配置加速度计"
|
||||
|
||||
msgid "Abort"
|
||||
msgstr "中止打印"
|
||||
msgstr "终止"
|
||||
|
||||
msgid "Acceleration:"
|
||||
msgstr "加速度:"
|
||||
@ -71,6 +71,9 @@ msgstr "加速度:"
|
||||
msgid "Accept"
|
||||
msgstr "确定"
|
||||
|
||||
msgid "Activate"
|
||||
msgstr "激活"
|
||||
|
||||
msgid "Adaptive Bed Leveling"
|
||||
msgstr "自适应床调平"
|
||||
|
||||
@ -235,9 +238,6 @@ msgstr "紧急停止需要二次确认"
|
||||
msgid "Confirm factory reset?\n"
|
||||
msgstr "确定恢复出厂设置?\n"
|
||||
|
||||
msgid "Connected"
|
||||
msgstr "已连接"
|
||||
|
||||
msgid "Connecting"
|
||||
msgstr "连接中"
|
||||
|
||||
@ -307,15 +307,24 @@ msgstr "您要忘记或断开%s的连接吗?"
|
||||
msgid "Do you want to recover %s?"
|
||||
msgstr "你想恢复 %s 吗?"
|
||||
|
||||
msgid "Elapsed trial time:"
|
||||
msgstr "已用时间:"
|
||||
|
||||
msgid "Elapsed:"
|
||||
msgstr "已用时间:"
|
||||
|
||||
msgid "Emergency Stop"
|
||||
msgstr "紧急停止"
|
||||
|
||||
msgid "Enable Registration Code"
|
||||
msgstr "启用注册码"
|
||||
|
||||
msgid "Enable screen power management"
|
||||
msgstr "开启屏幕功率管理功能"
|
||||
|
||||
msgid "Enabled successfully"
|
||||
msgstr "启用成功"
|
||||
|
||||
msgid "Error"
|
||||
msgstr "错误"
|
||||
|
||||
@ -463,9 +472,6 @@ msgstr "Z轴归零"
|
||||
msgid "Host"
|
||||
msgstr "主机"
|
||||
|
||||
msgid "Hostname"
|
||||
msgstr "主机名"
|
||||
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
@ -508,6 +514,18 @@ msgstr "设置文件可能存在错误"
|
||||
msgid "Job Status"
|
||||
msgstr "工作状态"
|
||||
|
||||
msgid "Key is empty"
|
||||
msgstr "密钥为空"
|
||||
|
||||
msgid "Key is invalid"
|
||||
msgstr "密钥无效"
|
||||
|
||||
msgid "Key is valid"
|
||||
msgstr "密钥有效"
|
||||
|
||||
msgid "Key:"
|
||||
msgstr "密钥:"
|
||||
|
||||
msgid "Klipper Restart"
|
||||
msgstr "重启Klipper"
|
||||
|
||||
@ -560,6 +578,9 @@ msgstr "剩余时间:"
|
||||
msgid "Leveling only in the actual print area"
|
||||
msgstr "仅在实际打印区域进行床调平"
|
||||
|
||||
msgid "License key"
|
||||
msgstr "许可证密钥"
|
||||
|
||||
msgid "Limits"
|
||||
msgstr "打印机限制"
|
||||
|
||||
@ -683,6 +704,9 @@ msgstr "未启用"
|
||||
msgid "Not Inserted"
|
||||
msgstr "未装载"
|
||||
|
||||
msgid "Not activated"
|
||||
msgstr "未激活"
|
||||
|
||||
msgid "Not all screens support this"
|
||||
msgstr "不一定所有屏幕都支持这项功能"
|
||||
|
||||
@ -745,12 +769,18 @@ msgstr "已暂停"
|
||||
msgid "Perform a full upgrade?"
|
||||
msgstr "是否更新全部?"
|
||||
|
||||
msgid "Permanent Activation"
|
||||
msgstr "永久激活"
|
||||
|
||||
msgid "Pins"
|
||||
msgstr "引脚"
|
||||
|
||||
msgid "Please ensure that the Probe Calibrate has been performed"
|
||||
msgstr "请确保已完成探针偏移校准"
|
||||
|
||||
msgid "Please enter a key to activate"
|
||||
msgstr "请输入密钥激活"
|
||||
|
||||
msgid "Please enter a valid number"
|
||||
msgstr "请输入有效的数字"
|
||||
|
||||
@ -835,6 +865,9 @@ msgstr "参考"
|
||||
msgid "Refresh"
|
||||
msgstr "检查更新"
|
||||
|
||||
msgid "Remaining Time:"
|
||||
msgstr "剩余时间:"
|
||||
|
||||
msgid "Remove network"
|
||||
msgstr "删除网络"
|
||||
|
||||
@ -844,6 +877,12 @@ msgstr "重命名/移动:"
|
||||
msgid "Reprint"
|
||||
msgstr "再次打印"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "重置"
|
||||
|
||||
msgid "Reset successfully"
|
||||
msgstr "重置成功"
|
||||
|
||||
msgid "Restart"
|
||||
msgstr "重启"
|
||||
|
||||
@ -923,6 +962,9 @@ msgstr "选择型号"
|
||||
msgid "Send"
|
||||
msgstr "发送"
|
||||
|
||||
msgid "Serial Number:"
|
||||
msgstr "序列号:"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
@ -944,6 +986,9 @@ msgstr "散热风扇"
|
||||
msgid "Size"
|
||||
msgstr "大小"
|
||||
|
||||
msgid "Skip"
|
||||
msgstr "跳过"
|
||||
|
||||
msgid "Slicer"
|
||||
msgstr "切片软件"
|
||||
|
||||
@ -983,15 +1028,15 @@ msgstr "开始"
|
||||
msgid "Start testing the Z offset value of the second nozzle?\n"
|
||||
msgstr "开始测试第二个喷嘴的 Z 偏移值吗?\n"
|
||||
|
||||
msgid "Starting WiFi Association"
|
||||
msgstr "开始WiFi连接"
|
||||
|
||||
msgid "Starting recovery for"
|
||||
msgstr "开始恢复"
|
||||
|
||||
msgid "Starting update for"
|
||||
msgstr "开始更新"
|
||||
|
||||
msgid "State:"
|
||||
msgstr "状态:"
|
||||
|
||||
msgid "System"
|
||||
msgstr "系统"
|
||||
|
||||
@ -1019,6 +1064,9 @@ msgstr ""
|
||||
msgid "The system will reboot!"
|
||||
msgstr "系统将重新启动!"
|
||||
|
||||
msgid "This device is not activated and is available for trial use only"
|
||||
msgstr "此设备尚未激活,仅供试用"
|
||||
|
||||
msgid "This operation is about to print the model"
|
||||
msgstr "此操作即将开始打印模型"
|
||||
|
||||
@ -1037,6 +1085,15 @@ msgstr "打印过程中超过倒计时后关闭屏幕"
|
||||
msgid "Total:"
|
||||
msgstr "合计:"
|
||||
|
||||
msgid "Trial"
|
||||
msgstr "试用"
|
||||
|
||||
msgid "Trial Time:"
|
||||
msgstr "试用时间:"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "Unknown Heater"
|
||||
msgstr "未知加热器"
|
||||
|
||||
@ -1136,6 +1193,9 @@ msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "小时"
|
||||
|
||||
msgid "license"
|
||||
msgstr "许可证"
|
||||
|
||||
msgid "macros that use 'rename_existing' are hidden"
|
||||
msgstr "使用\"rename_existing\"的宏将被隐藏"
|
||||
|
||||
@ -1168,6 +1228,15 @@ msgid "second"
|
||||
msgid_plural "seconds"
|
||||
msgstr[0] "秒"
|
||||
|
||||
#~ msgid "Connected"
|
||||
#~ msgstr "已连接"
|
||||
|
||||
#~ msgid "Hostname"
|
||||
#~ msgstr "主机名"
|
||||
|
||||
#~ msgid "Starting WiFi Association"
|
||||
#~ msgstr "开始WiFi连接"
|
||||
|
||||
#~ msgid "Restoring Left extruder temperature, this may take some time"
|
||||
#~ msgstr "恢复左挤出机温度,这可能需要一些时间"
|
||||
|
||||
@ -1243,9 +1312,6 @@ msgstr[0] "秒"
|
||||
#~ msgid "KlipperScreen will drop support in June 2024"
|
||||
#~ msgstr "KlipperScreen将于2024 年6月停止适配"
|
||||
|
||||
#~ msgid "Print Time"
|
||||
#~ msgstr "打印用时"
|
||||
|
||||
#~ msgid "Warning"
|
||||
#~ msgstr "警告"
|
||||
|
||||
@ -1420,6 +1486,3 @@ msgstr[0] "秒"
|
||||
|
||||
#~ msgid "Load Average"
|
||||
#~ msgstr "平均负载"
|
||||
|
||||
#~ msgid "Screen Blanking Time"
|
||||
#~ msgstr "关闭屏幕时间"
|
||||
|
Binary file not shown.
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: KlipperScreen\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-07 17:11+0800\n"
|
||||
"POT-Creation-Date: 2025-02-26 11:12+0800\n"
|
||||
"PO-Revision-Date: 2024-06-01 12:09+0000\n"
|
||||
"Last-Translator: 峻瑜哥 <a728728728@gmail.com>\n"
|
||||
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
|
||||
@ -71,6 +71,9 @@ msgstr "加速度:"
|
||||
msgid "Accept"
|
||||
msgstr "接受"
|
||||
|
||||
msgid "Activate"
|
||||
msgstr "激活"
|
||||
|
||||
msgid "Adaptive Bed Leveling"
|
||||
msgstr "自適應床調平"
|
||||
|
||||
@ -235,9 +238,6 @@ msgstr "緊急停止需確認"
|
||||
msgid "Confirm factory reset?\n"
|
||||
msgstr "確定恢復出廠設置?\n"
|
||||
|
||||
msgid "Connected"
|
||||
msgstr "已連線"
|
||||
|
||||
msgid "Connecting"
|
||||
msgstr "連接中"
|
||||
|
||||
@ -307,15 +307,24 @@ msgstr "您要忘記或斷開%s的連接嗎?"
|
||||
msgid "Do you want to recover %s?"
|
||||
msgstr "你想恢復 %s 嗎?"
|
||||
|
||||
msgid "Elapsed trial time:"
|
||||
msgstr "已用時間"
|
||||
|
||||
msgid "Elapsed:"
|
||||
msgstr "已用時間:"
|
||||
|
||||
msgid "Emergency Stop"
|
||||
msgstr "緊急停止"
|
||||
|
||||
msgid "Enable Registration Code"
|
||||
msgstr "啟用註冊碼"
|
||||
|
||||
msgid "Enable screen power management"
|
||||
msgstr "開啟螢幕功率管理功能"
|
||||
|
||||
msgid "Enabled successfully"
|
||||
msgstr "啟用成功"
|
||||
|
||||
msgid "Error"
|
||||
msgstr "錯誤"
|
||||
|
||||
@ -463,9 +472,6 @@ msgstr "Z軸歸零"
|
||||
msgid "Host"
|
||||
msgstr "主機"
|
||||
|
||||
msgid "Hostname"
|
||||
msgstr "主機名"
|
||||
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
@ -508,6 +514,18 @@ msgstr "設置文件可能存在錯誤"
|
||||
msgid "Job Status"
|
||||
msgstr "工作狀態"
|
||||
|
||||
msgid "Key is empty"
|
||||
msgstr "密鑰為空"
|
||||
|
||||
msgid "Key is invalid"
|
||||
msgstr "密鑰無效"
|
||||
|
||||
msgid "Key is valid"
|
||||
msgstr "密鑰有效"
|
||||
|
||||
msgid "Key:"
|
||||
msgstr "密鑰:"
|
||||
|
||||
msgid "Klipper Restart"
|
||||
msgstr "重啟Klipper"
|
||||
|
||||
@ -560,6 +578,9 @@ msgstr "剩餘時間:"
|
||||
msgid "Leveling only in the actual print area"
|
||||
msgstr "僅在實際打印區域進行床調平"
|
||||
|
||||
msgid "License key"
|
||||
msgstr "許可證密鑰"
|
||||
|
||||
msgid "Limits"
|
||||
msgstr "列印機限制"
|
||||
|
||||
@ -683,6 +704,9 @@ msgstr "未啟用"
|
||||
msgid "Not Inserted"
|
||||
msgstr "未裝載"
|
||||
|
||||
msgid "Not activated"
|
||||
msgstr "未激活"
|
||||
|
||||
msgid "Not all screens support this"
|
||||
msgstr "不一定所有屏幕都支持這項功能"
|
||||
|
||||
@ -745,12 +769,18 @@ msgstr "已暫停"
|
||||
msgid "Perform a full upgrade?"
|
||||
msgstr "是否全部升級?"
|
||||
|
||||
msgid "Permanent Activation"
|
||||
msgstr "永久激活"
|
||||
|
||||
msgid "Pins"
|
||||
msgstr "引腳"
|
||||
|
||||
msgid "Please ensure that the Probe Calibrate has been performed"
|
||||
msgstr "請確保已完成探針偏移校準"
|
||||
|
||||
msgid "Please enter a key to activate"
|
||||
msgstr "請輸入密鑰激活"
|
||||
|
||||
msgid "Please enter a valid number"
|
||||
msgstr "請輸入有效的數字"
|
||||
|
||||
@ -835,6 +865,9 @@ msgstr "參考"
|
||||
msgid "Refresh"
|
||||
msgstr "重新整理"
|
||||
|
||||
msgid "Remaining Time:"
|
||||
msgstr "剩余時間:"
|
||||
|
||||
msgid "Remove network"
|
||||
msgstr "刪除網絡"
|
||||
|
||||
@ -844,6 +877,12 @@ msgstr "重新命名/移動:"
|
||||
msgid "Reprint"
|
||||
msgstr "再次打印"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "重置"
|
||||
|
||||
msgid "Reset successfully"
|
||||
msgstr "重置成功"
|
||||
|
||||
msgid "Restart"
|
||||
msgstr "重啟"
|
||||
|
||||
@ -923,6 +962,9 @@ msgstr "選擇型號"
|
||||
msgid "Send"
|
||||
msgstr "發送"
|
||||
|
||||
msgid "Serial Number:"
|
||||
msgstr "序列號"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
@ -944,6 +986,9 @@ msgstr "散熱風扇"
|
||||
msgid "Size"
|
||||
msgstr "大小"
|
||||
|
||||
msgid "Skip"
|
||||
msgstr "跳過"
|
||||
|
||||
msgid "Slicer"
|
||||
msgstr "切片軟體"
|
||||
|
||||
@ -983,15 +1028,15 @@ msgstr "開始"
|
||||
msgid "Start testing the Z offset value of the second nozzle?\n"
|
||||
msgstr "開始測試第二個噴嘴的 Z 偏移值嗎?\n"
|
||||
|
||||
msgid "Starting WiFi Association"
|
||||
msgstr "開始WiFi連線"
|
||||
|
||||
msgid "Starting recovery for"
|
||||
msgstr "開始恢復"
|
||||
|
||||
msgid "Starting update for"
|
||||
msgstr "開始更新"
|
||||
|
||||
msgid "State:"
|
||||
msgstr "狀態:"
|
||||
|
||||
msgid "System"
|
||||
msgstr "系統"
|
||||
|
||||
@ -1019,6 +1064,9 @@ msgstr ""
|
||||
msgid "The system will reboot!"
|
||||
msgstr "系統將重新啟動!"
|
||||
|
||||
msgid "This device is not activated and is available for trial use only"
|
||||
msgstr "此設備尚未激活,僅供試用"
|
||||
|
||||
msgid "This operation is about to print the model"
|
||||
msgstr "此操作即將開始打印模型"
|
||||
|
||||
@ -1037,6 +1085,15 @@ msgstr "打印過程中超過倒計時後關閉屏幕"
|
||||
msgid "Total:"
|
||||
msgstr "合計:"
|
||||
|
||||
msgid "Trial"
|
||||
msgstr "試用"
|
||||
|
||||
msgid "Trial Time:"
|
||||
msgstr "試用時間:"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "Unknown Heater"
|
||||
msgstr "未知加熱器"
|
||||
|
||||
@ -1136,6 +1193,9 @@ msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] "小時"
|
||||
|
||||
msgid "license"
|
||||
msgstr "許可證"
|
||||
|
||||
msgid "macros that use 'rename_existing' are hidden"
|
||||
msgstr "使用\"rename_existing\"的宏將被隱藏"
|
||||
|
||||
@ -1168,6 +1228,15 @@ msgid "second"
|
||||
msgid_plural "seconds"
|
||||
msgstr[0] "秒"
|
||||
|
||||
#~ msgid "Connected"
|
||||
#~ msgstr "已連線"
|
||||
|
||||
#~ msgid "Hostname"
|
||||
#~ msgstr "主機名"
|
||||
|
||||
#~ msgid "Starting WiFi Association"
|
||||
#~ msgstr "開始WiFi連線"
|
||||
|
||||
#~ msgid "Restoring Left extruder temperature, this may take some time"
|
||||
#~ msgstr "恢復左擠出機溫度,這可能需要一些時間"
|
||||
|
||||
@ -1216,9 +1285,6 @@ msgstr[0] "秒"
|
||||
#~ msgid "Hidden"
|
||||
#~ msgstr "隱藏的"
|
||||
|
||||
#~ msgid "Print Time"
|
||||
#~ msgstr "列印時間"
|
||||
|
||||
#~ msgid "dBm"
|
||||
#~ msgstr "dBm"
|
||||
|
||||
@ -1390,6 +1456,3 @@ msgstr[0] "秒"
|
||||
|
||||
#~ msgid "Load Average"
|
||||
#~ msgstr "平均负载"
|
||||
|
||||
#~ msgid "Screen Blanking Time"
|
||||
#~ msgstr "关闭屏幕时间"
|
||||
|
@ -230,6 +230,10 @@ class SdbusNm:
|
||||
else None
|
||||
)
|
||||
|
||||
def get_signal_strength(self):
|
||||
ap = self.get_connected_ap()
|
||||
return ap.strength if ap else None
|
||||
|
||||
def get_security_type(self, ssid):
|
||||
return next(
|
||||
(
|
||||
|
165
ks_includes/sdbus_reg.py
Normal file
165
ks_includes/sdbus_reg.py
Normal file
@ -0,0 +1,165 @@
|
||||
from asyncio import new_event_loop, run_coroutine_threadsafe
|
||||
from threading import Thread
|
||||
import ast
|
||||
import logging
|
||||
from typing import Optional
|
||||
from sdbus import DbusInterfaceCommonAsync, dbus_method_async, dbus_property_async
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RegistrationInterface(DbusInterfaceCommonAsync, interface_name="org.registration.interface"):
|
||||
|
||||
def __init__(self, bus_name: str, object_path: str):
|
||||
super().__init__()
|
||||
self.proxy = self.new_proxy(bus_name, object_path)
|
||||
|
||||
@dbus_property_async(property_signature="s")
|
||||
def get_unique_id(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_property_async(property_signature="a{sv}")
|
||||
def get_time_info(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_property_async(property_signature="b")
|
||||
def is_active(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_property_async(property_signature="b")
|
||||
def is_trial_active(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_method_async(input_signature="s", result_signature="b")
|
||||
async def verify_activation_code(self, val: str) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_method_async(input_signature="s", result_signature="b")
|
||||
async def reset_registration(self, val: str) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@dbus_property_async(property_signature="b")
|
||||
def enabled_registration(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LicenseManager:
|
||||
|
||||
def __init__(self, bus_name: str = "org.registration.link", object_path: str = "/"):
|
||||
self.loop = new_event_loop()
|
||||
self.registration_interface: Optional[RegistrationInterface] = None
|
||||
self.interface_valid = False
|
||||
self._thread: Optional[Thread] = None
|
||||
self.callback = None
|
||||
|
||||
try:
|
||||
self.registration_interface = RegistrationInterface(bus_name, object_path)
|
||||
self.interface_valid = True
|
||||
logger.info("DBus connection established successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize DBus connection: {e}")
|
||||
self._cleanup_resources()
|
||||
return
|
||||
|
||||
self._thread = Thread(target=self._run_loop, daemon=True)
|
||||
self._thread.start()
|
||||
|
||||
def _run_loop(self) -> None:
|
||||
try:
|
||||
self.loop.run_forever()
|
||||
finally:
|
||||
self.loop.close()
|
||||
|
||||
def _cleanup_resources(self) -> None:
|
||||
if self.loop.is_running():
|
||||
self.loop.call_soon_threadsafe(self.loop.stop)
|
||||
if self._thread and self._thread.is_alive():
|
||||
self._thread.join(timeout=1)
|
||||
self.loop.close()
|
||||
|
||||
def is_interface_valid(self) -> bool:
|
||||
return self.interface_valid
|
||||
|
||||
def _async_call(self, coroutine_func, default=None):
|
||||
if not self.is_interface_valid():
|
||||
logger.warning("Attempting to use invalid DBus interface")
|
||||
return default
|
||||
|
||||
try:
|
||||
future = run_coroutine_threadsafe(coroutine_func(), self.loop)
|
||||
return future.result()
|
||||
except Exception as e:
|
||||
logger.error(f"DBus operation failed: {e}")
|
||||
self.interface_valid = False
|
||||
return default
|
||||
|
||||
def get_unique_id(self) -> str:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.get_unique_id
|
||||
|
||||
return self._async_call(_get, default="")
|
||||
|
||||
def get_trial_time(self) -> int:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.get_time_info
|
||||
|
||||
result = self._async_call(_get, default="{}")
|
||||
try:
|
||||
data_dict = ast.literal_eval(result)
|
||||
return data_dict.get("trial_time", 0)
|
||||
except Exception as e:
|
||||
logger.error(f"Parse time info failed: {e}")
|
||||
return 0
|
||||
|
||||
def get_total_printed_time(self) -> int:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.get_time_info
|
||||
|
||||
result = self._async_call(_get, default="{}")
|
||||
try:
|
||||
data_dict = ast.literal_eval(result)
|
||||
return int(data_dict.get("total_printed_time", 0))
|
||||
except Exception as e:
|
||||
logger.error(f"Parse time info failed: {e}")
|
||||
return 0
|
||||
|
||||
def is_active(self) -> bool:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.is_active
|
||||
|
||||
return self._async_call(_get, default=False)
|
||||
|
||||
def is_trial_active(self) -> bool:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.is_trial_active
|
||||
|
||||
return self._async_call(_get, default=False)
|
||||
|
||||
def is_time_sufficient(self, required_seconds: int = 40 * 3600) -> bool:
|
||||
trial_time = self.get_trial_time()
|
||||
printed_time = self.get_total_printed_time()
|
||||
return (trial_time - printed_time) > required_seconds
|
||||
|
||||
def verify_activation_code(self, code: str) -> bool:
|
||||
async def _verify():
|
||||
return await self.registration_interface.proxy.verify_activation_code(code)
|
||||
|
||||
return self._async_call(_verify, default=False)
|
||||
|
||||
def reset_registration(self, code: str) -> bool:
|
||||
async def _reset():
|
||||
return await self.registration_interface.proxy.reset_registration(code)
|
||||
|
||||
return self._async_call(_reset, default=False)
|
||||
|
||||
def enabled_registration(self) -> bool:
|
||||
async def _get():
|
||||
return await self.registration_interface.proxy.enabled_registration
|
||||
|
||||
return self._async_call(_get, default=False)
|
||||
|
||||
def close(self) -> None:
|
||||
if self.is_interface_valid():
|
||||
logger.info("Closing DBus connection...")
|
||||
self._cleanup_resources()
|
||||
self.interface_valid = False
|
@ -8,6 +8,7 @@ from gi.repository import GLib, Gtk, Pango
|
||||
from jinja2 import Environment
|
||||
from datetime import datetime
|
||||
from math import log
|
||||
from ks_includes.sdbus_nm import SdbusNm
|
||||
from ks_includes.screen_panel import ScreenPanel
|
||||
|
||||
|
||||
@ -18,11 +19,37 @@ class BasePanel(ScreenPanel):
|
||||
self.time_min = -1
|
||||
self.time_format = self._config.get_main_config().getboolean("24htime", True)
|
||||
self.time_update = None
|
||||
self.network_update = None
|
||||
self.titlebar_items = []
|
||||
self.titlebar_name_type = None
|
||||
self.current_extruder = None
|
||||
self.last_usage_report = datetime.now()
|
||||
self.usage_report = 0
|
||||
|
||||
icon_size_width = self._gtk.content_width * 0.05
|
||||
icon_size_height = self._gtk.content_height * 0.05
|
||||
|
||||
network_icons_map = {
|
||||
"excellent": "wifi_excellent",
|
||||
"good": "wifi_good",
|
||||
"fair": "wifi_fair",
|
||||
"weak": "wifi_weak",
|
||||
"ethernet": "ethernet",
|
||||
}
|
||||
|
||||
|
||||
self.network_icons = {
|
||||
key: self._gtk.PixbufFromIcon(value, width=icon_size_width, height=icon_size_height)
|
||||
for key, value in network_icons_map.items()
|
||||
}
|
||||
|
||||
try:
|
||||
self.sdbus_nm = SdbusNm(self.network_interface_refresh)
|
||||
except Exception as e:
|
||||
logging.exception("Failed to initialize SdbusNm: %s", e)
|
||||
self.sdbus_nm = None
|
||||
|
||||
|
||||
# Action bar buttons
|
||||
abscale = self.bts * 1.1
|
||||
self.control['back'] = self._gtk.Button('back', scale=abscale)
|
||||
@ -100,6 +127,26 @@ class BasePanel(ScreenPanel):
|
||||
|
||||
self.titlelbl = Gtk.Label(hexpand=True, halign=Gtk.Align.CENTER, ellipsize=Pango.EllipsizeMode.END)
|
||||
|
||||
if self._screen.license.is_interface_valid() and not self._screen.license.is_active():
|
||||
img_size = self._gtk.img_scale * self.bts
|
||||
self.control["license"] = self._gtk.Image("license", img_size, img_size)
|
||||
license_eventbox = Gtk.EventBox()
|
||||
license_eventbox.add(self.control["license"])
|
||||
license_eventbox.connect("button-press-event", self.show_license_key_page)
|
||||
self.control["license_box"] = Gtk.Box(halign=Gtk.Align.END)
|
||||
self.control["license_box"].pack_end(license_eventbox, True, True, 5)
|
||||
|
||||
if self.sdbus_nm:
|
||||
img_size = self._gtk.img_scale * self.bts
|
||||
self.control["network_ico"] = self._gtk.Image("wifi_excellent", img_size, img_size)
|
||||
network_eventbox = Gtk.EventBox()
|
||||
network_eventbox.add(self.control["network_ico"])
|
||||
network_eventbox.connect("button-press-event", self.show_network_page)
|
||||
self.control["network_box"] = Gtk.Box(halign=Gtk.Align.END)
|
||||
self.control["network_box"].pack_end(network_eventbox, True, True, 5)
|
||||
self.control["network_ico"].set_no_show_all(True)
|
||||
self.control["network_ico"].set_visible(False)
|
||||
|
||||
self.control['time'] = Gtk.Label(label="00:00 AM")
|
||||
self.control['time_box'] = Gtk.Box(halign=Gtk.Align.END)
|
||||
self.control['time_box'].pack_end(self.control['time'], True, True, 10)
|
||||
@ -108,6 +155,10 @@ class BasePanel(ScreenPanel):
|
||||
self.titlebar.get_style_context().add_class("title_bar")
|
||||
self.titlebar.add(self.control['temp_box'])
|
||||
self.titlebar.add(self.titlelbl)
|
||||
if self._screen.license.is_interface_valid() and not self._screen.license.is_active():
|
||||
self.titlebar.add(self.control["license_box"])
|
||||
if self.sdbus_nm:
|
||||
self.titlebar.add(self.control["network_box"])
|
||||
self.titlebar.add(self.control['time_box'])
|
||||
self.set_title(title)
|
||||
|
||||
@ -127,6 +178,14 @@ class BasePanel(ScreenPanel):
|
||||
|
||||
self.update_time()
|
||||
|
||||
def show_license_key_page(self, widget, event):
|
||||
if "license" not in self._screen._cur_panels:
|
||||
self._screen.show_panel("license", remove_all=False)
|
||||
|
||||
def show_network_page(self, widget, event):
|
||||
if "network" not in self._screen._cur_panels:
|
||||
self._screen.show_panel("network", remove_all=False)
|
||||
|
||||
def reload_icons(self):
|
||||
button: Gtk.Button
|
||||
for button in self.action_bar.get_children():
|
||||
@ -212,6 +271,8 @@ class BasePanel(ScreenPanel):
|
||||
def activate(self):
|
||||
if self.time_update is None:
|
||||
self.time_update = GLib.timeout_add_seconds(1, self.update_time)
|
||||
if self.sdbus_nm and self.network_update is None:
|
||||
self.network_update = GLib.timeout_add_seconds(5, self.network_interface_refresh)
|
||||
|
||||
def add_content(self, panel):
|
||||
printing = self._printer and self._printer.state in {"printing", "paused"}
|
||||
@ -381,6 +442,35 @@ class BasePanel(ScreenPanel):
|
||||
self.time_format = confopt
|
||||
return True
|
||||
|
||||
def network_interface_refresh(self, msg=None, level=3):
|
||||
if self.sdbus_nm:
|
||||
self.interface = self.sdbus_nm.get_primary_interface()
|
||||
if self.interface:
|
||||
if '?' not in self.sdbus_nm.get_ip_address():
|
||||
if self.interface == "eth0":
|
||||
self.control["network_ico"].set_from_pixbuf(self.network_icons["ethernet"])
|
||||
self.control["network_ico"].set_visible(True)
|
||||
elif self.interface == "wlan0":
|
||||
strength = self.sdbus_nm.get_signal_strength()
|
||||
if strength:
|
||||
self.control["network_ico"].set_from_pixbuf(self.get_signal_strength_icon(strength))
|
||||
self.control["network_ico"].set_visible(True)
|
||||
else:
|
||||
self.control["network_ico"].set_visible(False)
|
||||
else:
|
||||
self.control["network_ico"].set_visible(False)
|
||||
return True
|
||||
|
||||
def get_signal_strength_icon(self, signal_level):
|
||||
if signal_level > 75:
|
||||
return self.network_icons["excellent"]
|
||||
elif signal_level > 60:
|
||||
return self.network_icons["good"]
|
||||
elif signal_level > 30:
|
||||
return self.network_icons["fair"]
|
||||
else:
|
||||
return self.network_icons["weak"]
|
||||
|
||||
def set_ks_printer_cfg(self, printer):
|
||||
ScreenPanel.ks_printer_cfg = self._config.get_printer_config(printer)
|
||||
if self.ks_printer_cfg is not None:
|
||||
|
@ -37,6 +37,14 @@ class Panel(ScreenPanel):
|
||||
"callback": self.reset_factory_settings,
|
||||
}
|
||||
},
|
||||
{
|
||||
"License key": {
|
||||
"section": "main",
|
||||
"name": _("License key"),
|
||||
"type": "button",
|
||||
"callback": self.license_key,
|
||||
}
|
||||
},
|
||||
{
|
||||
"version_info": {
|
||||
"section": "main",
|
||||
@ -132,19 +140,47 @@ class Panel(ScreenPanel):
|
||||
self.content.show_all()
|
||||
self.select_model = False
|
||||
|
||||
def license_key(self, *args):
|
||||
self._screen.show_panel("license", title="license", remove_all=False, full=True)
|
||||
|
||||
def reset_factory_settings(self, *args):
|
||||
text = _("Are you sure?\n") + "\n\n" + _("The system will reboot!")
|
||||
label = Gtk.Label(wrap=True, vexpand=True)
|
||||
label.set_markup(text)
|
||||
buttons = [
|
||||
{"name": _("Accept"), "response": Gtk.ResponseType.OK, "style": "dialog-error"},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": "dialog-info"},
|
||||
]
|
||||
self._gtk.Dialog(_("factory settings"), buttons, label, self.confirm_factory_reset_production)
|
||||
|
||||
text = _("Are you sure?\n") + "\n\n" + _("The system will reboot!")
|
||||
label = Gtk.Label(wrap=True, vexpand=True)
|
||||
label.set_markup(text)
|
||||
label.set_margin_top(100)
|
||||
|
||||
def confirm_factory_reset_production(self, dialog, response_id):
|
||||
checkbox = Gtk.CheckButton(label=" " + _("Enable Registration Code"))
|
||||
checkbox.set_halign(Gtk.Align.CENTER)
|
||||
checkbox.set_valign(Gtk.Align.CENTER)
|
||||
|
||||
|
||||
grid = Gtk.Grid(row_homogeneous=True, column_homogeneous=True)
|
||||
grid.set_row_spacing(20)
|
||||
grid.set_column_spacing(0)
|
||||
grid.attach(label, 0, 0, 1, 1)
|
||||
if self._screen.license.is_interface_valid() and self._screen.license.is_active():
|
||||
grid.attach(checkbox, 0, 1, 1, 1)
|
||||
|
||||
self._gtk.Dialog(
|
||||
_("factory settings"),
|
||||
buttons,
|
||||
grid,
|
||||
self.confirm_factory_reset_production,
|
||||
checkbox,
|
||||
)
|
||||
|
||||
|
||||
def confirm_factory_reset_production(self, dialog, response_id, checkbox):
|
||||
self._gtk.remove_dialog(dialog)
|
||||
if response_id == Gtk.ResponseType.OK:
|
||||
if checkbox.get_active():
|
||||
if self._screen.license.is_interface_valid():
|
||||
self._screen.license.enabled_registration()
|
||||
KlippyFactory.production_factory_reset(self._screen._ws.klippy, self._config)
|
||||
|
||||
def version_selection(self, val):
|
||||
|
@ -341,6 +341,17 @@ class Panel(ScreenPanel):
|
||||
def confirm_print_response(self, dialog, response_id, filename):
|
||||
self._gtk.remove_dialog(dialog)
|
||||
if response_id == Gtk.ResponseType.OK:
|
||||
if self._screen.license.is_interface_valid() and not self._screen.license.is_active():
|
||||
if not self._screen.license.is_time_sufficient():
|
||||
if "license" not in self._screen._cur_panels:
|
||||
self._screen.show_panel(
|
||||
"license",
|
||||
title="license",
|
||||
remove_all=False,
|
||||
func=self._screen._ws.klippy.print_start,
|
||||
file=filename,
|
||||
)
|
||||
return
|
||||
logging.info(f"Starting print: {filename}")
|
||||
self._screen._ws.klippy.print_start(filename)
|
||||
|
||||
|
234
panels/license.py
Normal file
234
panels/license.py
Normal file
@ -0,0 +1,234 @@
|
||||
import logging
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Pango
|
||||
from ks_includes.screen_panel import ScreenPanel
|
||||
|
||||
|
||||
class Panel(ScreenPanel):
|
||||
|
||||
def __init__(self, screen, title, **kwargs):
|
||||
title = title or _("license")
|
||||
super().__init__(screen, title)
|
||||
self.title_text = (
|
||||
_("This device is not activated and is available for trial use only")
|
||||
+ "\n"
|
||||
+ _("Please enter a key to activate")
|
||||
)
|
||||
self.key_len = 15
|
||||
self.full = False
|
||||
self.interface = screen.license
|
||||
self.serial_num = self.interface.get_unique_id() or _("Unknown")
|
||||
self.is_active = self.interface.is_active()
|
||||
self.args = {}
|
||||
|
||||
def update_time(self):
|
||||
total_printed_time = max(0, self.interface.get_total_printed_time())
|
||||
trial_time = max(0, self.interface.get_trial_time())
|
||||
remaining_time = max(0, trial_time - total_printed_time)
|
||||
|
||||
self.license_box["elapsed_trial_time_value"].set_text(self.seconds_to_hms(total_printed_time))
|
||||
self.license_box["trial_time_value"].set_text(self.seconds_to_hms(trial_time))
|
||||
self.license_box["remain_time_value"].set_text(self.seconds_to_hms(remaining_time))
|
||||
|
||||
def seconds_to_hms(self, seconds):
|
||||
|
||||
if not isinstance(seconds, (int, float)) or seconds < 0:
|
||||
raise ValueError(f"seconds must be a non-negative number, got {seconds}")
|
||||
|
||||
hours, remainder = divmod(int(seconds), 3600)
|
||||
minutes, secs = divmod(remainder, 60)
|
||||
|
||||
return f"{hours:03}:{minutes:02}:{secs:02}"
|
||||
|
||||
def state_update(self, text):
|
||||
self.license_box["state_text_value"].set_text(text)
|
||||
|
||||
def verify_key(self, key):
|
||||
try:
|
||||
res = self.interface.verify_activation_code(key)
|
||||
if res:
|
||||
if self.interface.is_active():
|
||||
self.is_active = True
|
||||
self.state_update(_("Permanent Activation"))
|
||||
else:
|
||||
self.state_update(_("Key is valid"))
|
||||
else:
|
||||
self.state_update(_("Key is invalid"))
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
|
||||
def active_refresh(self, **args):
|
||||
self.args["full"] = args.get("full")
|
||||
self.args["callback"] = args.get("func")
|
||||
self.args["file"] = args.get("file")
|
||||
self.args["onboarding"] = args.get("onboarding")
|
||||
self.display_dialog()
|
||||
|
||||
def deactivate(self):
|
||||
self._screen.remove_keyboard()
|
||||
for child in self.content.get_children():
|
||||
self.content.remove(child)
|
||||
|
||||
def display_dialog(self, full=False, key=""):
|
||||
BUTTON_CONFIGS = {
|
||||
"trial_with_callback": [
|
||||
{"name": _("Activate"), "response": Gtk.ResponseType.OK, "style": "dialog-info"},
|
||||
{"name": _("Skip"), "response": Gtk.ResponseType.CANCEL, "style": "dialog-error"},
|
||||
],
|
||||
"full_features": [
|
||||
{"name": _("Reset"), "response": Gtk.ResponseType.APPLY, "style": "dialog-secondary"},
|
||||
{"name": _("Activate"), "response": Gtk.ResponseType.OK, "style": "dialog-info"},
|
||||
{"name": _("Close"), "response": Gtk.ResponseType.CLOSE, "style": "dialog-error"},
|
||||
],
|
||||
"Trial": [
|
||||
{"name": _("Activate"), "response": Gtk.ResponseType.OK, "style": "dialog-info"},
|
||||
{"name": _("Trial"), "response": Gtk.ResponseType.CLOSE, "style": "dialog-error"},
|
||||
],
|
||||
"default": [
|
||||
{"name": _("Activate"), "response": Gtk.ResponseType.OK, "style": "dialog-info"},
|
||||
{"name": _("Close"), "response": Gtk.ResponseType.CLOSE, "style": "dialog-error"},
|
||||
],
|
||||
}
|
||||
|
||||
if self.args.get("callback") and self.interface.is_trial_active():
|
||||
buttons = BUTTON_CONFIGS["trial_with_callback"]
|
||||
elif self.args.get("full"):
|
||||
buttons = BUTTON_CONFIGS["full_features"]
|
||||
elif self.args.get("onboarding"):
|
||||
buttons = BUTTON_CONFIGS["Trial"]
|
||||
else:
|
||||
buttons = BUTTON_CONFIGS["default"]
|
||||
|
||||
self.create_license_key_dialog(buttons=buttons, key=key)
|
||||
|
||||
def create_license_key_dialog(self, buttons=None, key=""):
|
||||
|
||||
if buttons is None:
|
||||
buttons = [
|
||||
{"name": _("Activate"), "response": Gtk.ResponseType.OK, "style": "dialog-info"},
|
||||
{"name": _("Close"), "response": Gtk.ResponseType.CLOSE, "style": "dialog-error"},
|
||||
]
|
||||
|
||||
self.title_label = Gtk.Label(hexpand=True, vexpand=False, wrap=True, wrap_mode=Pango.WrapMode.WORD_CHAR)
|
||||
self.title_label.set_markup(f"<big>{self.title_text}</big>\n")
|
||||
self.title_label.set_margin_top(50)
|
||||
self.title_label.set_margin_start(20)
|
||||
self.title_label.set_halign(Gtk.Align.START)
|
||||
|
||||
self.license_box = {}
|
||||
|
||||
self.grid = Gtk.Grid(column_spacing=20, row_spacing=20, hexpand=True, vexpand=True)
|
||||
|
||||
def add_labeled_value(row, label_text, value_text):
|
||||
label = Gtk.Label(label=label_text, use_markup=True, xalign=0, wrap=True)
|
||||
value = Gtk.Label(label=value_text, use_markup=True, xalign=0, wrap=True)
|
||||
self.grid.attach(label, 0, row, 1, 1)
|
||||
self.grid.attach(value, 1, row, 1, 1)
|
||||
return label, value
|
||||
|
||||
status_text = _("Not activated")
|
||||
if not self.interface.is_interface_valid():
|
||||
status_text = _("Unknown")
|
||||
elif self.is_active:
|
||||
status_text = _("Permanent Activation")
|
||||
self.license_box["state_text"], self.license_box["state_text_value"] = add_labeled_value(
|
||||
0, _("State:"), status_text
|
||||
)
|
||||
self.license_box["serial_num_text"], self.license_box["serial_num_value"] = add_labeled_value(
|
||||
1, _("Serial Number:"), self.serial_num
|
||||
)
|
||||
self.license_box["trial_time_text"], self.license_box["trial_time_value"] = add_labeled_value(
|
||||
2, _("Trial Time:"), "000:00:00"
|
||||
)
|
||||
self.license_box["elapsed_trial_time_text"], self.license_box["elapsed_trial_time_value"] = add_labeled_value(
|
||||
3, _("Elapsed trial time:"), "000:00:00"
|
||||
)
|
||||
self.license_box["remain_time_text"], self.license_box["remain_time_value"] = add_labeled_value(
|
||||
4, _("Remaining Time:"), "000:00:00"
|
||||
)
|
||||
|
||||
self.license_box["key_text"] = Gtk.Label(label=_("Key:"), use_markup=True, xalign=0, wrap=True)
|
||||
self.grid.attach(self.license_box["key_text"], 0, 5, 1, 1)
|
||||
|
||||
self.license_box["key_input"] = Gtk.Entry(hexpand=False, vexpand=False)
|
||||
self.license_box["key_input"].set_max_length(self.key_len)
|
||||
self.license_box["key_input"].set_text(key)
|
||||
self.license_box["key_input"].connect("button-press-event", self.on_show_keyboard)
|
||||
self.grid.attach(self.license_box["key_input"], 1, 5, 1, 1)
|
||||
|
||||
image = self._gtk.Image("license", self._gtk.content_width * 0.4, self._gtk.content_height * 0.4)
|
||||
image.set_margin_start(60)
|
||||
image.set_margin_end(20)
|
||||
|
||||
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, vexpand=True)
|
||||
horizontal_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, vexpand=True)
|
||||
horizontal_box.set_margin_top(20)
|
||||
|
||||
self.grid.set_margin_start(60)
|
||||
horizontal_box.pack_start(image, False, True, 0)
|
||||
horizontal_box.pack_start(self.grid, True, True, 0)
|
||||
|
||||
main_box.pack_start(self.title_label, False, True, 0)
|
||||
main_box.pack_start(horizontal_box, True, True, 0)
|
||||
|
||||
self.dialog = self._gtk.Dialog("License", buttons, main_box, self.confirm_license_response)
|
||||
self.update_time()
|
||||
|
||||
def confirm_license_response(self, dialog, response_id):
|
||||
if response_id == Gtk.ResponseType.YES:
|
||||
if self.interface.enabled_registration():
|
||||
self.state_update(_("Enabled successfully"))
|
||||
elif response_id == Gtk.ResponseType.APPLY:
|
||||
if len(self.license_box["key_input"].get_text()) == 0:
|
||||
self.state_update(_("Key is empty"))
|
||||
return
|
||||
else:
|
||||
if self.interface.reset_registration(self.license_box["key_input"].get_text()):
|
||||
self.update_time()
|
||||
self.state_update(_("Reset successfully"))
|
||||
else:
|
||||
self.state_update(_("Key is invalid"))
|
||||
elif response_id == Gtk.ResponseType.CLOSE:
|
||||
self._gtk.remove_dialog(dialog)
|
||||
self._screen._menu_go_back()
|
||||
elif response_id == Gtk.ResponseType.CANCEL:
|
||||
self._gtk.remove_dialog(dialog)
|
||||
self._screen._menu_go_back()
|
||||
if not self.interface.is_active() and self.interface.is_trial_active():
|
||||
if self.args.get("callback"):
|
||||
self.args["callback"](self.args["file"])
|
||||
elif response_id == Gtk.ResponseType.OK:
|
||||
if len(self.license_box["key_input"].get_text()) == 0:
|
||||
self.state_update(_("Key is empty"))
|
||||
return
|
||||
self.verify_key(self.license_box["key_input"].get_text())
|
||||
self.update_time()
|
||||
|
||||
def on_show_keyboard(self, entry=None, event=None):
|
||||
self._gtk.remove_dialog(self.dialog)
|
||||
lbl = Gtk.Label(_("Please enter a key to activate"), halign=Gtk.Align.START, hexpand=False)
|
||||
self.labels["entry"] = Gtk.Entry(hexpand=True)
|
||||
self.labels["entry"].set_max_length(self.key_len)
|
||||
self.labels["entry"].connect("focus-in-event", self._screen.show_keyboard)
|
||||
save = self._gtk.Button("complete", _("Save"), "color3")
|
||||
save.set_hexpand(False)
|
||||
save.connect("clicked", self.on_save_key)
|
||||
input_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
|
||||
input_box.pack_start(self.labels["entry"], True, True, 5)
|
||||
input_box.pack_start(save, False, False, 5)
|
||||
self.labels["input_box"] = Gtk.Box(
|
||||
orientation=Gtk.Orientation.VERTICAL, spacing=5, hexpand=True, vexpand=True, valign=Gtk.Align.CENTER
|
||||
)
|
||||
self.labels["input_box"].pack_start(lbl, True, True, 5)
|
||||
self.labels["input_box"].pack_start(input_box, True, True, 5)
|
||||
self.content.add(self.labels["input_box"])
|
||||
self.labels["entry"].grab_focus_without_selecting()
|
||||
|
||||
def on_save_key(self, dialog):
|
||||
key_text = self.labels["entry"].get_text()
|
||||
self._screen.remove_keyboard()
|
||||
for child in self.content.get_children():
|
||||
self.content.remove(child)
|
||||
self.display_dialog(self.full, key=key_text)
|
@ -77,9 +77,7 @@ class Panel(ScreenPanel):
|
||||
|
||||
self.labels['interface'] = Gtk.Label(hexpand=True)
|
||||
self.labels['ip'] = Gtk.Label(hexpand=True)
|
||||
if self.interface is not None:
|
||||
self.labels['interface'].set_text(_("Interface") + f': {self.interface}')
|
||||
self.labels['ip'].set_text(f"IP: {self.sdbus_nm.get_ip_address()}")
|
||||
self.network_interface_refresh()
|
||||
|
||||
self.reload_button = self._gtk.Button("refresh", None, "custom-icon-button", self.bts)
|
||||
self.reload_button.set_no_show_all(True)
|
||||
@ -120,6 +118,7 @@ class Panel(ScreenPanel):
|
||||
self.network_list.connect("row-activated", self.handle_wifi_selection)
|
||||
|
||||
def popup_callback(self, msg, level=3):
|
||||
self.network_interface_refresh()
|
||||
if not self.refresh_status(msg):
|
||||
for item in self.network_rows:
|
||||
if self.network_rows[item]["label_state"] is not None:
|
||||
@ -127,6 +126,12 @@ class Panel(ScreenPanel):
|
||||
self.network_rows[item]["label_state"].hide()
|
||||
self._screen.show_popup_message(msg, level)
|
||||
|
||||
def network_interface_refresh(self):
|
||||
if self.interface is not None:
|
||||
self.interface = self.sdbus_nm.get_primary_interface()
|
||||
self.labels['interface'].set_text(_("Interface") + f': {self.interface}')
|
||||
self.labels['ip'].set_text(f"IP: {self.sdbus_nm.get_ip_address()}")
|
||||
|
||||
def handle_wifi_selection(self, list_box, row):
|
||||
index = row.get_index()
|
||||
logging.info(f"clicked SSID is {self.networks[index]['SSID']}")
|
||||
@ -407,6 +412,7 @@ class Panel(ScreenPanel):
|
||||
if self.delay_reload_timer_id:
|
||||
GLib.source_remove(self.delay_reload_timer_id)
|
||||
self.delay_reload_timer_id = None
|
||||
self.network_interface_refresh()
|
||||
|
||||
return self.sdbus_nm.nm.wireless_enabled
|
||||
|
||||
@ -438,7 +444,7 @@ class Panel(ScreenPanel):
|
||||
return
|
||||
if self.sdbus_nm.wifi:
|
||||
if self.sdbus_nm.is_wifi_enabled():
|
||||
self.delay_reload_networks(1000)
|
||||
self.delay_reload_networks(2000)
|
||||
self.start_refresh_timer()
|
||||
|
||||
def deactivate(self):
|
||||
@ -464,3 +470,4 @@ class Panel(ScreenPanel):
|
||||
self.reload_button.hide()
|
||||
self.network_list.set_no_show_all(True)
|
||||
self.network_list.hide()
|
||||
self.network_interface_refresh()
|
@ -67,3 +67,6 @@ class Panel(ScreenPanel):
|
||||
self._screen.show_panel("main_menu", remove_all=True, items=self._config.get_menu_items("__main"))
|
||||
self._config.set("main", "onboarding", "False")
|
||||
self._config.save_user_config_options()
|
||||
if self._screen.license.is_interface_valid() and not self._screen.license.is_active():
|
||||
self._gtk.remove_dialog(dialog)
|
||||
self._screen.show_panel("license", remove_all=False, onboarding=True)
|
||||
|
@ -28,6 +28,7 @@ from ks_includes.printer import Printer
|
||||
from ks_includes.widgets.keyboard import Keyboard
|
||||
from ks_includes.widgets.prompts import Prompt
|
||||
from ks_includes.config import KlipperScreenConfig
|
||||
from ks_includes.sdbus_reg import LicenseManager
|
||||
from panels.base_panel import BasePanel
|
||||
|
||||
logging.getLogger("urllib3").setLevel(logging.WARNING)
|
||||
@ -89,6 +90,8 @@ class KlipperScreen(Gtk.Window):
|
||||
self.confirm = None
|
||||
self.panels_reinit = []
|
||||
self.last_popup_time = datetime.now()
|
||||
self.license = LicenseManager()
|
||||
logging.info(f"license interface:{self.license}")
|
||||
|
||||
configfile = os.path.normpath(os.path.expanduser(args.configfile))
|
||||
|
||||
|
3
styles/dark/images/license.svg
Normal file
3
styles/dark/images/license.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M37.4 25.6C37 21.2 33.6 18.2 29 18H26C25.8 15.4 26.8 11.8 31 11.4C32.8 11.2 34.4 11.6 35.8 13C37 14.4 37.4 16 37.4 17.8C37.4 18 37.4 18.4 37.6 18.6L39.4 20.4C40 18.6 40 16.8 39.6 15C38.6 11.4 35.6 9.2 31.8 9C29.6 9 27.6 9.4 26 11C23.2 13.6 22.2 19.4 26.2 23.2C26.8 23.8 27.6 24.2 28.4 24.6C29.4 25 30.2 24.2 30.2 23.4C30.2 22.6 29.8 22 28.8 21.8C28.6 21.8 28.4 21.6 28.2 21.4V21.2C29 21 30 21.2 30.6 21.8C31.2 22.4 31.4 23.2 31.2 24.2C30.8 25.6 29.6 26.2 28 25.8C25.8 25.2 24.4 23.8 23.4 21.8C23.2 21.2 22.8 20.6 22.6 20C21.2 21.4 20 22.8 19.6 24.8C18.8 28.4 19.8 31.4 22.4 33.8C22.6 34 22.8 34.2 22.6 34.6C22.4 36.2 22.2 37.6 21.8 39.2C21.2 42.6 20.8 45.8 20.2 49.2C20 50.2 20 51.4 20.2 52.4C20.4 53.2 20.8 53.8 21.8 54.2C22 53.4 22 52.6 22.2 51.8C22.8 48.4 23.2 45.2 23.8 41.8C24.2 39.8 24.4 37.6 24.8 35.6C24.8 35.2 25 35 25.4 35C25.8 35 25.8 35.4 25.8 35.8C25.6 37.8 25.2 39.8 24.8 41.6C24.2 45.8 23.4 50 22.8 54.2C22.8 54.4 23 54.6 23 54.6C24 54.6 24.8 54.8 25.8 54.8C26.8 54.8 27.6 54 28.2 53.2C28.8 52.6 28.8 51.8 28.4 51C28.2 50.8 28 50.6 28 50.4C27.4 49.6 27.6 49 28.4 48.6C28.6 48.4 29 48.4 29.2 48.2C29.6 48 29.8 47.4 29.4 47C28.8 46.4 28.4 45.8 27.8 45.4C27.4 45 27.6 44.2 28 44C28.6 43.6 29.4 43.4 30 43C30.4 42.8 30.6 42.4 30.2 42C30 41.8 29.8 41.6 29.6 41.2C29 40.6 29.2 39.6 29.8 39.2C30 39 30.2 38.8 30.6 38.8C31 38.6 31.2 38.4 31.2 38C31.2 37.4 31.4 36.8 31.4 36.2C31.4 36 31.6 35.6 31.8 35.4C32.4 34.8 33.2 34.4 34 34C36.8 32 37.8 29 37.4 25.6ZM44.6 48.4C44.6 48 44.4 47.6 43.8 47.6C43.4 47.6 42.8 47.6 42.6 47C42.4 46.4 42.4 45.8 42.6 45.2C43 44.4 42.8 43.8 41.8 43.6C41.4 43.6 41 43.4 40.4 43.4C40 43.4 39.8 43.2 39.8 42.8C39.8 42.4 39.6 42 39.6 41.6C39.6 41 40 40.6 40.4 40.2C40.8 39.6 40.8 39.4 40.2 39C40 38.8 39.6 38.6 39.4 38.4C38.6 38 38.6 37.6 39 36.8C39.2 36.6 39.4 36.4 39.4 36.2C39.8 35.8 39.8 35.4 39.6 35C39.4 34.6 39.2 34 38.8 33.6C38.6 33.2 38.6 32.8 38.8 32.4C40.4 29.2 40.8 26 39.4 22.6C38.4 20.4 36.6 19 34.2 18.4L34 18.6C34.2 18.8 34.4 19.2 34.6 19.4C37 21.4 38.4 24 38.4 27.2C38.4 30.6 37 33.4 34 35.6C33.6 35.8 33.4 36.2 33.6 36.6C34.4 38.6 35 40.4 35.8 42.4C37.4 46.2 39 49.8 40.6 53.6C40.8 53.8 40.8 54 41.2 54C43.6 52.8 45 50.6 44.6 48.4ZM32.6 36.6C32.4 37.4 32.4 38 32.2 38.6C32.2 39 32 39.4 32.2 39.8C33.6 43.2 35 46.8 36.4 50.2C36.8 51.2 37.4 52.2 38.4 53C38.8 53.2 39.2 53.4 39.4 53.6L39.6 53.4C37.4 47.8 35 42.2 32.6 36.6Z" fill="#DBCD68"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
3
styles/light/images/license.svg
Normal file
3
styles/light/images/license.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M37.4 25.6C37 21.2 33.6 18.2 29 18H26C25.8 15.4 26.8 11.8 31 11.4C32.8 11.2 34.4 11.6 35.8 13C37 14.4 37.4 16 37.4 17.8C37.4 18 37.4 18.4 37.6 18.6L39.4 20.4C40 18.6 40 16.8 39.6 15C38.6 11.4 35.6 9.2 31.8 9C29.6 9 27.6 9.4 26 11C23.2 13.6 22.2 19.4 26.2 23.2C26.8 23.8 27.6 24.2 28.4 24.6C29.4 25 30.2 24.2 30.2 23.4C30.2 22.6 29.8 22 28.8 21.8C28.6 21.8 28.4 21.6 28.2 21.4V21.2C29 21 30 21.2 30.6 21.8C31.2 22.4 31.4 23.2 31.2 24.2C30.8 25.6 29.6 26.2 28 25.8C25.8 25.2 24.4 23.8 23.4 21.8C23.2 21.2 22.8 20.6 22.6 20C21.2 21.4 20 22.8 19.6 24.8C18.8 28.4 19.8 31.4 22.4 33.8C22.6 34 22.8 34.2 22.6 34.6C22.4 36.2 22.2 37.6 21.8 39.2C21.2 42.6 20.8 45.8 20.2 49.2C20 50.2 20 51.4 20.2 52.4C20.4 53.2 20.8 53.8 21.8 54.2C22 53.4 22 52.6 22.2 51.8C22.8 48.4 23.2 45.2 23.8 41.8C24.2 39.8 24.4 37.6 24.8 35.6C24.8 35.2 25 35 25.4 35C25.8 35 25.8 35.4 25.8 35.8C25.6 37.8 25.2 39.8 24.8 41.6C24.2 45.8 23.4 50 22.8 54.2C22.8 54.4 23 54.6 23 54.6C24 54.6 24.8 54.8 25.8 54.8C26.8 54.8 27.6 54 28.2 53.2C28.8 52.6 28.8 51.8 28.4 51C28.2 50.8 28 50.6 28 50.4C27.4 49.6 27.6 49 28.4 48.6C28.6 48.4 29 48.4 29.2 48.2C29.6 48 29.8 47.4 29.4 47C28.8 46.4 28.4 45.8 27.8 45.4C27.4 45 27.6 44.2 28 44C28.6 43.6 29.4 43.4 30 43C30.4 42.8 30.6 42.4 30.2 42C30 41.8 29.8 41.6 29.6 41.2C29 40.6 29.2 39.6 29.8 39.2C30 39 30.2 38.8 30.6 38.8C31 38.6 31.2 38.4 31.2 38C31.2 37.4 31.4 36.8 31.4 36.2C31.4 36 31.6 35.6 31.8 35.4C32.4 34.8 33.2 34.4 34 34C36.8 32 37.8 29 37.4 25.6ZM44.6 48.4C44.6 48 44.4 47.6 43.8 47.6C43.4 47.6 42.8 47.6 42.6 47C42.4 46.4 42.4 45.8 42.6 45.2C43 44.4 42.8 43.8 41.8 43.6C41.4 43.6 41 43.4 40.4 43.4C40 43.4 39.8 43.2 39.8 42.8C39.8 42.4 39.6 42 39.6 41.6C39.6 41 40 40.6 40.4 40.2C40.8 39.6 40.8 39.4 40.2 39C40 38.8 39.6 38.6 39.4 38.4C38.6 38 38.6 37.6 39 36.8C39.2 36.6 39.4 36.4 39.4 36.2C39.8 35.8 39.8 35.4 39.6 35C39.4 34.6 39.2 34 38.8 33.6C38.6 33.2 38.6 32.8 38.8 32.4C40.4 29.2 40.8 26 39.4 22.6C38.4 20.4 36.6 19 34.2 18.4L34 18.6C34.2 18.8 34.4 19.2 34.6 19.4C37 21.4 38.4 24 38.4 27.2C38.4 30.6 37 33.4 34 35.6C33.6 35.8 33.4 36.2 33.6 36.6C34.4 38.6 35 40.4 35.8 42.4C37.4 46.2 39 49.8 40.6 53.6C40.8 53.8 40.8 54 41.2 54C43.6 52.8 45 50.6 44.6 48.4ZM32.6 36.6C32.4 37.4 32.4 38 32.2 38.6C32.2 39 32 39.4 32.2 39.8C33.6 43.2 35 46.8 36.4 50.2C36.8 51.2 37.4 52.2 38.4 53C38.8 53.2 39.2 53.4 39.4 53.6L39.6 53.4C37.4 47.8 35 42.2 32.6 36.6Z" fill="#DBCD68"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
Loading…
x
Reference in New Issue
Block a user