├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── Keygen ├── CMakeLists.txt ├── Resources │ ├── art │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── icon128.png │ │ │ │ ├── icon128@2x.png │ │ │ │ ├── icon16.png │ │ │ │ ├── icon16@2x.png │ │ │ │ ├── icon256.png │ │ │ │ ├── icon256@2x.png │ │ │ │ ├── icon32.png │ │ │ │ ├── icon32@2x.png │ │ │ │ ├── icon512.png │ │ │ │ └── icon512@2x.png │ │ │ └── Icon.iconset │ │ │ │ ├── icon_128x128.png │ │ │ │ ├── icon_128x128@2x.png │ │ │ │ ├── icon_16x16.png │ │ │ │ ├── icon_16x16@2x.png │ │ │ │ ├── icon_256x256.png │ │ │ │ ├── icon_256x256@2x.png │ │ │ │ ├── icon_32x32.png │ │ │ │ ├── icon_32x32@2x.png │ │ │ │ ├── icon_512x512.png │ │ │ │ └── icon_512x512@2x.png │ │ ├── icon256.ico │ │ ├── logo.png │ │ └── lottie │ │ │ ├── keyboard.tgs │ │ │ └── paper.tgs │ ├── icons │ │ ├── intro_gem.png │ │ ├── intro_gem@2x.png │ │ ├── intro_gem@3x.png │ │ ├── intro_left.png │ │ ├── intro_left@2x.png │ │ ├── intro_left@3x.png │ │ ├── intro_right.png │ │ ├── intro_right@2x.png │ │ └── intro_right@3x.png │ ├── mac │ │ ├── Keygen.entitlements │ │ └── Keygen.plist │ ├── qrc │ │ └── keygen │ │ │ └── keygen.qrc │ └── win │ │ ├── Keygen.manifest │ │ └── Keygen.rc ├── SourceFiles │ ├── core │ │ ├── base_integration.cpp │ │ ├── base_integration.h │ │ ├── launcher.cpp │ │ ├── launcher.h │ │ ├── main.cpp │ │ ├── pch.cpp │ │ ├── pch.h │ │ ├── qt_static_plugins.cpp │ │ ├── sandbox.cpp │ │ ├── sandbox.h │ │ ├── ui_integration.cpp │ │ └── ui_integration.h │ ├── keygen │ │ ├── application.cpp │ │ ├── application.h │ │ ├── phrases.cpp │ │ ├── phrases.h │ │ ├── steps │ │ │ ├── check.cpp │ │ │ ├── check.h │ │ │ ├── created.cpp │ │ │ ├── created.h │ │ │ ├── done.cpp │ │ │ ├── done.h │ │ │ ├── intro.cpp │ │ │ ├── intro.h │ │ │ ├── manager.cpp │ │ │ ├── manager.h │ │ │ ├── random_seed.cpp │ │ │ ├── random_seed.h │ │ │ ├── step.cpp │ │ │ ├── step.h │ │ │ ├── view.cpp │ │ │ └── view.h │ │ └── tr.h │ └── ui │ │ ├── keygen.style │ │ ├── lottie_widget.cpp │ │ ├── lottie_widget.h │ │ ├── message_box.cpp │ │ ├── message_box.h │ │ ├── public_key_label.cpp │ │ ├── public_key_label.h │ │ ├── word_suggestions.cpp │ │ └── word_suggestions.h ├── build │ ├── build.bat │ ├── build.sh │ ├── set_version.bat │ ├── set_version.py │ ├── set_version.sh │ └── version ├── configure.bat ├── configure.py ├── configure.sh └── create.bat ├── LEGAL ├── LICENSE ├── README.md └── docs ├── building-cmake.md ├── building-msvc.md └── building-xcode.md /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | Debug/ 3 | Release/ 4 | /ThirdParty/ 5 | /Keygen/build/target 6 | /Keygen/tests/ 7 | /Keygen/gyp/tests/*.test 8 | /Keygen/out/ 9 | /Keygen/*.user 10 | *.vcxproj* 11 | *.sln 12 | *.suo 13 | *.sdf 14 | *.opensdf 15 | *.opendb 16 | *.VC.db 17 | *.aps 18 | *.xcodeproj 19 | /Win32/ 20 | ipch/ 21 | .vs/ 22 | 23 | .DS_Store 24 | ._* 25 | .qmake.stash 26 | /Mac/ 27 | project.xcworkspace 28 | xcuserdata 29 | 30 | parts 31 | prime 32 | stage 33 | *.snap 34 | .snapcraft 35 | /snap/gui/*.png 36 | /snap/gui/*.desktop 37 | /snap/plugins/__pycache__ 38 | 39 | /Keygen/*.user.* 40 | *.pro.user 41 | /Linux/ 42 | /Keygen/Makefile 43 | *.*~ 44 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Keygen/ThirdParty/variant"] 2 | path = Keygen/ThirdParty/variant 3 | url = https://github.com/mapbox/variant 4 | [submodule "Keygen/ThirdParty/GSL"] 5 | path = Keygen/ThirdParty/GSL 6 | url = https://github.com/Microsoft/GSL.git 7 | [submodule "Keygen/lib_crl"] 8 | path = Keygen/lib_crl 9 | url = https://github.com/desktop-app/lib_crl 10 | [submodule "Keygen/lib_rpl"] 11 | path = Keygen/lib_rpl 12 | url = https://github.com/desktop-app/lib_rpl 13 | [submodule "Keygen/lib_base"] 14 | path = Keygen/lib_base 15 | url = https://github.com/desktop-app/lib_base 16 | [submodule "Keygen/lib_ui"] 17 | path = Keygen/lib_ui 18 | url = https://github.com/desktop-app/lib_ui 19 | [submodule "Keygen/codegen"] 20 | path = Keygen/codegen 21 | url = https://github.com/desktop-app/codegen 22 | [submodule "Keygen/lib_ton"] 23 | path = Keygen/lib_ton 24 | url = https://github.com/desktop-app/lib_ton.git 25 | [submodule "Keygen/ThirdParty/rlottie"] 26 | path = Keygen/ThirdParty/rlottie 27 | url = https://github.com/desktop-app/rlottie.git 28 | [submodule "Keygen/lib_lottie"] 29 | path = Keygen/lib_lottie 30 | url = https://github.com/desktop-app/lib_lottie.git 31 | [submodule "Keygen/lib_tl"] 32 | path = Keygen/lib_tl 33 | url = https://github.com/desktop-app/lib_tl.git 34 | [submodule "Keygen/ThirdParty/xxHash"] 35 | path = Keygen/ThirdParty/xxHash 36 | url = https://github.com/Cyan4973/xxHash.git 37 | [submodule "Keygen/lib_storage"] 38 | path = Keygen/lib_storage 39 | url = https://github.com/desktop-app/lib_storage.git 40 | [submodule "Keygen/ThirdParty/expected"] 41 | path = Keygen/ThirdParty/expected 42 | url = https://github.com/TartanLlama/expected 43 | [submodule "cmake"] 44 | path = cmake 45 | url = https://github.com/desktop-app/cmake_helpers.git 46 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file is part of TON Key Generator, 2 | # a desktop application for the TON Blockchain project. 3 | # 4 | # For license and copyright information please follow this link: 5 | # https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | 7 | cmake_minimum_required(VERSION 3.16) 8 | cmake_policy(SET CMP0076 NEW) 9 | cmake_policy(SET CMP0091 NEW) 10 | 11 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 12 | 13 | include(cmake/validate_special_target.cmake) 14 | include(cmake/version.cmake) 15 | desktop_app_parse_version(Keygen/build/version) 16 | 17 | project(Keygen 18 | LANGUAGES C CXX 19 | VERSION ${desktop_app_version_cmake} 20 | DESCRIPTION "TON Key Generator" 21 | HOMEPAGE_URL "https://generator.ton.org" 22 | ) 23 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Keygen) 24 | 25 | get_filename_component(third_party_loc "Keygen/ThirdParty" REALPATH) 26 | get_filename_component(submodules_loc "Keygen" REALPATH) 27 | 28 | include(cmake/variables.cmake) 29 | include(cmake/nice_target_sources.cmake) 30 | include(cmake/target_link_static_libraries.cmake) 31 | include(cmake/target_link_frameworks.cmake) 32 | include(cmake/init_target.cmake) 33 | include(cmake/generate_target.cmake) 34 | 35 | include(cmake/options.cmake) 36 | 37 | include(cmake/external/qt/package.cmake) 38 | 39 | set(desktop_app_skip_libs 40 | dbusmenu_qt 41 | ffmpeg 42 | hunspell 43 | iconv 44 | lz4 45 | minizip 46 | openal 47 | opus 48 | qr_code_generator 49 | sp_media_key_tap 50 | statusnotifieritem 51 | ) 52 | set(DESKTOP_APP_LOTTIE_USE_CACHE OFF) 53 | 54 | add_subdirectory(cmake) 55 | add_subdirectory(Keygen) 56 | -------------------------------------------------------------------------------- /Keygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file is part of TON Key Generator, 2 | # a desktop application for the TON Blockchain project. 3 | # 4 | # For license and copyright information please follow this link: 5 | # https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | 7 | add_executable(Keygen WIN32 MACOSX_BUNDLE) 8 | init_target(Keygen) 9 | 10 | if (${CMAKE_GENERATOR} MATCHES "(Visual Studio|Xcode)") 11 | set(output_folder ${CMAKE_BINARY_DIR}) 12 | elseif (DESKTOP_APP_SPECIAL_TARGET STREQUAL "") 13 | set(output_folder ${CMAKE_BINARY_DIR}/bin) 14 | else() 15 | set(output_folder ${CMAKE_BINARY_DIR}/$,Debug,Release>) 16 | endif() 17 | set(update_packer_output_folder ${output_folder}) 18 | 19 | add_subdirectory(lib_rpl) 20 | add_subdirectory(lib_crl) 21 | add_subdirectory(lib_base) 22 | add_subdirectory(lib_ui) 23 | add_subdirectory(lib_tl) 24 | add_subdirectory(lib_storage) 25 | add_subdirectory(lib_lottie) 26 | add_subdirectory(lib_ton) 27 | add_subdirectory(codegen) 28 | 29 | include(CheckCXXSourceCompiles) 30 | include(lib_ui/cmake/generate_styles.cmake) 31 | 32 | get_filename_component(src_loc SourceFiles REALPATH) 33 | get_filename_component(res_loc Resources REALPATH) 34 | 35 | set(style_files 36 | ui/keygen.style 37 | ) 38 | 39 | set(dependent_style_files 40 | ${submodules_loc}/lib_ui/ui/colors.palette 41 | ${submodules_loc}/lib_ui/ui/basic.style 42 | ${submodules_loc}/lib_ui/ui/layers/layers.style 43 | ${submodules_loc}/lib_ui/ui/widgets/widgets.style 44 | ) 45 | 46 | generate_styles(Keygen ${src_loc} "${style_files}" "${dependent_style_files}") 47 | 48 | set_target_properties(Keygen PROPERTIES AUTORCC ON) 49 | 50 | target_link_libraries(Keygen 51 | PRIVATE 52 | desktop-app::lib_crl 53 | desktop-app::lib_ui 54 | desktop-app::lib_tl 55 | desktop-app::lib_ton 56 | desktop-app::lib_storage 57 | desktop-app::lib_lottie 58 | desktop-app::lib_base 59 | desktop-app::lib_base_crash_report_writer 60 | desktop-app::external_rlottie 61 | desktop-app::external_qt 62 | desktop-app::external_crash_reports 63 | desktop-app::external_auto_updates 64 | desktop-app::external_openssl 65 | ) 66 | 67 | if (DESKTOP_APP_USE_PACKAGED) 68 | set(CMAKE_THREAD_PREFER_PTHREAD TRUE) 69 | find_package(Threads) 70 | 71 | target_link_libraries(Keygen 72 | PRIVATE 73 | ${CMAKE_DL_LIBS} 74 | Threads::Threads 75 | ) 76 | endif() 77 | 78 | target_precompile_headers(Keygen PRIVATE ${src_loc}/core/pch.h) 79 | nice_target_sources(Keygen ${src_loc} 80 | PRIVATE 81 | ${style_files} 82 | 83 | core/base_integration.cpp 84 | core/base_integration.h 85 | core/launcher.cpp 86 | core/launcher.h 87 | core/main.cpp 88 | core/qt_static_plugins.cpp 89 | core/sandbox.cpp 90 | core/sandbox.h 91 | core/ui_integration.cpp 92 | core/ui_integration.h 93 | keygen/application.cpp 94 | keygen/application.h 95 | keygen/phrases.cpp 96 | keygen/phrases.h 97 | keygen/steps/check.cpp 98 | keygen/steps/check.h 99 | keygen/steps/created.cpp 100 | keygen/steps/created.h 101 | keygen/steps/done.cpp 102 | keygen/steps/done.h 103 | keygen/steps/intro.cpp 104 | keygen/steps/intro.h 105 | keygen/steps/manager.cpp 106 | keygen/steps/manager.h 107 | keygen/steps/random_seed.cpp 108 | keygen/steps/random_seed.h 109 | keygen/steps/step.cpp 110 | keygen/steps/step.h 111 | keygen/steps/view.cpp 112 | keygen/steps/view.h 113 | keygen/tr.h 114 | ui/lottie_widget.cpp 115 | ui/lottie_widget.h 116 | ui/message_box.cpp 117 | ui/message_box.h 118 | ui/public_key_label.cpp 119 | ui/public_key_label.h 120 | ui/word_suggestions.cpp 121 | ui/word_suggestions.h 122 | ) 123 | 124 | if (DESKTOP_APP_SPECIAL_TARGET) 125 | target_compile_definitions(Keygen PRIVATE KEYGEN_OFFICIAL_BUILD) 126 | endif() 127 | 128 | if (DESKTOP_APP_USE_PACKAGED) 129 | message(FATAL_ERROR "Packaged build is not supported yet.") 130 | nice_target_sources(Keygen ${src_loc} PRIVATE core/qt_functions.cpp) 131 | else() 132 | nice_target_sources(Keygen ${src_loc} PRIVATE core/qt_static_plugins.cpp) 133 | endif() 134 | 135 | nice_target_sources(Keygen ${res_loc} 136 | PRIVATE 137 | qrc/keygen/keygen.qrc 138 | win/Keygen.rc 139 | win/Keygen.manifest 140 | ) 141 | 142 | if (WIN32) 143 | elseif (APPLE) 144 | set(icons_path ${res_loc}/art/Images.xcassets) 145 | set_target_properties(Keygen PROPERTIES RESOURCE ${icons_path}) 146 | target_sources(Keygen PRIVATE ${icons_path}) 147 | elseif (LINUX) 148 | #if (NOT KEYGEN_DISABLE_GTK_INTEGRATION) 149 | find_package(PkgConfig REQUIRED) 150 | 151 | pkg_search_module(GTK REQUIRED gtk+-2.0 gtk+-3.0) 152 | target_include_directories(Keygen PRIVATE ${GTK_INCLUDE_DIRS}) 153 | target_compile_options(Keygen PRIVATE -Wno-register) 154 | 155 | if (DESKTOP_APP_USE_PACKAGED) 156 | find_library(X11_LIBRARY X11) 157 | target_link_libraries(Keygen PRIVATE ${X11_LIBRARY}) 158 | endif() 159 | #endif() 160 | endif() 161 | 162 | if (build_macstore) 163 | message(FATAL_ERROR "Mac App Store build is not supported.") 164 | else() 165 | set(bundle_identifier "org.ton.TonKeyGenerator$<$:Debug>") 166 | set(bundle_entitlements "Keygen.entitlements") 167 | if (LINUX AND DESKTOP_APP_USE_PACKAGED) 168 | set(output_name "keygen-desktop") 169 | else() 170 | set(output_name "Keygen") 171 | endif() 172 | endif() 173 | 174 | set_target_properties(Keygen PROPERTIES 175 | OUTPUT_NAME ${output_name} 176 | MACOSX_BUNDLE_GUI_IDENTIFIER ${bundle_identifier} 177 | MACOSX_BUNDLE_INFO_PLIST ${res_loc}/mac/Keygen.plist 178 | XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${res_loc}/mac/${bundle_entitlements}" 179 | XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${bundle_identifier} 180 | XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION ${desktop_app_version_string} 181 | XCODE_ATTRIBUTE_PRODUCT_NAME ${output_name} 182 | XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT $<$>:dwarf-with-dsym> 183 | XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon 184 | XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES 185 | XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES YES 186 | XCODE_ATTRIBUTE_COPY_PHASE_STRIP NO 187 | XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO 188 | XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY libc++ 189 | XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep 190 | ) 191 | set(entitlement_sources 192 | "${res_loc}/mac/Keygen.entitlements" 193 | ) 194 | target_sources(Keygen PRIVATE ${entitlement_sources}) 195 | source_group(TREE ${res_loc} PREFIX Resources FILES ${entitlement_sources}) 196 | 197 | target_include_directories(Keygen PRIVATE ${src_loc}) 198 | 199 | set_target_properties(Keygen PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder}) 200 | -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon128.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon128@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon16.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon16@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon256.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon256@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon32.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon32@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon512.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/AppIcon.appiconset/icon512@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/Images.xcassets/Icon.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/art/icon256.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/icon256.ico -------------------------------------------------------------------------------- /Keygen/Resources/art/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/logo.png -------------------------------------------------------------------------------- /Keygen/Resources/art/lottie/keyboard.tgs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/lottie/keyboard.tgs -------------------------------------------------------------------------------- /Keygen/Resources/art/lottie/paper.tgs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/art/lottie/paper.tgs -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_gem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_gem.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_gem@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_gem@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_gem@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_gem@3x.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_left.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_left@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_left@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_left@3x.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_right.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_right@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_right@2x.png -------------------------------------------------------------------------------- /Keygen/Resources/icons/intro_right@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton-blockchain/tonkeygen/ff994b1c44bdd9486dbfbd23602c4daf77a1ab9d/Keygen/Resources/icons/intro_right@3x.png -------------------------------------------------------------------------------- /Keygen/Resources/mac/Keygen.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Keygen/Resources/mac/Keygen.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | $(PRODUCT_NAME) 7 | CFBundleIdentifier 8 | $(PRODUCT_BUNDLE_IDENTIFIER) 9 | CFBundlePackageType 10 | APPL 11 | CFBundleShortVersionString 12 | $(CURRENT_PROJECT_VERSION) 13 | CFBundleSignature 14 | ???? 15 | CFBundleURLTypes 16 | 17 | 18 | CFBundleTypeRole 19 | Viewer 20 | CFBundleURLIconFile 21 | Icon.icns 22 | CFBundleURLName 23 | $(PRODUCT_BUNDLE_IDENTIFIER) 24 | CFBundleURLSchemes 25 | 26 | tg 27 | 28 | 29 | 30 | CFBundleVersion 31 | $(CURRENT_PROJECT_VERSION) 32 | LSApplicationCategoryType 33 | public.app-category.social-networking 34 | LSMinimumSystemVersion 35 | $(MACOSX_DEPLOYMENT_TARGET) 36 | NOTE 37 | 38 | NSPrincipalClass 39 | NSApplication 40 | NSSupportsAutomaticGraphicsSwitching 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Keygen/Resources/qrc/keygen/keygen.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../../art/lottie/keyboard.tgs 4 | ../../art/lottie/paper.tgs 5 | ../../art/logo.png 6 | 7 | 8 | -------------------------------------------------------------------------------- /Keygen/Resources/win/Keygen.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Keygen/Resources/win/Keygen.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | 4 | #define APSTUDIO_READONLY_SYMBOLS 5 | ///////////////////////////////////////////////////////////////////////////// 6 | // 7 | // Generated from the TEXTINCLUDE 2 resource. 8 | // 9 | #include "winres.h" 10 | 11 | ///////////////////////////////////////////////////////////////////////////// 12 | #undef APSTUDIO_READONLY_SYMBOLS 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | // English (United States) resources 16 | 17 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 18 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 19 | #pragma code_page(1252) 20 | 21 | ///////////////////////////////////////////////////////////////////////////// 22 | // 23 | // Icon 24 | // 25 | 26 | // Icon with lowest ID value placed first to ensure application icon 27 | // remains consistent on all systems. 28 | IDI_ICON1 ICON "..\\art\\icon256.ico" 29 | 30 | ///////////////////////////////////////////////////////////////////////////// 31 | // 32 | // Version 33 | // 34 | 35 | VS_VERSION_INFO VERSIONINFO 36 | FILEVERSION 1,1,0,0 37 | PRODUCTVERSION 1,1,0,0 38 | FILEFLAGSMASK 0x3fL 39 | #ifdef _DEBUG 40 | FILEFLAGS 0x1L 41 | #else 42 | FILEFLAGS 0x0L 43 | #endif 44 | FILEOS 0x40004L 45 | FILETYPE 0x0L 46 | FILESUBTYPE 0x0L 47 | BEGIN 48 | BLOCK "StringFileInfo" 49 | BEGIN 50 | BLOCK "040904b0" 51 | BEGIN 52 | VALUE "CompanyName", "Telegram FZ-LLC" 53 | VALUE "FileDescription", "TON Key Generator" 54 | VALUE "FileVersion", "1.1.0.0" 55 | VALUE "LegalCopyright", "Copyright (C) 2019" 56 | VALUE "ProductName", "TON Key Generator" 57 | VALUE "ProductVersion", "1.1.0.0" 58 | END 59 | END 60 | BLOCK "VarFileInfo" 61 | BEGIN 62 | VALUE "Translation", 0x409, 1200 63 | END 64 | END 65 | 66 | #endif // English (United States) resources 67 | ///////////////////////////////////////////////////////////////////////////// 68 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/base_integration.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/base_integration.h" 8 | 9 | #include "core/launcher.h" 10 | #include "core/sandbox.h" 11 | 12 | namespace Core { 13 | 14 | BaseIntegration::BaseIntegration( 15 | int argc, 16 | char *argv[]) 17 | : Integration(argc, argv) { 18 | } 19 | 20 | void BaseIntegration::enterFromEventLoop(FnMut &&method) { 21 | Core::Sandbox::Instance().customEnterFromEventLoop( 22 | std::move(method)); 23 | } 24 | 25 | void BaseIntegration::logMessage(const QString &message) { 26 | } 27 | 28 | } // namespace Core 29 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/base_integration.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "base/integration.h" 10 | 11 | namespace Core { 12 | 13 | class BaseIntegration : public base::Integration { 14 | public: 15 | BaseIntegration(int argc, char *argv[]); 16 | 17 | void enterFromEventLoop(FnMut &&method) override; 18 | void logMessage(const QString &message) override; 19 | 20 | }; 21 | 22 | } // namespace Core 23 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/launcher.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/launcher.h" 8 | 9 | #include "ui/main_queue_processor.h" 10 | #include "core/sandbox.h" 11 | #include "base/platform/base_platform_info.h" 12 | #include "base/concurrent_timer.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Core { 19 | namespace { 20 | 21 | class FilteredCommandLineArguments { 22 | public: 23 | FilteredCommandLineArguments(int argc, char **argv); 24 | 25 | int &count(); 26 | char **values(); 27 | 28 | private: 29 | static constexpr auto kForwardArgumentCount = 1; 30 | 31 | int _count = 0; 32 | char *_arguments[kForwardArgumentCount + 1] = { nullptr }; 33 | 34 | }; 35 | 36 | FilteredCommandLineArguments::FilteredCommandLineArguments( 37 | int argc, 38 | char **argv) 39 | : _count(std::clamp(argc, 0, kForwardArgumentCount)) { 40 | // For now just pass only the first argument, the executable path. 41 | for (auto i = 0; i != _count; ++i) { 42 | _arguments[i] = argv[i]; 43 | } 44 | } 45 | 46 | int &FilteredCommandLineArguments::count() { 47 | return _count; 48 | } 49 | 50 | char **FilteredCommandLineArguments::values() { 51 | return _arguments; 52 | } 53 | 54 | } // namespace 55 | 56 | std::unique_ptr Launcher::Create(int argc, char *argv[]) { 57 | return std::make_unique(argc, argv); 58 | } 59 | 60 | Launcher::Launcher(int argc, char *argv[]) 61 | : _argc(argc) 62 | , _argv(argv) 63 | , _baseIntegration(argc, argv) { 64 | base::Integration::Set(&_baseIntegration); 65 | } 66 | 67 | void Launcher::init() { 68 | _arguments = readArguments(_argc, _argv); 69 | 70 | prepareSettings(); 71 | 72 | QApplication::setApplicationName("TonKeyGenerator"); 73 | 74 | #ifdef Q_OS_MAC 75 | // macOS Retina display support is working fine, others are not. 76 | QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, false); 77 | #else // Q_OS_MAC 78 | QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true); 79 | #endif // Q_OS_MAC 80 | } 81 | 82 | int Launcher::exec() { 83 | init(); 84 | 85 | auto options = QJsonObject(); 86 | const auto tempFontConfigPath = QStandardPaths::writableLocation( 87 | QStandardPaths::TempLocation 88 | ) + "/fc-custom-1.conf"; 89 | options.insert("custom_font_config_src", QString(":/fc/fc-custom.conf")); 90 | options.insert("custom_font_config_dst", tempFontConfigPath); 91 | Platform::Start(options); 92 | 93 | auto result = executeApplication(); 94 | 95 | Platform::Finish(); 96 | 97 | return result; 98 | } 99 | 100 | QStringList Launcher::readArguments(int argc, char *argv[]) const { 101 | Expects(argc >= 0); 102 | 103 | auto result = QStringList(); 104 | result.reserve(argc); 105 | for (auto i = 0; i != argc; ++i) { 106 | result.push_back(base::FromUtf8Safe(argv[i])); 107 | } 108 | return result; 109 | } 110 | 111 | QString Launcher::argumentsString() const { 112 | return _arguments.join(' '); 113 | } 114 | 115 | void Launcher::prepareSettings() { 116 | processArguments(); 117 | } 118 | 119 | void Launcher::processArguments() { 120 | } 121 | 122 | int Launcher::executeApplication() { 123 | FilteredCommandLineArguments arguments(_argc, _argv); 124 | Sandbox sandbox(this, arguments.count(), arguments.values()); 125 | Ui::MainQueueProcessor processor; 126 | base::ConcurrentTimerEnvironment environment; 127 | return sandbox.exec(); 128 | } 129 | 130 | } // namespace Core 131 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/launcher.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "core/base_integration.h" 10 | 11 | namespace Core { 12 | 13 | class Launcher { 14 | public: 15 | Launcher(int argc, char *argv[]); 16 | 17 | static std::unique_ptr Create(int argc, char *argv[]); 18 | 19 | int exec(); 20 | 21 | QString argumentsString() const; 22 | 23 | virtual ~Launcher() = default; 24 | 25 | private: 26 | void prepareSettings(); 27 | void processArguments(); 28 | 29 | QStringList readArguments(int argc, char *argv[]) const; 30 | 31 | void init(); 32 | int executeApplication(); 33 | 34 | int _argc; 35 | char **_argv; 36 | QStringList _arguments; 37 | BaseIntegration _baseIntegration; 38 | 39 | }; 40 | 41 | } // namespace Core 42 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/main.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/launcher.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | const auto launcher = Core::Launcher::Create(argc, argv); 11 | return launcher ? launcher->exec() : 1; 12 | } 13 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/pch.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/pch.h" 8 | 9 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/pch.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "base/assertion.h" 28 | #include "base/basic_types.h" 29 | #include "base/variant.h" 30 | #include "base/optional.h" 31 | #include "base/algorithm.h" 32 | #include "base/invoke_queued.h" 33 | #include "base/flat_set.h" 34 | #include "base/flat_map.h" 35 | #include "base/weak_ptr.h" 36 | #include "base/observer.h" 37 | 38 | #include 39 | #include 40 | #include 41 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/qt_static_plugins.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include 8 | 9 | #ifdef Q_OS_WIN 10 | Q_IMPORT_PLUGIN(QWebpPlugin) 11 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) 12 | #elif defined Q_OS_MAC // Q_OS_WIN 13 | Q_IMPORT_PLUGIN(QWebpPlugin) 14 | Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) 15 | Q_IMPORT_PLUGIN(QGenericEnginePlugin) 16 | #elif defined Q_OS_LINUX // Q_OS_WIN | Q_OS_MAC 17 | Q_IMPORT_PLUGIN(QWebpPlugin) 18 | Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) 19 | Q_IMPORT_PLUGIN(QConnmanEnginePlugin) 20 | Q_IMPORT_PLUGIN(QGenericEnginePlugin) 21 | Q_IMPORT_PLUGIN(QNetworkManagerEnginePlugin) 22 | Q_IMPORT_PLUGIN(QComposePlatformInputContextPlugin) 23 | Q_IMPORT_PLUGIN(QIbusPlatformInputContextPlugin) 24 | Q_IMPORT_PLUGIN(QFcitxPlatformInputContextPlugin) 25 | Q_IMPORT_PLUGIN(QHimePlatformInputContextPlugin) 26 | Q_IMPORT_PLUGIN(NimfInputContextPlugin) 27 | #endif // Q_OS_WIN | Q_OS_MAC | Q_OS_LINUX 28 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/sandbox.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/sandbox.h" 8 | 9 | #include "core/launcher.h" 10 | #include "keygen/application.h" 11 | #include "ui/widgets/tooltip.h" 12 | #include "ui/emoji_config.h" 13 | #include "ui/effects/animations.h" 14 | #include "base/concurrent_timer.h" 15 | #include "base/unixtime.h" 16 | #include "base/timer.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace Core { 24 | 25 | Sandbox::Sandbox( 26 | not_null launcher, 27 | int &argc, 28 | char **argv) 29 | : QApplication(argc, argv) 30 | , _launcher(launcher) 31 | , _mainThreadId(QThread::currentThreadId()) 32 | , _animationsManager(std::make_unique()) { 33 | Ui::Integration::Set(&uiIntegration); 34 | InvokeQueued(this, [=] { run(); }); 35 | } 36 | 37 | Sandbox::~Sandbox() { 38 | Ui::Emoji::Clear(); 39 | style::stopManager(); 40 | } 41 | 42 | void Sandbox::run() { 43 | setupScreenScale(); 44 | installNativeEventFilter(this); 45 | 46 | style::internal::StartFonts(); 47 | 48 | style::startManager(_scale); 49 | Ui::Emoji::Init(); 50 | 51 | connect( 52 | this, 53 | &Sandbox::applicationStateChanged, 54 | this, 55 | &Sandbox::stateChanged); 56 | 57 | launchApplication(); 58 | } 59 | 60 | void Sandbox::launchApplication() { 61 | _application = std::make_unique(); 62 | connect(this, &Sandbox::aboutToQuit, [=] { 63 | customEnterFromEventLoop([&] { 64 | _application = nullptr; 65 | }); 66 | }); 67 | _application->run(); 68 | } 69 | 70 | auto Sandbox::createNestedEventLoopState(not_null guard) 71 | -> std::shared_ptr { 72 | auto state = std::make_shared(); 73 | const auto waslevel = _loopNestingLevel; 74 | state->checkEntered = [=] { 75 | if (state->finished) { 76 | return; 77 | } 78 | if (_loopNestingLevel > waslevel) { 79 | state->checkEntered = nullptr; 80 | processPostponedCalls(waslevel); 81 | } else { 82 | InvokeQueued(guard, state->checkEntered); 83 | } 84 | }; 85 | InvokeQueued(guard, state->checkEntered); 86 | return state; 87 | } 88 | 89 | bool Sandbox::event(QEvent *event) { 90 | if (event->type() == QEvent::Close) { 91 | quit(); 92 | } 93 | return QApplication::event(event); 94 | } 95 | 96 | void Sandbox::setupScreenScale() { 97 | const auto dpi = Sandbox::primaryScreen()->logicalDotsPerInch(); 98 | if (dpi <= 108) { 99 | setScale(100); // 100%: 96 DPI (0-108) 100 | } else if (dpi <= 132) { 101 | setScale(125); // 125%: 120 DPI (108-132) 102 | } else if (dpi <= 168) { 103 | setScale(150); // 150%: 144 DPI (132-168) 104 | } else if (dpi <= 216) { 105 | setScale(200); // 200%: 192 DPI (168-216) 106 | } else if (dpi <= 264) { 107 | setScale(250); // 250%: 240 DPI (216-264) 108 | } else { 109 | setScale(300); // 300%: 288 DPI (264-inf) 110 | } 111 | const auto ratio = devicePixelRatio(); 112 | if (ratio > 1.) { 113 | style::SetDevicePixelRatio(int(ratio)); 114 | setScale(style::kScaleDefault); 115 | } 116 | } 117 | 118 | void Sandbox::setScale(int scale) { 119 | _scale = scale; 120 | style::SetScale(scale); 121 | } 122 | 123 | void Sandbox::stateChanged(Qt::ApplicationState state) { 124 | if (state == Qt::ApplicationActive) { 125 | handleAppActivated(); 126 | } else { 127 | handleAppDeactivated(); 128 | } 129 | } 130 | 131 | void Sandbox::handleAppActivated() { 132 | base::CheckLocalTime(); 133 | } 134 | 135 | void Sandbox::handleAppDeactivated() { 136 | Ui::Tooltip::Hide(); 137 | } 138 | 139 | // macOS Qt bug workaround, sometimes no leaveEvent() gets to the nested widgets. 140 | void Sandbox::registerLeaveSubscription(not_null widget) { 141 | #ifdef Q_OS_MAC 142 | // if (const auto topLevel = widget->window()) { 143 | // if (topLevel == _window->widget()) { 144 | // auto weak = Ui::MakeWeak(widget); 145 | // auto subscription = _window->widget()->leaveEvents( 146 | // ) | rpl::start_with_next([weak] { 147 | // if (const auto window = weak.data()) { 148 | // QEvent ev(QEvent::Leave); 149 | // QGuiSandbox::sendEvent(window, &ev); 150 | // } 151 | // }); 152 | // _leaveSubscriptions.emplace_back(weak, std::move(subscription)); 153 | // } 154 | // } 155 | #endif // Q_OS_MAC 156 | } 157 | 158 | void Sandbox::unregisterLeaveSubscription(not_null widget) { 159 | #ifdef Q_OS_MAC 160 | // _leaveSubscriptions = std::move( 161 | // _leaveSubscriptions 162 | // ) | ranges::action::remove_if([&](const LeaveSubscription &subscription) { 163 | // auto pointer = subscription.pointer.data(); 164 | // return !pointer || (pointer == widget); 165 | // }); 166 | #endif // Q_OS_MAC 167 | } 168 | 169 | void Sandbox::postponeCall(FnMut &&callable) { 170 | Expects(callable != nullptr); 171 | Expects(_eventNestingLevel >= _loopNestingLevel); 172 | 173 | // _loopNestingLevel == _eventNestingLevel means that we had a 174 | // native event in a nesting loop that didn't get a notify() call 175 | // after. That means we already have exited the nesting loop and 176 | // there must not be any postponed calls with that nesting level. 177 | if (_loopNestingLevel == _eventNestingLevel) { 178 | Assert(_postponedCalls.empty() 179 | || _postponedCalls.back().loopNestingLevel < _loopNestingLevel); 180 | Assert(!_previousLoopNestingLevels.empty()); 181 | 182 | _loopNestingLevel = _previousLoopNestingLevels.back(); 183 | _previousLoopNestingLevels.pop_back(); 184 | } 185 | 186 | _postponedCalls.push_back({ 187 | _loopNestingLevel, 188 | std::move(callable) 189 | }); 190 | } 191 | 192 | void Sandbox::incrementEventNestingLevel() { 193 | ++_eventNestingLevel; 194 | } 195 | 196 | void Sandbox::decrementEventNestingLevel() { 197 | if (_eventNestingLevel == _loopNestingLevel) { 198 | _loopNestingLevel = _previousLoopNestingLevels.back(); 199 | _previousLoopNestingLevels.pop_back(); 200 | } 201 | const auto processTillLevel = _eventNestingLevel - 1; 202 | processPostponedCalls(processTillLevel); 203 | _eventNestingLevel = processTillLevel; 204 | } 205 | 206 | void Sandbox::registerEnterFromEventLoop() { 207 | if (_eventNestingLevel > _loopNestingLevel) { 208 | _previousLoopNestingLevels.push_back(_loopNestingLevel); 209 | _loopNestingLevel = _eventNestingLevel; 210 | } 211 | } 212 | 213 | bool Sandbox::notifyOrInvoke(QObject *receiver, QEvent *e) { 214 | if (e->type() == base::InvokeQueuedEvent::kType) { 215 | static_cast(e)->invoke(); 216 | return true; 217 | } 218 | return QApplication::notify(receiver, e); 219 | } 220 | 221 | bool Sandbox::notify(QObject *receiver, QEvent *e) { 222 | if (QThread::currentThreadId() != _mainThreadId) { 223 | return notifyOrInvoke(receiver, e); 224 | } 225 | const auto wrap = createEventNestingLevelWrap(); 226 | if (e->type() == QEvent::UpdateRequest) { 227 | const auto weak = QPointer(receiver); 228 | _widgetUpdateRequests.fire({}); 229 | if (!weak) { 230 | return true; 231 | } 232 | } 233 | return notifyOrInvoke(receiver, e); 234 | } 235 | 236 | void Sandbox::processPostponedCalls(int level) { 237 | while (!_postponedCalls.empty()) { 238 | auto &last = _postponedCalls.back(); 239 | if (last.loopNestingLevel != level) { 240 | break; 241 | } 242 | auto taken = std::move(last); 243 | _postponedCalls.pop_back(); 244 | taken.callable(); 245 | } 246 | } 247 | 248 | bool Sandbox::nativeEventFilter( 249 | const QByteArray &eventType, 250 | void *message, 251 | long *result) { 252 | registerEnterFromEventLoop(); 253 | return false; 254 | } 255 | 256 | rpl::producer<> Sandbox::widgetUpdateRequests() const { 257 | return _widgetUpdateRequests.events(); 258 | } 259 | 260 | } // namespace Core 261 | 262 | namespace crl { 263 | 264 | rpl::producer<> on_main_update_requests() { 265 | return Core::Sandbox::Instance().widgetUpdateRequests(); 266 | } 267 | 268 | } // namespace crl 269 | 270 | namespace base { 271 | 272 | void EnterFromEventLoop(FnMut &&method) { 273 | Core::Sandbox::Instance().customEnterFromEventLoop( 274 | std::move(method)); 275 | } 276 | 277 | } // namespace base 278 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/sandbox.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "base/timer.h" 10 | #include "core/ui_integration.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace Ui { 16 | namespace Animations { 17 | class Manager; 18 | } // namespace Animations 19 | } // namespace Ui 20 | 21 | namespace Keygen { 22 | class Application; 23 | } // namespace Keygen 24 | 25 | namespace Core { 26 | 27 | class Launcher; 28 | 29 | class Sandbox final 30 | : public QApplication 31 | , private QAbstractNativeEventFilter { 32 | auto createEventNestingLevelWrap() { 33 | incrementEventNestingLevel(); 34 | return gsl::finally([=] { decrementEventNestingLevel(); }); 35 | } 36 | 37 | public: 38 | Sandbox(not_null launcher, int &argc, char **argv); 39 | Sandbox(const Sandbox &other) = delete; 40 | Sandbox &operator=(const Sandbox &other) = delete; 41 | ~Sandbox(); 42 | 43 | not_null launcher() const { 44 | return _launcher; 45 | } 46 | 47 | void postponeCall(FnMut &&callable); 48 | bool notify(QObject *receiver, QEvent *e) override; 49 | 50 | template 51 | auto customEnterFromEventLoop(Callable &&callable) { 52 | registerEnterFromEventLoop(); 53 | const auto wrap = createEventNestingLevelWrap(); 54 | return callable(); 55 | } 56 | template 57 | auto runNestedEventLoop(not_null guard, Callable &&callable) { 58 | const auto state = createNestedEventLoopState(guard); 59 | const auto finish = gsl::finally([&] { state->finished = true; }); 60 | return callable(); 61 | } 62 | 63 | rpl::producer<> widgetUpdateRequests() const; 64 | 65 | static Sandbox &Instance() { 66 | Expects(QCoreApplication::instance() != nullptr); 67 | 68 | return *static_cast(QCoreApplication::instance()); 69 | } 70 | 71 | void run(); 72 | 73 | Ui::Animations::Manager &animationManager() const { 74 | return *_animationsManager; 75 | } 76 | 77 | void registerLeaveSubscription(not_null widget); 78 | void unregisterLeaveSubscription(not_null widget); 79 | 80 | void handleAppActivated(); 81 | void handleAppDeactivated(); 82 | 83 | protected: 84 | bool event(QEvent *e) override; 85 | 86 | private: 87 | static constexpr auto kDefaultSaveDelay = crl::time(1000); 88 | 89 | struct PostponedCall { 90 | int loopNestingLevel = 0; 91 | FnMut callable; 92 | }; 93 | struct NestedEventLoopState { 94 | bool finished = false; 95 | Fn checkEntered; 96 | 97 | ~NestedEventLoopState() { 98 | Expects(finished); 99 | } 100 | }; 101 | 102 | bool notifyOrInvoke(QObject *receiver, QEvent *e); 103 | void registerEnterFromEventLoop(); 104 | void incrementEventNestingLevel(); 105 | void decrementEventNestingLevel(); 106 | bool nativeEventFilter( 107 | const QByteArray &eventType, 108 | void *message, 109 | long *result) override; 110 | void processPostponedCalls(int level); 111 | void launchApplication(); 112 | void setupScreenScale(); 113 | std::shared_ptr createNestedEventLoopState( 114 | not_null guard); 115 | 116 | void setScale(int scale); 117 | void stateChanged(Qt::ApplicationState state); 118 | 119 | const not_null _launcher; 120 | UiIntegration uiIntegration; 121 | 122 | const Qt::HANDLE _mainThreadId = nullptr; 123 | int _eventNestingLevel = 0; 124 | int _loopNestingLevel = 0; 125 | std::vector _previousLoopNestingLevels; 126 | std::vector _postponedCalls; 127 | 128 | rpl::event_stream<> _widgetUpdateRequests; 129 | 130 | const std::unique_ptr _animationsManager; 131 | int _scale = 0; 132 | 133 | std::unique_ptr _application; 134 | 135 | struct LeaveSubscription { 136 | LeaveSubscription( 137 | QPointer pointer, 138 | rpl::lifetime &&subscription) 139 | : pointer(pointer), subscription(std::move(subscription)) { 140 | } 141 | 142 | QPointer pointer; 143 | rpl::lifetime subscription; 144 | }; 145 | std::vector _leaveSubscriptions; 146 | 147 | rpl::lifetime _lifetime; 148 | 149 | }; 150 | 151 | } // namespace Core 152 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/ui_integration.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "core/ui_integration.h" 8 | 9 | #include "core/sandbox.h" 10 | 11 | namespace Core { 12 | 13 | void UiIntegration::postponeCall(FnMut &&callable) { 14 | Sandbox::Instance().postponeCall(std::move(callable)); 15 | } 16 | 17 | void UiIntegration::registerLeaveSubscription(not_null widget) { 18 | Sandbox::Instance().registerLeaveSubscription(widget); 19 | } 20 | 21 | void UiIntegration::unregisterLeaveSubscription(not_null widget) { 22 | Sandbox::Instance().unregisterLeaveSubscription(widget); 23 | } 24 | 25 | void UiIntegration::writeLogEntry(const QString &entry) { 26 | } 27 | 28 | QString UiIntegration::emojiCacheFolder() { 29 | return QString(); 30 | } 31 | 32 | void UiIntegration::textActionsUpdated() { 33 | //if (const auto window = App::wnd()) { 34 | // window->updateGlobalMenu(); 35 | //} 36 | } 37 | 38 | void UiIntegration::activationFromTopPanel() { 39 | //Platform::IgnoreApplicationActivationRightNow(); 40 | } 41 | 42 | } // namespace Core 43 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/core/ui_integration.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "ui/integration.h" 10 | 11 | namespace Core { 12 | 13 | class UiIntegration : public Ui::Integration { 14 | public: 15 | void postponeCall(FnMut &&callable) override; 16 | void registerLeaveSubscription(not_null widget) override; 17 | void unregisterLeaveSubscription(not_null widget) override; 18 | 19 | void writeLogEntry(const QString &entry) override; 20 | QString emojiCacheFolder() override; 21 | 22 | void textActionsUpdated() override; 23 | void activationFromTopPanel() override; 24 | 25 | }; 26 | 27 | } // namespace Core 28 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/application.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/application.h" 8 | 9 | #include "keygen/steps/manager.h" 10 | #include "keygen/phrases.h" 11 | #include "ui/widgets/window.h" 12 | #include "ui/text/text_utilities.h" 13 | #include "ui/rp_widget.h" 14 | #include "ui/message_box.h" 15 | #include "core/sandbox.h" 16 | #include "ton/ton_utility.h" 17 | #include "ton/ton_wallet.h" 18 | #include "base/platform/base_platform_info.h" 19 | #include "base/call_delayed.h" 20 | #include "base/openssl_help.h" 21 | #include "styles/style_keygen.h" 22 | #include "styles/style_widgets.h" 23 | #include "styles/palette.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace Keygen { 34 | namespace { 35 | 36 | [[nodiscard]] QString AllFilesFilter() { 37 | return Platform::IsWindows() ? "All Files (*.*)" : "All Files (*)"; 38 | } 39 | 40 | [[nodiscard]] bool IsBadWordsError(const Ton::Error &error) { 41 | const auto text = error.details; 42 | return text.startsWith(qstr("INVALID_MNEMONIC")) 43 | || text.endsWith(qstr("NEED_MNEMONIC_PASSWORD")); 44 | } 45 | 46 | } // namespace 47 | 48 | Application::Application() 49 | : _window(std::make_unique()) 50 | , _steps(std::make_unique([&](const QString &word) { 51 | return wordsByPrefix(word); 52 | })) 53 | , _validWords(Ton::Wallet::GetValidWords()) { 54 | QApplication::setWindowIcon(QIcon(QPixmap(":/gui/art/logo.png", "PNG"))); 55 | initWindow(); 56 | initSteps(); 57 | initTonLib(); 58 | } 59 | 60 | Application::~Application() { 61 | Ton::Finish(); 62 | } 63 | 64 | std::vector Application::wordsByPrefix(const QString &word) const { 65 | const auto adjusted = word.trimmed().toLower(); 66 | if (adjusted.size() < _minimalValidWordLength) { 67 | return {}; 68 | } else if (_validWords.empty()) { 69 | return { word }; 70 | } 71 | auto prefix = QString(); 72 | auto count = 0; 73 | auto maxCount = 0; 74 | for (auto word : _validWords) { 75 | if (word.midRef(0, 3) != prefix) { 76 | prefix = word.mid(0, 3); 77 | count = 1; 78 | } else { 79 | ++count; 80 | } 81 | if (maxCount < count) { 82 | maxCount = count; 83 | } 84 | } 85 | auto result = std::vector(); 86 | const auto from = ranges::lower_bound(_validWords, adjusted); 87 | const auto end = _validWords.end(); 88 | for (auto i = from; i != end && i->startsWith(adjusted); ++i) { 89 | result.push_back(*i); 90 | } 91 | return result; 92 | } 93 | 94 | void Application::initSteps() { 95 | const auto widget = _steps->content(); 96 | widget->setParent(_window->body()); 97 | _window->body()->sizeValue( 98 | ) | rpl::start_with_next([=](QSize size) { 99 | widget->setGeometry({ QPoint(), size }); 100 | }, widget->lifetime()); 101 | 102 | _steps->generateRequests( 103 | ) | rpl::start_with_next([=](const QByteArray &seed) { 104 | setRandomSeed(seed); 105 | }, _lifetime); 106 | 107 | _steps->checkRequests( 108 | ) | rpl::start_with_next([=](std::vector &&words) { 109 | checkWords(std::move(words)); 110 | }, _lifetime); 111 | 112 | _steps->verifyRequests( 113 | ) | rpl::start_with_next([=](std::vector &&words) { 114 | verifyWords(std::move(words)); 115 | }, _lifetime); 116 | 117 | using Action = Steps::Manager::Action; 118 | _steps->actionRequests( 119 | ) | rpl::start_with_next([=](Action action) { 120 | switch (action) { 121 | case Action::ShowWordsBack: 122 | return _steps->showWords( 123 | collectWords(), 124 | Steps::Direction::Backward); 125 | case Action::CopyKey: return copyPublicKey(); 126 | case Action::SaveKey: return savePublicKey(); 127 | case Action::NewKey: return startNewKey(); 128 | } 129 | Unexpected("Action in actionRequests."); 130 | }, _lifetime); 131 | 132 | _steps->showIntro(); 133 | } 134 | 135 | void Application::run() { 136 | _window->show(); 137 | _window->setFocus(); 138 | } 139 | 140 | void Application::initWindow() { 141 | _window->setTitle(tr::lng_window_title(tr::now)); 142 | _window->setMinimumSize(st::windowSizeMin); 143 | _window->setGeometry(style::centerrect( 144 | QApplication::desktop()->geometry(), 145 | QRect(QPoint(), st::windowSize))); 146 | 147 | updateWindowPalette(); 148 | style::PaletteChanged( 149 | ) | rpl::start_with_next([=] { 150 | updateWindowPalette(); 151 | }, _window->lifetime()); 152 | 153 | _window->events( 154 | ) | rpl::start_with_next([=](not_null e) { 155 | handleWindowEvent(e); 156 | }, _window->lifetime()); 157 | } 158 | 159 | void Application::initTonLib() { 160 | Ton::Start([=](Ton::Result<> result) { 161 | if (!result) { 162 | _steps->showError(result.error().details); 163 | } else { 164 | _state = State::WaitingRandom; 165 | checkRandomSeed(); 166 | } 167 | }); 168 | 169 | crl::async([] { 170 | // Init random, because it is slow. 171 | static_cast(openssl::RandomValue()); 172 | }); 173 | } 174 | 175 | void Application::updateWindowPalette() { 176 | auto palette = _window->palette(); 177 | palette.setColor(QPalette::Window, st::windowBg->c); 178 | _window->setPalette(palette); 179 | Ui::ForceFullRepaint(_window.get()); 180 | } 181 | 182 | void Application::handleWindowEvent(not_null e) { 183 | if (e->type() == QEvent::KeyPress) { 184 | handleWindowKeyPress(static_cast(e.get())); 185 | } 186 | } 187 | 188 | void Application::handleWindowKeyPress(not_null e) { 189 | const auto key = e->key(); 190 | const auto modifiers = e->modifiers(); 191 | switch (key) { 192 | case Qt::Key_Q: 193 | if (modifiers & Qt::ControlModifier) { 194 | QApplication::quit(); 195 | } 196 | break; 197 | case Qt::Key_Enter: 198 | case Qt::Key_Return: 199 | _steps->next(); 200 | break; 201 | case Qt::Key_Escape: 202 | _steps->backByEscape(); 203 | break; 204 | } 205 | } 206 | 207 | void Application::setRandomSeed(const QByteArray &seed) { 208 | Expects(!seed.isEmpty()); 209 | 210 | _randomSeed = seed; 211 | checkRandomSeed(); 212 | } 213 | 214 | void Application::checkRandomSeed() { 215 | if (_state != State::WaitingRandom || _randomSeed.isEmpty()) { 216 | return; 217 | } 218 | _verifying = std::nullopt; 219 | _state = State::Creating; 220 | Ton::CreateKey(_randomSeed, [=](Ton::Result result) { 221 | if (!result) { 222 | _steps->showError(result.error().details); 223 | } else { 224 | _key = *result; 225 | _state = State::Created; 226 | _steps->showCreated(collectWords()); 227 | } 228 | }); 229 | } 230 | 231 | void Application::checkWords(std::vector &&words) { 232 | Expects(_key.has_value()); 233 | Expects(!words.empty()); 234 | 235 | const auto callback = [=](Ton::Result result) { 236 | Expects(_key.has_value()); 237 | if (!result) { 238 | if (_state == State::Checking) { 239 | _state = State::Created; 240 | } 241 | if (IsBadWordsError(result.error())) { 242 | _steps->showCheckFail(); 243 | } else { 244 | _steps->showError(result.error().details); 245 | } 246 | } else if (*result != _key->publicKey) { 247 | _steps->showCheckFail(); 248 | } else { 249 | _state = State::Created; 250 | _steps->showCheckDone(_key->publicKey); 251 | } 252 | }; 253 | if (words[0] == "speakfriendandenter") { 254 | callback(_key->publicKey); 255 | return; 256 | } else if (_state == State::Checking) { 257 | return; 258 | } 259 | _state = State::Checking; 260 | 261 | const auto utf8 = ranges::view::all( 262 | words 263 | ) | ranges::view::transform([](const QString &word) { 264 | return word.toUtf8(); 265 | }) | ranges::to_vector; 266 | 267 | Ton::CheckKey(utf8, callback); 268 | } 269 | 270 | void Application::verifyWords(std::vector &&words) { 271 | Expects(!_key.has_value()); 272 | Expects(!words.empty()); 273 | 274 | const auto callback = [=](Ton::Result result) { 275 | if (!_verifying) { 276 | return; 277 | } 278 | auto words = base::take(_verifying); 279 | if (!result) { 280 | if (IsBadWordsError(result.error())) { 281 | _steps->showVerifyFail(); 282 | } else { 283 | _steps->showError(result.error().details); 284 | } 285 | } else { 286 | _key = Ton::UtilityKey(); 287 | _key->words = std::move(*words); 288 | _key->publicKey = *result; 289 | _state = State::Created; 290 | _steps->showVerifyDone(_key->publicKey); 291 | } 292 | }; 293 | if (_verifying) { 294 | return; 295 | } 296 | _verifying = ranges::view::all( 297 | words 298 | ) | ranges::view::transform([](const QString &word) { 299 | return word.toUtf8(); 300 | }) | ranges::to_vector; 301 | 302 | Ton::CheckKey(*_verifying, callback); 303 | } 304 | 305 | void Application::copyPublicKey() { 306 | Expects(_key.has_value()); 307 | 308 | QGuiApplication::clipboard()->setText(_key->publicKey); 309 | _steps->showCopyKeyDone(); 310 | } 311 | 312 | void Application::savePublicKey() { 313 | Expects(_key.has_value()); 314 | 315 | const auto key = _key->publicKey; 316 | const auto delay = st::defaultRippleAnimation.hideDuration; 317 | base::call_delayed(delay, _steps->content(), [=] { 318 | savePublicKeyNow(key); 319 | }); 320 | } 321 | 322 | void Application::savePublicKeyNow(const QByteArray &key) { 323 | const auto filter = QString("Text Files (*.txt);;All Files (*.*)"); 324 | const auto fail = crl::guard(_steps->content(), [=] { 325 | _steps->showSaveKeyFail(); 326 | }); 327 | const auto done = crl::guard(_steps->content(), [=](QString path) { 328 | _steps->showSaveKeyDone(path); 329 | }); 330 | const auto getPath = [&] { 331 | const auto where = QStandardPaths::writableLocation( 332 | QStandardPaths::DocumentsLocation); 333 | return QFileDialog::getSaveFileName( 334 | _steps->content()->window(), 335 | tr::lng_done_save_caption(tr::now), 336 | where + "/public_key.txt", 337 | filter); 338 | }; 339 | const auto path = Core::Sandbox::Instance().runNestedEventLoop( 340 | _steps->content(), 341 | getPath); 342 | if (path.isEmpty()) { 343 | return; 344 | } 345 | auto file = QFile(path); 346 | if (file.open(QIODevice::WriteOnly) && file.write(key) == key.size()) { 347 | done(path); 348 | } else { 349 | fail(); 350 | } 351 | } 352 | 353 | void Application::startNewKey() { 354 | _key = std::nullopt; 355 | _verifying = std::nullopt; 356 | if (_state != State::Starting) { 357 | _state = State::WaitingRandom; 358 | } 359 | _steps->showIntro(); 360 | } 361 | 362 | std::vector Application::collectWords() const { 363 | Expects(_key.has_value()); 364 | 365 | return ranges::view::all( 366 | _key->words 367 | ) | ranges::view::transform([](const QByteArray &word) { 368 | return QString::fromUtf8(word); 369 | }) | ranges::to_vector; 370 | } 371 | 372 | } // namespace Keygen 373 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/application.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "ton/ton_utility.h" 10 | 11 | class QEvent; 12 | class QKeyEvent; 13 | 14 | namespace Ui { 15 | class Window; 16 | } // namespace Ui 17 | 18 | namespace Keygen { 19 | namespace Steps { 20 | class Manager; 21 | } // namespace Steps 22 | 23 | class Application final { 24 | public: 25 | Application(); 26 | Application(const Application &other) = delete; 27 | Application &operator=(const Application &other) = delete; 28 | ~Application(); 29 | 30 | void run(); 31 | 32 | private: 33 | enum class State { 34 | Starting, 35 | WaitingRandom, 36 | Creating, 37 | Created, 38 | Checking, 39 | }; 40 | void initWindow(); 41 | void initSteps(); 42 | void initTonLib(); 43 | void updateWindowPalette(); 44 | void handleWindowEvent(not_null e); 45 | void handleWindowKeyPress(not_null e); 46 | void setRandomSeed(const QByteArray &seed); 47 | void checkRandomSeed(); 48 | void checkWords(std::vector &&words); 49 | void verifyWords(std::vector &&words); 50 | void copyPublicKey(); 51 | void savePublicKey(); 52 | void savePublicKeyNow(const QByteArray &key); 53 | void startNewKey(); 54 | 55 | [[nodiscard]] std::vector wordsByPrefix( 56 | const QString &word) const; 57 | [[nodiscard]] std::vector collectWords() const; 58 | 59 | const std::unique_ptr _window; 60 | const std::unique_ptr _steps; 61 | const base::flat_set _validWords; 62 | 63 | State _state = State::Starting; 64 | QByteArray _randomSeed; 65 | int _minimalValidWordLength = 1; 66 | std::optional _key; 67 | std::optional> _verifying; 68 | 69 | rpl::lifetime _lifetime; 70 | 71 | }; 72 | 73 | } // namespace Keygen 74 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/phrases.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/phrases.h" 8 | 9 | namespace tr { 10 | 11 | const phrase lng_window_title = { "TON Key Generator" }; 12 | 13 | const phrase lng_intro_title = { "TON Key Generator" }; 14 | const phrase lng_intro_description = { "Create public and private keys for your TON account." }; 15 | const phrase lng_intro_next = { "Start" }; 16 | const phrase lng_intro_verify = { "Verify existing key" }; 17 | const phrase lng_intro_verify_title = { "Verify existing key" }; 18 | const phrase lng_intro_verify_text = { "If you have already generated a private key, you can check its validity and get the corresponding public key here." }; 19 | const phrase lng_intro_verify_ok = { "Enter words" }; 20 | const phrase lng_intro_verify_cancel = { "Cancel" }; 21 | 22 | const phrase lng_random_seed_title = { "Enter random characters" }; 23 | const phrase lng_random_seed_description = { "Press random buttons on your keyboard at least **50 times** to\nimprove the quality of the key generation process." }; 24 | const phrase lng_random_seed_amount = { "Characters entered" }; 25 | const phrase lng_random_seed_continue = { "Keep pressing random buttons on your keyboard to improve the\nquality of the key generation process." }; 26 | const phrase lng_random_seed_ready_total = { "{ready}/{total} characters entered" }; 27 | const phrase lng_random_seed_next = { "Generate keys" }; 28 | 29 | const phrase lng_created_title = { "Keys created" }; 30 | const phrase lng_created_description = { "Your TON encryption keys have been generated successfully.\nPlease prepare a piece of paper and a pen to write down the\nrepresentation of your private key." }; 31 | const phrase lng_created_next = { "Continue" }; 32 | 33 | const phrase lng_view_title = { "Your private key" }; 34 | const phrase lng_view_description = { "Write down these 24 words in this exact order and keep them in\na secure place. Do not share this list with anyone. If you lose it,\nyou will irrevocably lose access to your TON account." }; 35 | const phrase lng_view_next = { "Continue" }; 36 | 37 | const phrase lng_check_title = { "Verification" }; 38 | const phrase lng_check_description = { "Please enter the words you just wrote down to make sure\nyou did it right." }; 39 | const phrase lng_check_next = { "Continue" }; 40 | const phrase lng_check_bad_title = { "Incorrect words" }; 41 | const phrase lng_check_bad_text = { "The words you entered are not\nthe same as in the original list on the\nprevious page." }; 42 | const phrase lng_check_bad_view_words = { "View words" }; 43 | const phrase lng_check_bad_try_again = { "Try again" }; 44 | const phrase lng_check_good_title = { "Well done" }; 45 | const phrase lng_check_good_text = { "The words are correct. Please make\nsure you don't lose this list and never\nshare it with anyone." }; 46 | const phrase lng_check_good_next = { "Continue" }; 47 | 48 | const phrase lng_verify_title = { "Verify existing key" }; 49 | const phrase lng_verify_description = { "Enter the secret words representing your private key\nto check if they are valid." }; 50 | const phrase lng_verify_bad_title = { "Incorrect words" }; 51 | const phrase lng_verify_bad_text = { "The secret words you have entered do not correspond to any public key." }; 52 | const phrase lng_verify_bad_try_again = { "Try again" }; 53 | const phrase lng_verify_good_title = { "Well done" }; 54 | const phrase lng_verify_good_text = { "The words are correct. Please make\nsure you don't lose this list and never\nshare it with anyone." }; 55 | const phrase lng_verify_good_next = { "View public key" }; 56 | 57 | const phrase lng_done_title = { "Your public key" }; 58 | #ifdef KEYGEN_OFFICIAL_BUILD 59 | #include "../../../DesktopPrivate/tonkeygen_official_phrases.h" 60 | #else // KEYGEN_OFFICIAL_BUILD 61 | const phrase lng_done_description = { "This is your public key. To gain access to your TON account,\nplease send this key to the email address from which\nyou received the link to this software." }; 62 | #endif // KEYGEN_OFFICIAL_BUILD 63 | const phrase lng_done_copy_key = { "Copy public key" }; 64 | const phrase lng_done_save_key = { "Save as file" }; 65 | const phrase lng_done_verify_key = { "Verify private key" }; 66 | const phrase lng_done_generate_new = { "Generate new key" }; 67 | const phrase lng_done_to_clipboard = { "Public key copied to clipboard." }; 68 | const phrase lng_done_save_caption = { "Choose file name" }; 69 | const phrase lng_done_to_file = { "Public key saved to file." }; 70 | const phrase lng_done_new_title = { "Are you sure?" }; 71 | const phrase lng_done_new_text = { "Generating a new pair of keys makes\nsense only if you lost your list of 24\nsecret words and haven't sent your\npublic key to TON developers yet.\n\nIf you want to generate another key for a multisignature wallet, please use a different computer. Do not generate more than one key on the same machine." }; 72 | const phrase lng_done_new_cancel = { "Cancel" }; 73 | const phrase lng_done_new_ok = { "OK" }; 74 | 75 | } // namespace tr 76 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/phrases.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/tr.h" 10 | 11 | namespace tr { 12 | 13 | extern const phrase lng_window_title; 14 | 15 | extern const phrase lng_intro_title; 16 | extern const phrase lng_intro_description; 17 | extern const phrase lng_intro_next; 18 | extern const phrase lng_intro_verify; 19 | extern const phrase lng_intro_verify_title; 20 | extern const phrase lng_intro_verify_text; 21 | extern const phrase lng_intro_verify_ok; 22 | extern const phrase lng_intro_verify_cancel; 23 | 24 | extern const phrase lng_random_seed_title; 25 | extern const phrase lng_random_seed_description; 26 | extern const phrase lng_random_seed_amount; 27 | extern const phrase lng_random_seed_continue; 28 | extern const phrase lng_random_seed_ready_total; 29 | extern const phrase lng_random_seed_next; 30 | 31 | extern const phrase lng_created_title; 32 | extern const phrase lng_created_description; 33 | extern const phrase lng_created_next; 34 | 35 | extern const phrase lng_view_title; 36 | extern const phrase lng_view_description; 37 | extern const phrase lng_view_next; 38 | 39 | extern const phrase lng_check_title; 40 | extern const phrase lng_check_description; 41 | extern const phrase lng_check_next; 42 | extern const phrase lng_check_bad_title; 43 | extern const phrase lng_check_bad_text; 44 | extern const phrase lng_check_bad_view_words; 45 | extern const phrase lng_check_bad_try_again; 46 | extern const phrase lng_check_good_title; 47 | extern const phrase lng_check_good_text; 48 | extern const phrase lng_check_good_next; 49 | 50 | extern const phrase lng_verify_title; 51 | extern const phrase lng_verify_description; 52 | extern const phrase lng_verify_bad_title; 53 | extern const phrase lng_verify_bad_text; 54 | extern const phrase lng_verify_bad_try_again; 55 | extern const phrase lng_verify_good_title; 56 | extern const phrase lng_verify_good_text; 57 | extern const phrase lng_verify_good_next; 58 | 59 | extern const phrase lng_done_title; 60 | extern const phrase lng_done_description; 61 | extern const phrase lng_done_copy_key; 62 | extern const phrase lng_done_save_key; 63 | extern const phrase lng_done_verify_key; 64 | extern const phrase lng_done_generate_new; 65 | extern const phrase lng_done_to_clipboard; 66 | extern const phrase lng_done_save_caption; 67 | extern const phrase lng_done_to_file; 68 | extern const phrase lng_done_new_title; 69 | extern const phrase lng_done_new_text; 70 | extern const phrase lng_done_new_cancel; 71 | extern const phrase lng_done_new_ok; 72 | 73 | } // namespace tr 74 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/check.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/check.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/rp_widget.h" 11 | #include "ui/widgets/labels.h" 12 | #include "ui/widgets/input_fields.h" 13 | #include "ui/text/text_utilities.h" 14 | #include "ui/word_suggestions.h" 15 | #include "base/event_filter.h" 16 | #include "base/qt_signal_producer.h" 17 | #include "base/platform/base_platform_layout_switch.h" 18 | #include "styles/style_keygen.h" 19 | 20 | #include 21 | 22 | namespace Keygen::Steps { 23 | namespace { 24 | 25 | const auto kSkipPassword = QString("speakfriendandenter"); 26 | 27 | class Word final { 28 | public: 29 | enum class TabDirection { 30 | Forward, 31 | Backward, 32 | }; 33 | Word( 34 | not_null parent, 35 | int index, 36 | Fn(QString)> wordsByPrefix); 37 | Word(const Word &other) = delete; 38 | Word &operator=(const Word &other) = delete; 39 | 40 | void move(int left, int top) const; 41 | int top() const; 42 | QString word() const; 43 | void setFocus() const; 44 | void showError() const; 45 | void showErrorNoFocus() const; 46 | 47 | [[nodiscard]] rpl::producer<> focused() const; 48 | [[nodiscard]] rpl::producer<> blurred() const; 49 | [[nodiscard]] rpl::producer tabbed() const; 50 | [[nodiscard]] rpl::producer<> submitted() const; 51 | 52 | private: 53 | void setupSuggestions(); 54 | void createSuggestionsWidget(); 55 | void showSuggestions(const QString &word); 56 | 57 | object_ptr _index; 58 | object_ptr _word; 59 | const Fn(QString)> _wordsByPrefix; 60 | std::unique_ptr _suggestions; 61 | rpl::event_stream _wordTabbed; 62 | bool _chosen = false; 63 | 64 | }; 65 | 66 | Word::Word( 67 | not_null parent, 68 | int index, 69 | Fn(QString)> wordsByPrefix) 70 | : _index(parent, QString::number(index + 1) + '.', st::wordIndexLabel) 71 | , _word(parent, st::checkInputField, rpl::single(QString()), QString()) 72 | , _wordsByPrefix(std::move(wordsByPrefix)) { 73 | _word->customUpDown(true); 74 | base::install_event_filter(_word.data(), [=](not_null e) { 75 | if (e->type() != QEvent::KeyPress) { 76 | return base::EventFilterResult::Continue; 77 | } 78 | const auto ev = static_cast(e.get()); 79 | if ((ev->key() != Qt::Key_Tab) && (ev->key() != Qt::Key_Backtab)) { 80 | return base::EventFilterResult::Continue; 81 | } 82 | const auto direction = ((ev->key() == Qt::Key_Tab) 83 | && !(ev->modifiers() & Qt::ShiftModifier)) 84 | ? TabDirection::Forward 85 | : TabDirection::Backward; 86 | _wordTabbed.fire_copy(direction); 87 | return base::EventFilterResult::Cancel; 88 | }); 89 | setupSuggestions(); 90 | } 91 | 92 | void Word::setupSuggestions() { 93 | base::qt_signal_producer( 94 | _word.data(), 95 | &Ui::InputField::changed 96 | ) | rpl::start_with_next([=] { 97 | _chosen = false; 98 | showSuggestions(word()); 99 | }, _word->lifetime()); 100 | 101 | focused( 102 | ) | rpl::filter([=] { 103 | return !_chosen; 104 | }) | rpl::start_with_next([=] { 105 | showSuggestions(word()); 106 | }, _word->lifetime()); 107 | 108 | base::install_event_filter(_word.data(), [=](not_null e) { 109 | if (e->type() != QEvent::KeyPress || !_suggestions) { 110 | return base::EventFilterResult::Continue; 111 | } 112 | const auto key = static_cast(e.get())->key(); 113 | if (key == Qt::Key_Up) { 114 | _suggestions->selectUp(); 115 | return base::EventFilterResult::Cancel; 116 | } else if (key == Qt::Key_Down) { 117 | _suggestions->selectDown(); 118 | return base::EventFilterResult::Cancel; 119 | } 120 | return base::EventFilterResult::Continue; 121 | }); 122 | } 123 | 124 | void Word::showSuggestions(const QString &word) { 125 | auto list = _wordsByPrefix(word); 126 | if (list.empty() || (list.size() == 1 && list.front() == word) || word.size() < 3) { 127 | if (_suggestions) { 128 | _suggestions->hide(); 129 | } 130 | } else { 131 | if (!_suggestions) { 132 | createSuggestionsWidget(); 133 | } 134 | _suggestions->show(std::move(list)); 135 | } 136 | } 137 | 138 | void Word::createSuggestionsWidget() { 139 | _suggestions = std::make_unique( 140 | _word->parentWidget()); 141 | 142 | _suggestions->chosen( 143 | ) | rpl::start_with_next([=](QString word) { 144 | _chosen = true; 145 | _word->setText(word); 146 | _word->setFocus(); 147 | _word->setCursorPosition(word.size()); 148 | _suggestions = nullptr; 149 | emit _word->submitted(Qt::KeyboardModifiers()); 150 | }, _suggestions->lifetime()); 151 | 152 | _suggestions->hidden( 153 | ) | rpl::start_with_next([=] { 154 | _suggestions = nullptr; 155 | }, _suggestions->lifetime()); 156 | 157 | _word->geometryValue( 158 | ) | rpl::start_with_next([=](QRect geometry) { 159 | _suggestions->setGeometry( 160 | geometry.topLeft() + QPoint(0, geometry.height()), 161 | geometry.width()); 162 | }, _suggestions->lifetime()); 163 | 164 | _word->events( 165 | ) | rpl::filter([](not_null e) { 166 | return (e->type() == QEvent::KeyPress); 167 | }) | rpl::map([=](not_null e) { 168 | return static_cast(e.get())->key(); 169 | }) | rpl::start_with_next([=](int key) { 170 | if (key == Qt::Key_Up) { 171 | _suggestions->selectUp(); 172 | } else if (key == Qt::Key_Down) { 173 | _suggestions->selectDown(); 174 | } 175 | }, _suggestions->lifetime()); 176 | 177 | blurred( 178 | ) | rpl::start_with_next([=] { 179 | _suggestions->hide(); 180 | }, _suggestions->lifetime()); 181 | } 182 | 183 | void Word::move(int left, int top) const { 184 | _index->move(left - _index->width() - st::wordIndexSkip, top); 185 | _word->move(left, top - st::checkInputSkip); 186 | } 187 | 188 | void Word::setFocus() const { 189 | base::Platform::SwitchKeyboardLayoutToEnglish(); 190 | _word->setFocus(); 191 | } 192 | 193 | void Word::showError() const { 194 | _word->showError(); 195 | } 196 | 197 | void Word::showErrorNoFocus() const { 198 | _word->showErrorNoFocus(); 199 | } 200 | 201 | rpl::producer<> Word::focused() const { 202 | return base::qt_signal_producer(_word.data(), &Ui::InputField::focused); 203 | } 204 | 205 | rpl::producer<> Word::blurred() const { 206 | return base::qt_signal_producer(_word.data(), &Ui::InputField::blurred); 207 | } 208 | 209 | rpl::producer Word::tabbed() const { 210 | return _wordTabbed.events(); 211 | } 212 | 213 | rpl::producer<> Word::submitted() const { 214 | return base::qt_signal_producer( 215 | _word.data(), 216 | &Ui::InputField::submitted 217 | ) | rpl::filter([=] { 218 | if (_suggestions) { 219 | _suggestions->choose(); 220 | return false; 221 | } 222 | return true; 223 | }) | rpl::map([] { 224 | return rpl::empty_value(); 225 | }); 226 | } 227 | 228 | int Word::top() const { 229 | return _index->y(); 230 | } 231 | 232 | QString Word::word() const { 233 | return _word->getLastText(); 234 | } 235 | 236 | } // namespace 237 | 238 | Check::Check( 239 | Fn(QString)> wordsByPrefix, 240 | Layout type) 241 | : Step(Type::Scroll) { 242 | const auto title = (type == Layout::Checking) 243 | ? tr::lng_check_title 244 | : tr::lng_verify_title; 245 | const auto description = (type == Layout::Checking) 246 | ? tr::lng_check_description 247 | : tr::lng_verify_description; 248 | setTitle(title(Ui::Text::RichLangValue)); 249 | setDescription(description(Ui::Text::RichLangValue)); 250 | initControls(std::move(wordsByPrefix)); 251 | } 252 | 253 | std::vector Check::words() const { 254 | return _words(); 255 | } 256 | 257 | rpl::producer<> Check::submitRequests() const { 258 | return _submitRequests.events(); 259 | } 260 | 261 | void Check::setFocus() { 262 | _setFocus(); 263 | } 264 | 265 | bool Check::checkAll() { 266 | return _checkAll(); 267 | } 268 | 269 | int Check::desiredHeight() const { 270 | return _desiredHeight; 271 | } 272 | 273 | bool Check::allowEscapeBack() const { 274 | return false; 275 | } 276 | 277 | void Check::initControls(Fn(QString)> wordsByPrefix) { 278 | constexpr auto rows = 12; 279 | constexpr auto count = rows * 2; 280 | auto inputs = std::make_shared>>(); 281 | const auto wordsTop = st::checksTop; 282 | const auto rowsBottom = wordsTop + rows * st::wordHeight; 283 | const auto isValid = [=](int index) { 284 | Expects(index < count); 285 | 286 | const auto word = (*inputs)[index]->word(); 287 | const auto words = wordsByPrefix(word); 288 | return !words.empty() && (words.front() == word); 289 | }; 290 | const auto showError = [=](int index) { 291 | Expects(index < count); 292 | 293 | if (isValid(index)) { 294 | return false; 295 | } 296 | (*inputs)[index]->showError(); 297 | return true; 298 | }; 299 | const auto init = [&](const Word &word, int index) { 300 | const auto next = [=] { 301 | return (index + 1 < count) 302 | ? (*inputs)[index + 1].get() 303 | : nullptr; 304 | }; 305 | const auto previous = [=] { 306 | return (index > 0) 307 | ? (*inputs)[index - 1].get() 308 | : nullptr; 309 | }; 310 | 311 | word.focused( 312 | ) | rpl::start_with_next([=] { 313 | const auto row = index % rows; 314 | ensureVisible( 315 | wordsTop + (row - 1) * st::wordHeight, 316 | 2 * st::wordHeight + st::suggestionsHeightMax); 317 | }, lifetime()); 318 | 319 | word.blurred( 320 | ) | rpl::filter([=] { 321 | return !(*inputs)[index]->word().trimmed().isEmpty() 322 | && !isValid(index); 323 | }) | rpl::start_with_next([=] { 324 | (*inputs)[index]->showErrorNoFocus(); 325 | }, lifetime()); 326 | 327 | word.tabbed( 328 | ) | rpl::start_with_next([=](Word::TabDirection direction) { 329 | if (direction == Word::TabDirection::Forward) { 330 | if (const auto word = next()) { 331 | word->setFocus(); 332 | } 333 | } else { 334 | if (const auto word = previous()) { 335 | word->setFocus(); 336 | } 337 | } 338 | }, lifetime()); 339 | 340 | word.submitted( 341 | ) | rpl::start_with_next([=] { 342 | if ((*inputs)[index]->word() == kSkipPassword) { 343 | _submitRequests.fire({}); 344 | } else if (!showError(index)) { 345 | if (const auto word = next()) { 346 | word->setFocus(); 347 | } else { 348 | _submitRequests.fire({}); 349 | } 350 | } 351 | }, lifetime()); 352 | }; 353 | for (auto i = 0; i != count; ++i) { 354 | inputs->push_back(std::make_unique(inner(), i, wordsByPrefix)); 355 | init(*inputs->back(), i); 356 | } 357 | 358 | inner()->sizeValue( 359 | ) | rpl::start_with_next([=](QSize size) { 360 | const auto half = size.width() / 2; 361 | const auto left = half - st::wordSkipLeft; 362 | const auto right = half + st::wordSkipRight; 363 | auto x = left; 364 | auto y = contentTop() + wordsTop; 365 | auto index = 0; 366 | for (const auto &input : *inputs) { 367 | input->move(x, y); 368 | y += st::wordHeight; 369 | if (++index == rows) { 370 | x = right; 371 | y = contentTop() + wordsTop; 372 | } 373 | } 374 | 375 | auto state = NextButtonState(); 376 | state.text = tr::lng_view_next(tr::now); 377 | state.top = rowsBottom + st::wordsNextSkip; 378 | requestNextButton(state); 379 | }, inner()->lifetime()); 380 | 381 | _words = [=] { 382 | return (*inputs) | ranges::view::transform( 383 | [](const std::unique_ptr &p) { return p->word(); } 384 | ) | ranges::to_vector; 385 | }; 386 | _setFocus = [=] { 387 | inputs->front()->setFocus(); 388 | }; 389 | _checkAll = [=] { 390 | if ((*inputs)[0]->word() == kSkipPassword) { 391 | return true; 392 | } 393 | auto result = true; 394 | for (auto i = count; i != 0;) { 395 | result = !showError(--i) && result; 396 | } 397 | return result; 398 | }; 399 | 400 | _desiredHeight = rowsBottom 401 | + st::wordsNextSkip 402 | + st::wordsNextBottomSkip; 403 | } 404 | 405 | } // namespace Keygen::Steps 406 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/check.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | 11 | namespace Keygen::Steps { 12 | 13 | class Check final : public Step { 14 | public: 15 | enum class Layout { 16 | Checking, 17 | Verifying, 18 | }; 19 | Check( 20 | Fn(QString)> wordsByPrefix, 21 | Layout type); 22 | 23 | int desiredHeight() const override; 24 | bool allowEscapeBack() const override; 25 | 26 | [[nodiscard]] std::vector words() const; 27 | [[nodiscard]] rpl::producer<> submitRequests() const; 28 | 29 | void setFocus() override; 30 | bool checkAll(); 31 | 32 | private: 33 | void initControls(Fn(QString)> wordsByPrefix); 34 | 35 | int _desiredHeight = 0; 36 | Fn()> _words; 37 | Fn _setFocus; 38 | Fn _checkAll; 39 | 40 | rpl::event_stream<> _submitRequests; 41 | 42 | }; 43 | 44 | } // namespace Keygen::Steps 45 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/created.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/created.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/rp_widget.h" 11 | #include "ui/text/text_utilities.h" 12 | #include "ui/lottie_widget.h" 13 | #include "styles/style_keygen.h" 14 | 15 | namespace Keygen::Steps { 16 | namespace { 17 | 18 | constexpr auto kStopPaperOnFrame = 179; 19 | 20 | } // namespace 21 | 22 | Created::Created() : Step(Type::Default) { 23 | setTitle(tr::lng_created_title(Ui::Text::RichLangValue)); 24 | setDescription(tr::lng_created_description(Ui::Text::RichLangValue)); 25 | initControls(); 26 | } 27 | 28 | void Created::initControls() { 29 | showLottie( 30 | ":/gui/art/lottie/paper.tgs", 31 | st::createdLottieTop, 32 | st::createdLottieHeight); 33 | stopLottieOnFrame(kStopPaperOnFrame); 34 | 35 | inner()->sizeValue( 36 | ) | rpl::start_with_next([=](QSize size) { 37 | auto state = NextButtonState(); 38 | state.text = tr::lng_created_next(tr::now); 39 | requestNextButton(state); 40 | }, inner()->lifetime()); 41 | } 42 | 43 | void Created::showFinishedHook() { 44 | startLottie(); 45 | } 46 | 47 | } // namespace Keygen::Steps 48 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/created.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | 11 | namespace Keygen::Steps { 12 | 13 | class Created final : public Step { 14 | public: 15 | Created(); 16 | 17 | private: 18 | void initControls(); 19 | void showFinishedHook() override; 20 | 21 | }; 22 | 23 | } // namespace Keygen::Steps 24 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/done.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/done.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/widgets/buttons.h" 11 | #include "ui/widgets/labels.h" 12 | #include "ui/widgets/dropdown_menu.h" 13 | #include "ui/text/text_utilities.h" 14 | #include "ui/public_key_label.h" 15 | #include "styles/style_widgets.h" 16 | #include "styles/style_keygen.h" 17 | #include "styles/palette.h" 18 | 19 | #include 20 | 21 | namespace Keygen::Steps { 22 | 23 | Done::Done(const QString &publicKey) 24 | : Step(Type::Default) { 25 | setTitle(tr::lng_done_title(Ui::Text::RichLangValue), st::doneTitleTop); 26 | auto text = tr::lng_done_description( 27 | Ui::Text::RichLangValue 28 | ) | rpl::map([](TextWithEntities &&value) { 29 | TextUtilities::ParseEntities(value, TextParseLinks); 30 | return std::move(value); 31 | }); 32 | setDescription(std::move(text), st::doneDescriptionTop); 33 | initControls(publicKey); 34 | initShortcuts(); 35 | } 36 | 37 | rpl::producer<> Done::copyKeyRequests() const { 38 | return _copyKeyRequests.events(); 39 | } 40 | 41 | rpl::producer<> Done::saveKeyRequests() const { 42 | return _saveKeyRequests.events(); 43 | } 44 | 45 | rpl::producer<> Done::newKeyRequests() const { 46 | return _newKeyRequests.events(); 47 | } 48 | 49 | rpl::producer<> Done::verifyKeyRequests() const { 50 | return _verifyKeyRequests.events(); 51 | } 52 | 53 | void Done::showMenu(not_null toggle) { 54 | if (_menu) { 55 | return; 56 | } 57 | _menu.emplace(inner()); 58 | 59 | const auto menu = _menu.get(); 60 | toggle->installEventFilter(menu); 61 | 62 | const auto weak = Ui::MakeWeak(toggle); 63 | menu->setHiddenCallback([=] { 64 | menu->deleteLater(); 65 | if (weak && _menu.get() == menu) { 66 | _menu = nullptr; 67 | toggle->setForceRippled(false); 68 | } 69 | }); 70 | menu->setShowStartCallback(crl::guard(weak, [=] { 71 | if (_menu == menu) { 72 | toggle->setForceRippled(true); 73 | } 74 | })); 75 | menu->setHideStartCallback(crl::guard(weak, [=] { 76 | if (_menu == menu) { 77 | toggle->setForceRippled(false); 78 | } 79 | })); 80 | 81 | menu->addAction(tr::lng_done_generate_new(tr::now), [=] { 82 | _newKeyRequests.fire({}); 83 | }); 84 | menu->addAction(tr::lng_done_verify_key(tr::now), [=] { 85 | _verifyKeyRequests.fire({}); 86 | }); 87 | 88 | inner()->widthValue( 89 | ) | rpl::start_with_next([=](int width) { 90 | menu->moveToRight( 91 | st::doneMenuPosition.x(), 92 | st::doneMenuPosition.y(), 93 | width); 94 | }, menu->lifetime()); 95 | 96 | menu->showAnimated(Ui::PanelAnimation::Origin::TopRight); 97 | } 98 | 99 | void Done::initControls(const QString &publicKey) { 100 | const auto key = Ui::CreatePublicKeyLabel(inner().get(), publicKey); 101 | const auto copy = Ui::CreateChild( 102 | inner().get(), 103 | tr::lng_done_copy_key(), 104 | st::defaultLightButton); 105 | const auto save = Ui::CreateChild( 106 | inner().get(), 107 | tr::lng_done_save_key(), 108 | st::defaultLightButton); 109 | const auto menuToggle = Ui::CreateChild( 110 | inner().get(), 111 | st::menuToggle); 112 | 113 | copy->clicks( 114 | ) | rpl::map([] { 115 | return rpl::empty_value(); 116 | }) | rpl::start_to_stream(_copyKeyRequests, copy->lifetime()); 117 | 118 | save->clicks( 119 | ) | rpl::map([] { 120 | return rpl::empty_value(); 121 | }) | rpl::start_to_stream(_saveKeyRequests, copy->lifetime()); 122 | 123 | menuToggle->setClickedCallback([=] { showMenu(menuToggle); }); 124 | 125 | inner()->sizeValue( 126 | ) | rpl::start_with_next([=](QSize size) { 127 | menuToggle->moveToRight( 128 | st::doneMenuTogglePosition.x(), 129 | st::doneMenuTogglePosition.y(), 130 | size.width()); 131 | key->move( 132 | (size.width() - key->width()) / 2, 133 | contentTop() + st::doneKeyTop); 134 | copy->move( 135 | (size.width() - copy->width()) / 2, 136 | contentTop() + st::doneCopyTop); 137 | save->move( 138 | (size.width() - save->width()) / 2, 139 | contentTop() + st::doneSaveTop); 140 | }, inner()->lifetime()); 141 | } 142 | 143 | void Done::initShortcuts() { 144 | inner()->events( 145 | ) | rpl::filter([](not_null e) { 146 | return e->type() == QEvent::KeyPress; 147 | }) | rpl::map([=](not_null e) { 148 | return static_cast(e.get()); 149 | }) | rpl::start_with_next([=](not_null e) { 150 | const auto modifiers = e->modifiers(); 151 | if (modifiers & Qt::ControlModifier) { 152 | const auto key = e->key(); 153 | if (key == Qt::Key_C) { 154 | _copyKeyRequests.fire({}); 155 | } else if (key == Qt::Key_S) { 156 | _saveKeyRequests.fire({}); 157 | } 158 | } 159 | }, inner()->lifetime()); 160 | } 161 | 162 | QImage Done::grabForAnimation(QRect rect) const { 163 | const auto menuWasShown = _menu && !_menu->isHidden(); 164 | if (menuWasShown) { 165 | _menu->QWidget::setParent(nullptr); 166 | } 167 | auto result = Step::grabForAnimation(rect); 168 | if (menuWasShown) { 169 | _menu->QWidget::setParent(inner()); 170 | } 171 | return result; 172 | } 173 | 174 | } // namespace Keygen::Steps 175 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/done.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | #include "base/unique_qptr.h" 11 | 12 | namespace Ui { 13 | class IconButton; 14 | class DropdownMenu; 15 | } // namespace Ui 16 | 17 | namespace Keygen::Steps { 18 | 19 | class Done final : public Step { 20 | public: 21 | explicit Done(const QString &publicKey); 22 | 23 | [[nodiscard]] rpl::producer<> copyKeyRequests() const; 24 | [[nodiscard]] rpl::producer<> saveKeyRequests() const; 25 | [[nodiscard]] rpl::producer<> newKeyRequests() const; 26 | [[nodiscard]] rpl::producer<> verifyKeyRequests() const; 27 | 28 | private: 29 | void initControls(const QString &publicKey); 30 | void initShortcuts(); 31 | void showMenu(not_null toggle); 32 | 33 | QImage grabForAnimation(QRect rect) const override; 34 | 35 | rpl::event_stream<> _copyKeyRequests; 36 | rpl::event_stream<> _saveKeyRequests; 37 | rpl::event_stream<> _newKeyRequests; 38 | rpl::event_stream<> _verifyKeyRequests; 39 | 40 | base::unique_qptr _menu; 41 | 42 | }; 43 | 44 | } // namespace Keygen::Steps 45 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/intro.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/intro.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/rp_widget.h" 11 | #include "ui/text/text_utilities.h" 12 | #include "styles/style_keygen.h" 13 | 14 | namespace Keygen::Steps { 15 | 16 | Intro::Intro() : Step(Type::Intro) { 17 | setTitle(tr::lng_intro_title(Ui::Text::RichLangValue)); 18 | setDescription(tr::lng_intro_description(Ui::Text::RichLangValue)); 19 | initControls(); 20 | } 21 | 22 | void Intro::initControls() { 23 | inner()->sizeValue( 24 | ) | rpl::start_with_next([=](QSize size) { 25 | auto state = NextButtonState(); 26 | state.text = tr::lng_intro_next(tr::now); 27 | state.width = st::introNextWidth; 28 | requestNextButton(state); 29 | }, inner()->lifetime()); 30 | } 31 | 32 | } // namespace Keygen::Steps 33 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/intro.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | 11 | namespace Keygen::Steps { 12 | 13 | class Intro final : public Step { 14 | public: 15 | Intro(); 16 | 17 | private: 18 | void initControls(); 19 | 20 | }; 21 | 22 | } // namespace Keygen::Steps 23 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/manager.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/manager.h" 8 | 9 | #include "keygen/steps/intro.h" 10 | #include "keygen/steps/random_seed.h" 11 | #include "keygen/steps/created.h" 12 | #include "keygen/steps/view.h" 13 | #include "keygen/steps/check.h" 14 | #include "keygen/steps/done.h" 15 | #include "keygen/phrases.h" 16 | #include "ui/wrap/fade_wrap.h" 17 | #include "ui/widgets/buttons.h" 18 | #include "ui/text/text_utilities.h" 19 | #include "ui/toast/toast.h" 20 | #include "ui/rp_widget.h" 21 | #include "ui/message_box.h" 22 | #include "base/platform/base_platform_file_utilities.h" 23 | #include "base/call_delayed.h" 24 | #include "styles/style_keygen.h" 25 | 26 | namespace Keygen::Steps { 27 | namespace { 28 | 29 | constexpr auto kSeedLengthMin = 50; 30 | constexpr auto kSeedLengthMax = 200; 31 | constexpr auto kSaveKeyDoneDuration = crl::time(500); 32 | 33 | } // namespace 34 | 35 | Manager::Manager(Fn(QString)> wordsByPrefix) 36 | : _content(std::make_unique()) 37 | , _nextButton( 38 | std::in_place, 39 | _content.get(), 40 | object_ptr( 41 | _content.get(), 42 | rpl::single(QString()), 43 | st::nextButton)) 44 | , _verifyLink( 45 | std::in_place, 46 | _content.get(), 47 | object_ptr( 48 | _content.get(), 49 | tr::lng_intro_verify(tr::now), 50 | st::verifyLink)) 51 | , _backButton( 52 | std::in_place, 53 | _content.get(), 54 | object_ptr(_content.get(), st::topBackButton)) 55 | , _layerManager(_content.get()) 56 | , _wordsByPrefix(std::move(wordsByPrefix)) { 57 | initButtons(); 58 | } 59 | 60 | void Manager::initButtons() { 61 | _nextButton->entity()->setClickedCallback([=] { next(); }); 62 | _nextButton->setDuration(st::coverDuration); 63 | _nextButton->toggledValue( 64 | ) | rpl::start_with_next([=](bool toggled) { 65 | _nextButtonShown.start( 66 | [=] { moveNextButton(); }, 67 | toggled ? 0. : 1., 68 | toggled ? 1. : 0., 69 | st::coverDuration); 70 | }, _nextButton->lifetime()); 71 | _nextButtonShown.stop(); 72 | 73 | _verifyLink->entity()->setClickedCallback([=] { 74 | verify(); 75 | }); 76 | _verifyLink->setDuration(st::coverDuration); 77 | 78 | _backButton->entity()->setClickedCallback([=] { back(); }); 79 | _backButton->toggle(false, anim::type::instant); 80 | _backButton->setDuration(st::coverDuration); 81 | _backButton->move(0, 0); 82 | } 83 | 84 | Manager::~Manager() = default; 85 | 86 | not_null Manager::content() const { 87 | return _content.get(); 88 | } 89 | 90 | void Manager::next() { 91 | if (_next) { 92 | _next(); 93 | } 94 | } 95 | 96 | void Manager::back() { 97 | if (_back) { 98 | _back(); 99 | } 100 | } 101 | 102 | void Manager::backByEscape() { 103 | if (_step->allowEscapeBack()) { 104 | back(); 105 | } 106 | } 107 | 108 | void Manager::verify() { 109 | _layerManager.showBox(Box([=](not_null box) { 110 | Ui::InitMessageBox( 111 | box, 112 | tr::lng_intro_verify_title(), 113 | tr::lng_intro_verify_text(Ui::Text::RichLangValue)); 114 | box->addButton( 115 | tr::lng_intro_verify_ok(), 116 | [=] { showVerify(); }); 117 | box->addButton( 118 | tr::lng_intro_verify_cancel(), 119 | [=] { box->closeBox(); }); 120 | })); 121 | } 122 | 123 | void Manager::showIntro() { 124 | _verifyLink->show(anim::type::normal); 125 | showStep(std::make_unique(), Direction::Forward, [=] { 126 | _verifyLink->hide(anim::type::normal); 127 | showRandomSeed(); 128 | }); 129 | } 130 | 131 | void Manager::showVerify() { 132 | auto check = std::make_unique( 133 | _wordsByPrefix, 134 | Check::Layout::Verifying); 135 | 136 | const auto raw = check.get(); 137 | 138 | raw->submitRequests( 139 | ) | rpl::start_with_next([=] { 140 | next(); 141 | }, raw->lifetime()); 142 | 143 | _verifyLink->hide(anim::type::normal); 144 | showStep(std::move(check), Direction::Forward, [=] { 145 | if (raw->checkAll()) { 146 | _verifyRequests.fire(raw->words()); 147 | } 148 | }, [=] { 149 | _actionRequests.fire(Action::NewKey); 150 | }); 151 | } 152 | 153 | void Manager::showRandomSeed() { 154 | using namespace rpl::mappers; 155 | 156 | auto seed = std::make_unique(); 157 | 158 | const auto raw = seed.get(); 159 | raw->length( 160 | ) | rpl::filter( 161 | _1 >= kSeedLengthMin 162 | ) | rpl::take( 163 | 1 164 | ) | rpl::start_with_next([=] { 165 | raw->showLimit(kSeedLengthMax); 166 | }, raw->lifetime()); 167 | 168 | showStep(std::move(seed), Direction::Forward, [=] { 169 | const auto text = raw->accumulated(); 170 | if (text.size() >= kSeedLengthMin) { 171 | _generateRequests.fire(text.toUtf8()); 172 | } 173 | }, [=] { 174 | _actionRequests.fire(Action::NewKey); 175 | }); 176 | } 177 | 178 | void Manager::showCreated(std::vector &&words) { 179 | auto next = [=, list = std::move(words)]() mutable { 180 | showWords(std::move(list), Direction::Forward); 181 | }; 182 | showStep( 183 | std::make_unique(), 184 | Direction::Forward, 185 | std::move(next)); 186 | } 187 | 188 | void Manager::showWords(std::vector &&words, Direction direction) { 189 | showStep(std::make_unique(std::move(words)), direction, [=] { 190 | showCheck(Direction::Forward); 191 | }); 192 | } 193 | 194 | void Manager::showCheck(Direction direction) { 195 | auto check = std::make_unique( 196 | _wordsByPrefix, 197 | Check::Layout::Checking); 198 | 199 | const auto raw = check.get(); 200 | 201 | raw->submitRequests( 202 | ) | rpl::start_with_next([=] { 203 | next(); 204 | }, raw->lifetime()); 205 | 206 | showStep(std::move(check), direction, [=] { 207 | if (raw->checkAll()) { 208 | _checkRequests.fire(raw->words()); 209 | } 210 | }, [=] { 211 | _actionRequests.fire(Action::ShowWordsBack); 212 | }); 213 | } 214 | 215 | void Manager::showCheckDone(const QString &publicKey) { 216 | _layerManager.showBox(Box([=](not_null box) { 217 | Ui::InitMessageBox( 218 | box, 219 | tr::lng_check_good_title(), 220 | tr::lng_check_good_text(Ui::Text::RichLangValue)); 221 | box->addButton( 222 | tr::lng_check_good_next(), 223 | [=] { showDone(publicKey); }); 224 | })); 225 | } 226 | 227 | void Manager::showCheckFail() { 228 | _layerManager.showBox(Box([=](not_null box) { 229 | Ui::InitMessageBox( 230 | box, 231 | tr::lng_check_bad_title(), 232 | tr::lng_check_bad_text(Ui::Text::RichLangValue)); 233 | box->addButton( 234 | tr::lng_check_bad_try_again(), 235 | [=] { box->closeBox(); }); 236 | box->addButton(tr::lng_check_bad_view_words(), [=] { back(); }); 237 | 238 | const auto weak = Ui::MakeWeak(_step->widget()); 239 | box->boxClosing( 240 | ) | rpl::filter([=] { 241 | return weak != nullptr; 242 | }) | rpl::start_with_next([=] { 243 | _step->setFocus(); 244 | }, box->lifetime()); 245 | })); 246 | } 247 | 248 | void Manager::showVerifyDone(const QString &publicKey) { 249 | showDone(publicKey); 250 | } 251 | 252 | void Manager::showVerifyFail() { 253 | _layerManager.showBox(Box([=](not_null box) { 254 | Ui::InitMessageBox( 255 | box, 256 | tr::lng_verify_bad_title(), 257 | tr::lng_verify_bad_text(Ui::Text::RichLangValue)); 258 | box->addButton( 259 | tr::lng_verify_bad_try_again(), 260 | [=] { box->closeBox(); }); 261 | 262 | const auto weak = Ui::MakeWeak(_step->widget()); 263 | box->boxClosing( 264 | ) | rpl::filter([=] { 265 | return weak != nullptr; 266 | }) | rpl::start_with_next([=] { 267 | _step->setFocus(); 268 | }, box->lifetime()); 269 | })); 270 | 271 | } 272 | 273 | void Manager::showDone(const QString &publicKey) { 274 | auto done = std::make_unique(publicKey); 275 | done->copyKeyRequests( 276 | ) | rpl::map([] { 277 | return Action::CopyKey; 278 | }) | rpl::start_to_stream(_actionRequests, done->lifetime()); 279 | done->saveKeyRequests( 280 | ) | rpl::map([] { 281 | return Action::SaveKey; 282 | }) | rpl::start_to_stream(_actionRequests, done->lifetime()); 283 | done->newKeyRequests( 284 | ) | rpl::start_with_next([=] { 285 | confirmNewKey(); 286 | }, done->lifetime()); 287 | done->verifyKeyRequests( 288 | ) | rpl::start_with_next([=] { 289 | showCheck(Direction::Backward); 290 | }, done->lifetime()); 291 | showStep(std::move(done), Direction::Forward); 292 | } 293 | 294 | void Manager::showCopyKeyDone() { 295 | Ui::Toast::Show(_content.get(), tr::lng_done_to_clipboard(tr::now)); 296 | } 297 | 298 | void Manager::showSaveKeyDone(const QString &path) { 299 | auto config = Ui::Toast::Config(); 300 | config.text = tr::lng_done_to_file(tr::now); 301 | config.durationMs = kSaveKeyDoneDuration; 302 | Ui::Toast::Show(_content.get(), config); 303 | const auto delay = st::toastFadeInDuration 304 | + kSaveKeyDoneDuration 305 | + st::toastFadeOutDuration; 306 | base::call_delayed(delay, _content.get(), [=] { 307 | base::Platform::ShowInFolder(path); 308 | }); 309 | } 310 | 311 | void Manager::showSaveKeyFail() { 312 | showError("Could not write this file :("); 313 | } 314 | 315 | void Manager::showError(const QString &text) { 316 | _layerManager.showBox(Box([=](not_null box) { 317 | Ui::InitMessageBox( 318 | box, 319 | rpl::single(QString("Error")), 320 | rpl::single(Ui::Text::WithEntities(text))); 321 | box->addButton( 322 | rpl::single(QString("OK")), 323 | [=] { box->closeBox(); }); 324 | })); 325 | } 326 | 327 | void Manager::showStep( 328 | std::unique_ptr step, 329 | Direction direction, 330 | FnMut next, 331 | FnMut back) { 332 | _layerManager.hideAll(); 333 | 334 | std::swap(_step, step); 335 | _next = std::move(next); 336 | _back = std::move(back); 337 | 338 | const auto inner = _step->widget(); 339 | inner->setParent(_content.get()); 340 | _content->sizeValue( 341 | ) | rpl::start_with_next([=](QSize size) { 342 | inner->setGeometry({ QPoint(), size }); 343 | }, inner->lifetime()); 344 | inner->show(); 345 | 346 | _nextButton->entity()->setText(_step->nextButtonState( 347 | ) | rpl::filter([](const NextButtonState &state) { 348 | return !state.text.isEmpty(); 349 | }) | rpl::map([](const NextButtonState &state) { 350 | return state.text; 351 | })); 352 | _step->nextButtonState( 353 | ) | rpl::start_with_next([=](const NextButtonState &state) { 354 | _nextButton->toggle(!state.text.isEmpty(), anim::type::normal); 355 | }, _step->lifetime()); 356 | if (!step) { 357 | _nextButton->finishAnimating(); 358 | _verifyLink->finishAnimating(); 359 | _nextButtonShown.stop(); 360 | } 361 | _backButton->toggle(_back != nullptr, anim::type::normal); 362 | _nextButton->raise(); 363 | _verifyLink->raise(); 364 | _backButton->raise(); 365 | _layerManager.raise(); 366 | 367 | rpl::combine( 368 | _step->nextButtonState(), 369 | _content->widthValue() 370 | ) | rpl::start_with_next([=](NextButtonState state, int width) { 371 | if (state.text.isEmpty()) { 372 | _lastNextState.text = QString(); 373 | } else { 374 | _nextButton->resizeToWidth(state.width 375 | ? state.width 376 | : st::nextButton.width); 377 | _lastNextState = state; 378 | } 379 | moveNextButton(); 380 | }, _step->lifetime()); 381 | 382 | _step->nextClicks( 383 | ) | rpl::start_with_next([=] { 384 | this->next(); 385 | }, _step->lifetime()); 386 | 387 | _step->coverShown( 388 | ) | rpl::start_with_next([=](float64 shown) { 389 | _backButton->move(0, st::coverHeight * shown); 390 | }, _step->lifetime()); 391 | 392 | if (step) { 393 | _step->showAnimated(step.get(), direction); 394 | } else { 395 | _step->setFocus(); 396 | } 397 | } 398 | 399 | void Manager::moveNextButton() { 400 | const auto shown = _nextButton->toggled(); 401 | const auto progress = _nextButtonShown.value(shown ? 1. : 0.); 402 | const auto shownTop = _lastNextState.top; 403 | const auto hiddenTop = shownTop + 2 * st::nextButton.height; 404 | _nextButton->move( 405 | (_content->width() - _nextButton->width()) / 2, 406 | anim::interpolate(hiddenTop, shownTop, progress)); 407 | _verifyLink->move( 408 | (_content->width() - _verifyLink->width()) / 2, 409 | _nextButton->y() + _nextButton->height() + st::verifyLinkTop); 410 | } 411 | 412 | void Manager::confirmNewKey() { 413 | _layerManager.showBox(Box([=](not_null box) { 414 | Ui::InitMessageBox( 415 | box, 416 | tr::lng_done_new_title(), 417 | tr::lng_done_new_text(Ui::Text::RichLangValue)); 418 | box->addButton( 419 | tr::lng_done_new_ok(), 420 | [=] { _actionRequests.fire(Action::NewKey); }); 421 | box->addButton(tr::lng_done_new_cancel(), [=] { box->closeBox(); }); 422 | })); 423 | } 424 | 425 | rpl::producer Manager::generateRequests() const { 426 | return _generateRequests.events(); 427 | } 428 | 429 | rpl::producer> Manager::checkRequests() const { 430 | return _checkRequests.events(); 431 | } 432 | 433 | rpl::producer> Manager::verifyRequests() const { 434 | return _verifyRequests.events(); 435 | } 436 | 437 | rpl::producer Manager::actionRequests() const { 438 | return _actionRequests.events(); 439 | } 440 | 441 | } // namespace Keygen::Steps 442 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/manager.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | #include "ui/effects/animations.h" 11 | #include "ui/layers/layer_manager.h" 12 | #include "base/unique_qptr.h" 13 | 14 | namespace Ui { 15 | class RpWidget; 16 | class RoundButton; 17 | class LinkButton; 18 | class IconButton; 19 | template 20 | class FadeWrap; 21 | } // namespace Ui 22 | 23 | namespace Keygen::Steps { 24 | 25 | class Manager final { 26 | public: 27 | explicit Manager(Fn(QString)> wordsByPrefix); 28 | Manager(const Manager &other) = delete; 29 | Manager &operator=(const Manager &other) = delete; 30 | ~Manager(); 31 | 32 | [[nodiscard]] not_null content() const; 33 | 34 | [[nodiscard]] rpl::producer generateRequests() const; 35 | [[nodiscard]] rpl::producer> checkRequests() const; 36 | [[nodiscard]] rpl::producer> verifyRequests() const; 37 | 38 | enum class Action { 39 | ShowWordsBack, 40 | CopyKey, 41 | SaveKey, 42 | NewKey, 43 | }; 44 | 45 | [[nodiscard]] rpl::producer actionRequests() const; 46 | 47 | void next(); 48 | void back(); 49 | void backByEscape(); 50 | void verify(); 51 | 52 | void showIntro(); 53 | void showVerify(); 54 | void showRandomSeed(); 55 | void showCreated(std::vector &&words); 56 | void showWords(std::vector &&words, Direction direction); 57 | void showCheck(Direction direction); 58 | void showCheckDone(const QString &publicKey); 59 | void showCheckFail(); 60 | void showVerifyDone(const QString &publicKey); 61 | void showVerifyFail(); 62 | void showDone(const QString &publicKey); 63 | void showCopyKeyDone(); 64 | void showSaveKeyDone(const QString &path); 65 | void showSaveKeyFail(); 66 | void showError(const QString &text); 67 | 68 | private: 69 | void showStep( 70 | std::unique_ptr step, 71 | Direction direction, 72 | FnMut next = nullptr, 73 | FnMut back = nullptr); 74 | void confirmNewKey(); 75 | void initButtons(); 76 | void moveNextButton(); 77 | 78 | const std::unique_ptr _content; 79 | const base::unique_qptr> _nextButton; 80 | const base::unique_qptr> _verifyLink; 81 | const base::unique_qptr> _backButton; 82 | Ui::Animations::Simple _nextButtonShown; 83 | NextButtonState _lastNextState; 84 | Ui::LayerManager _layerManager; 85 | 86 | const Fn(QString)> _wordsByPrefix; 87 | 88 | std::unique_ptr _step; 89 | 90 | FnMut _next; 91 | FnMut _back; 92 | 93 | rpl::event_stream _generateRequests; 94 | rpl::event_stream> _checkRequests; 95 | rpl::event_stream> _verifyRequests; 96 | rpl::event_stream _actionRequests; 97 | 98 | }; 99 | 100 | } // namespace Keygen::Steps 101 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/random_seed.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/random_seed.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/rp_widget.h" 11 | #include "ui/widgets/labels.h" 12 | #include "ui/text/text_utilities.h" 13 | #include "ui/wrap/fade_wrap.h" 14 | #include "ui/lottie_widget.h" 15 | #include "styles/style_keygen.h" 16 | 17 | #include 18 | 19 | namespace Keygen::Steps { 20 | 21 | RandomSeed::RandomSeed() 22 | : Step(Type::Default) { 23 | using namespace rpl::mappers; 24 | 25 | setTitle(tr::lng_random_seed_title(Ui::Text::RichLangValue)); 26 | setDescription(rpl::conditional( 27 | _limit.value() | rpl::map(!_1), 28 | tr::lng_random_seed_description(Ui::Text::RichLangValue), 29 | tr::lng_random_seed_continue(Ui::Text::RichLangValue))); 30 | initControls(); 31 | } 32 | 33 | rpl::producer RandomSeed::length() const { 34 | return _length.value(); 35 | } 36 | 37 | QString RandomSeed::accumulated() const { 38 | return _accumulated; 39 | } 40 | 41 | void RandomSeed::initControls() { 42 | using namespace rpl::mappers; 43 | 44 | showLottie( 45 | ":/gui/art/lottie/keyboard.tgs", 46 | st::randomLottieTop, 47 | st::randomLottieHeight); 48 | startLottie(); 49 | 50 | auto countText = _length.value() | rpl::map([](int value) { 51 | return QString::number(value); 52 | }); 53 | const auto counter = Ui::CreateChild>( 54 | inner().get(), 55 | object_ptr( 56 | inner().get(), 57 | std::move(countText), 58 | st::randomCounter))->setDuration( 59 | st::coverDuration 60 | )->show(anim::type::instant); 61 | const auto counterLabel = Ui::CreateChild>( 62 | inner().get(), 63 | object_ptr( 64 | inner().get(), 65 | tr::lng_random_seed_amount(), 66 | st::randomCounterLabel))->setDuration( 67 | st::coverDuration 68 | )->show(anim::type::instant); 69 | auto totalText = rpl::combine( 70 | tr::lng_random_seed_ready_total(), 71 | _length.value(), 72 | _limit.value() 73 | ) | rpl::map([](QString phrase, int ready, int total) { 74 | return phrase.replace( 75 | "{ready}", 76 | QString::number(ready) 77 | ).replace( 78 | "{total}", 79 | QString::number(total) 80 | ); 81 | }); 82 | const auto totalLabel = Ui::CreateChild>( 83 | inner().get(), 84 | object_ptr( 85 | inner().get(), 86 | std::move(totalText), 87 | st::randomCounterLabel))->setDuration( 88 | st::coverDuration 89 | )->hide(anim::type::instant); 90 | 91 | inner()->sizeValue( 92 | ) | rpl::start_with_next([=](QSize size) { 93 | counter->resizeToWidth(size.width()); 94 | counter->move(0, contentTop() + st::randomCounterTop); 95 | counterLabel->resizeToWidth(size.width()); 96 | counterLabel->move(0, contentTop() + st::randomCounterLabelTop); 97 | totalLabel->resizeToWidth(size.width()); 98 | totalLabel->move( 99 | 0, 100 | contentTop() + st::randomReadyTotalLabelTop); 101 | }, counter->lifetime()); 102 | 103 | rpl::combine( 104 | _limit.value() | rpl::filter(_1 > 0), 105 | inner()->heightValue(), 106 | _2 107 | ) | rpl::start_with_next([=](int height) { 108 | counter->hide(anim::type::normal); 109 | counterLabel->hide(anim::type::normal); 110 | totalLabel->show(anim::type::normal); 111 | auto state = NextButtonState(); 112 | state.text = tr::lng_random_seed_next(tr::now); 113 | requestNextButton(state); 114 | }, inner()->lifetime()); 115 | 116 | inner()->events( 117 | ) | rpl::filter([](not_null e) { 118 | return e->type() == QEvent::KeyPress; 119 | }) | rpl::map([](not_null e) { 120 | return static_cast(e.get()); 121 | }) | rpl::filter([](not_null e) { 122 | return !e->text().isEmpty() && e->text().begin()->isPrint(); 123 | }) | rpl::start_with_next([=](not_null e) { 124 | append(e->text()); 125 | }, inner()->lifetime()); 126 | } 127 | 128 | void RandomSeed::append(const QString &text) { 129 | _accumulated += text; 130 | const auto limit = _limit.current(); 131 | if (limit && _accumulated.size() > limit) { 132 | _accumulated = _accumulated.mid(_accumulated.size() - limit); 133 | } 134 | _length = _accumulated.size(); 135 | } 136 | 137 | void RandomSeed::showLimit(int limit) { 138 | Expects(limit > 0); 139 | 140 | _limit = limit; 141 | } 142 | 143 | } // namespace Keygen::Steps 144 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/random_seed.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | 11 | namespace Ui { 12 | class FlatLabel; 13 | } // namespace Ui 14 | 15 | namespace Keygen::Steps { 16 | 17 | class RandomSeed final : public Step { 18 | public: 19 | RandomSeed(); 20 | 21 | void showLimit(int limit); 22 | 23 | [[nodiscard]] rpl::producer length() const; 24 | [[nodiscard]] QString accumulated() const; 25 | 26 | private: 27 | void initControls(); 28 | void append(const QString &text); 29 | 30 | QString _accumulated; 31 | rpl::variable _limit = 0; 32 | rpl::variable _length = 0; 33 | 34 | }; 35 | 36 | } // namespace Keygen::Steps 37 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/step.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/step.h" 8 | 9 | #include "ui/rp_widget.h" 10 | #include "ui/widgets/scroll_area.h" 11 | #include "ui/widgets/labels.h" 12 | #include "ui/widgets/buttons.h" 13 | #include "ui/effects/slide_animation.h" 14 | #include "ui/wrap/fade_wrap.h" 15 | #include "ui/text/text_utilities.h" 16 | #include "ui/lottie_widget.h" 17 | #include "styles/style_keygen.h" 18 | #include "styles/palette.h" 19 | 20 | namespace Keygen::Steps { 21 | namespace { 22 | 23 | QImage AddImageMargins(const QImage &source, QMargins margins) { 24 | const auto pixelRatio = style::DevicePixelRatio(); 25 | const auto was = source.size() / pixelRatio; 26 | const auto size = QRect({}, was).marginsAdded(margins).size(); 27 | auto large = QImage( 28 | size * pixelRatio, 29 | QImage::Format_ARGB32_Premultiplied); 30 | large.setDevicePixelRatio(pixelRatio); 31 | large.fill(Qt::transparent); 32 | { 33 | auto p = QPainter(&large); 34 | p.drawImage( 35 | QRect({ margins.left(), margins.top() }, was), 36 | source); 37 | } 38 | return large; 39 | } 40 | 41 | } // namespace 42 | 43 | struct Step::CoverAnimationData { 44 | Type type = Type(); 45 | std::unique_ptr lottie; 46 | int lottieTop = 0; 47 | int lottieHeight = 0; 48 | Ui::CrossFadeAnimation::Data title; 49 | Ui::CrossFadeAnimation::Data description; 50 | QPixmap content; 51 | int contentBottom = 0; 52 | }; 53 | 54 | struct Step::SlideAnimationData { 55 | Type type = Type(); 56 | std::unique_ptr lottie; 57 | int lottieTop = 0; 58 | int lottieHeight = 0; 59 | QImage content; 60 | int contentTop = 0; 61 | }; 62 | 63 | Step::CoverAnimation::~CoverAnimation() = default; 64 | Step::SlideAnimation::~SlideAnimation() = default; 65 | 66 | Step::Step(Type type) 67 | : _type(type) 68 | , _widget(std::make_unique()) 69 | , _scroll(resolveScrollArea()) 70 | , _inner(resolveInner()) 71 | , _coverShown(type == Type::Intro ? 1. : 0.) 72 | , _nextButton(resolveNextButton()) { 73 | initGeometry(); 74 | initNextButton(); 75 | initCover(); 76 | } 77 | 78 | Step::~Step() = default; 79 | 80 | Ui::ScrollArea *Step::resolveScrollArea() { 81 | return (_type == Type::Scroll) 82 | ? Ui::CreateChild(_widget.get(), st::scrollArea) 83 | : nullptr; 84 | } 85 | 86 | not_null Step::resolveInner() { 87 | return _scroll 88 | ? _scroll->setOwnedWidget(object_ptr(_scroll)).data() 89 | : Ui::CreateChild(_widget.get()); 90 | } 91 | 92 | std::unique_ptr> Step::resolveNextButton() { 93 | return _scroll 94 | ? std::make_unique>( 95 | _inner, 96 | object_ptr( 97 | _inner.get(), 98 | rpl::single(QString()), 99 | st::nextButton)) 100 | : nullptr; 101 | } 102 | 103 | void Step::initGeometry() { 104 | _widget->sizeValue( 105 | ) | rpl::start_with_next([=](QSize size) { 106 | if (_scroll) { 107 | _scroll->setGeometry({ QPoint(), size }); 108 | } 109 | _inner->setGeometry( 110 | 0, 111 | 0, 112 | size.width(), 113 | std::max(desiredHeight(), size.height())); 114 | }, _inner->lifetime()); 115 | } 116 | 117 | void Step::initNextButton() { 118 | if (!_nextButton) { 119 | return; 120 | } 121 | _nextButton->entity()->setText(_nextButtonState.value( 122 | ) | rpl::filter([](const NextButtonState &state) { 123 | return !state.text.isEmpty(); 124 | }) | rpl::map([](const NextButtonState &state) { 125 | return state.text; 126 | })); 127 | _nextButton->toggleOn(_nextButtonState.value( 128 | ) | rpl::map([](const NextButtonState &state) { 129 | return !state.text.isEmpty(); 130 | }))->setDuration(0); 131 | 132 | rpl::combine( 133 | _nextButtonState.value(), 134 | inner()->widthValue() 135 | ) | rpl::start_with_next([=](NextButtonState state, int width) { 136 | _nextButton->move( 137 | (width - _nextButton->width()) / 2, 138 | state.top); 139 | _lastNextState = state; 140 | }, inner()->lifetime()); 141 | } 142 | 143 | void Step::initCover() { 144 | if (_type == Type::Intro) { 145 | prepareCoverMask(); 146 | 147 | inner()->paintRequest( 148 | ) | rpl::start_with_next([=](QRect clip) { 149 | auto p = QPainter(inner()); 150 | paintCover(p, 0, clip); 151 | }, inner()->lifetime()); 152 | } 153 | 154 | _widget->paintRequest( 155 | ) | rpl::start_with_next([=](QRect clip) { 156 | paintContent(clip); 157 | }, _widget->lifetime()); 158 | } 159 | 160 | void Step::paintContent(QRect clip) { 161 | if (_slideAnimation.slide) { 162 | if (!_slideAnimation.slide->animating()) { 163 | showFinished(); 164 | return; 165 | } 166 | } else if (!_coverAnimationValue.animating()) { 167 | if (_coverAnimation.title) { 168 | showFinished(); 169 | } 170 | return; 171 | } 172 | 173 | auto p = QPainter(_widget.get()); 174 | if (_slideAnimation.slide) { 175 | paintSlideAnimation(p, clip); 176 | } else { 177 | paintCoverAnimation(p, clip); 178 | } 179 | } 180 | 181 | void Step::paintCoverAnimation(QPainter &p, QRect clip) { 182 | const auto dt = _coverAnimationValue.value(1.); 183 | const auto isIntro = (_type == Type::Intro); 184 | const auto progress = isIntro 185 | ? anim::easeOutCirc(1., dt) 186 | : anim::linear(1., dt); 187 | const auto arrivingAlpha = progress; 188 | const auto departingAlpha = 1. - progress; 189 | const auto showCoverMethod = progress; 190 | const auto hideCoverMethod = progress; 191 | const auto coverTop = isIntro 192 | ? anim::interpolate(-st::coverHeight, 0, showCoverMethod) 193 | : anim::interpolate(0, -st::coverHeight, hideCoverMethod); 194 | 195 | paintCover(p, coverTop, clip); 196 | 197 | const auto positionReady = isIntro ? showCoverMethod : hideCoverMethod; 198 | _coverAnimation.title->paintFrame( 199 | p, 200 | positionReady, 201 | departingAlpha, 202 | arrivingAlpha); 203 | _coverAnimation.description->paintFrame( 204 | p, 205 | positionReady, 206 | departingAlpha, 207 | arrivingAlpha); 208 | 209 | paintCoverAnimationContent( 210 | p, 211 | _coverAnimation.contentWas, 212 | _coverAnimation.contentWasBottom, 213 | departingAlpha, 214 | showCoverMethod); 215 | paintCoverAnimationContent( 216 | p, 217 | _coverAnimation.contentNow, 218 | _coverAnimation.contentNowBottom, 219 | arrivingAlpha, 220 | 1. - hideCoverMethod); 221 | } 222 | 223 | void Step::paintSlideAnimation(QPainter &p, QRect clip) { 224 | const auto left = (_widget->width() - _slideAnimation.slideWidth) / 2; 225 | const auto top = _slideAnimation.slideTop; 226 | _slideAnimation.slide->paintFrame(p, left, top, _widget->width()); 227 | } 228 | 229 | void Step::showFinished() { 230 | _coverAnimationValue.stop(); 231 | if (_type != Type::Intro 232 | && (_coverAnimation.lottie || _slideAnimation.lottieNow)) { 233 | _lottie = _coverAnimation.lottie 234 | ? std::move(_coverAnimation.lottie) 235 | : std::move(_slideAnimation.lottieNow); 236 | _lottie->attach(inner()); 237 | _lottie->setOpacity(1.); 238 | _lottie->setGeometry(lottieGeometry( 239 | contentTop() + _lottieTop, 240 | _lottieHeight)); 241 | } 242 | _coverAnimation = CoverAnimation(); 243 | _slideAnimation = SlideAnimation(); 244 | if (_scroll) { 245 | _scroll->show(); 246 | } 247 | inner()->show(); 248 | showFinishedHook(); 249 | setFocus(); 250 | } 251 | 252 | void Step::paintCover(QPainter &p, int top, QRect clip) { 253 | const auto coverWidth = inner()->width(); 254 | const auto coverHeight = top + st::coverHeight; 255 | if (coverHeight <= 0 256 | || !clip.intersects({ 0, 0, coverWidth, coverHeight })) { 257 | return; 258 | } 259 | if (coverHeight > 0) { 260 | p.drawPixmap( 261 | QRect(0, 0, coverWidth, coverHeight), 262 | _coverMask, 263 | QRect( 264 | 0, 265 | -top * style::DevicePixelRatio(), 266 | _coverMask.width(), 267 | coverHeight * style::DevicePixelRatio())); 268 | } 269 | 270 | auto left = 0; 271 | auto right = 0; 272 | if (coverWidth < st::coverMaxWidth) { 273 | const auto iconsMaxSkip = st::coverMaxWidth 274 | - st::coverLeft.width() 275 | - st::coverRight.width(); 276 | const auto iconsSkip = st::coverIconsMinSkip 277 | + (((iconsMaxSkip - st::coverIconsMinSkip) 278 | * (coverWidth - st::windowSizeMin.width())) 279 | / (st::coverMaxWidth - st::windowSizeMin.width())); 280 | const auto outside = iconsSkip 281 | + st::coverLeft.width() 282 | + st::coverRight.width() 283 | - coverWidth; 284 | left = -outside / 2; 285 | right = -outside - left; 286 | } 287 | if (top < 0) { 288 | const auto shown = float64(coverHeight) / st::coverHeight; 289 | auto leftShown = qRound(shown * (left + st::coverLeft.width())); 290 | left = leftShown - st::coverLeft.width(); 291 | auto rightShown = qRound(shown * (right + st::coverRight.width())); 292 | right = rightShown - st::coverRight.width(); 293 | } 294 | st::coverLeft.paint( 295 | p, 296 | left, 297 | coverHeight - st::coverLeft.height(), 298 | coverWidth); 299 | st::coverRight.paint( 300 | p, 301 | coverWidth - right - st::coverRight.width(), 302 | coverHeight - st::coverRight.height(), 303 | coverWidth); 304 | 305 | const auto iconLeft = (coverWidth - st::coverIcon.width()) / 2; 306 | const auto iconTop = top + st::coverIconTop; 307 | st::coverIcon.paint(p, iconLeft, iconTop, coverWidth); 308 | } 309 | 310 | void Step::paintCoverAnimationContent( 311 | QPainter &p, 312 | const QPixmap &snapshot, 313 | int snapshotBottom, 314 | float64 alpha, 315 | float64 howMuchHidden) { 316 | const auto pixelRatio = style::DevicePixelRatio(); 317 | const auto snapshotWidth = snapshot.width() / pixelRatio; 318 | if (!snapshotWidth) { 319 | return; 320 | } 321 | const auto contentTop = anim::interpolate( 322 | snapshotBottom - (snapshot.height() / pixelRatio), 323 | snapshotBottom, 324 | howMuchHidden); 325 | p.setOpacity(alpha); 326 | p.drawPixmap( 327 | QPoint((inner()->width() - snapshotWidth) / 2, contentTop), 328 | snapshot); 329 | } 330 | 331 | rpl::producer<> Step::nextClicks() const { 332 | if (!_nextButton) { 333 | return rpl::never<>(); 334 | } 335 | return _nextButton->entity()->clicks( 336 | ) | rpl::map([] { 337 | return rpl::empty_value(); 338 | }); 339 | } 340 | 341 | rpl::producer Step::coverShown() const { 342 | return _coverShown.value(); 343 | } 344 | 345 | not_null Step::widget() const { 346 | return _widget.get(); 347 | } 348 | 349 | int Step::desiredHeight() const { 350 | return st::stepHeight; 351 | } 352 | 353 | bool Step::allowEscapeBack() const { 354 | return true; 355 | } 356 | 357 | Step::CoverAnimationData Step::prepareCoverAnimationData() { 358 | Expects(_title != nullptr); 359 | Expects(_description != nullptr); 360 | 361 | auto result = CoverAnimationData(); 362 | result.type = _type; 363 | if (_lottie) { 364 | _lottie->detach(); 365 | result.lottie = std::move(_lottie); 366 | result.lottieTop = contentTop() + _lottieTop; 367 | result.lottieHeight = _lottieHeight; 368 | } 369 | result.title = _title->crossFadeData(st::windowBg); 370 | result.description = _description->crossFadeData(st::windowBg); 371 | result.content = prepareCoverAnimationContent(); 372 | result.contentBottom = animationContentBottom(); 373 | return result; 374 | } 375 | 376 | QPixmap Step::prepareCoverAnimationContent() const { 377 | Expects(_description != nullptr); 378 | 379 | const auto otherTop = coverAnimationContentTop(); 380 | const auto otherWidth = _description->naturalWidth(); 381 | const auto otherRect = QRect( 382 | (inner()->width() - otherWidth) / 2, 383 | otherTop, 384 | otherWidth, 385 | animationContentBottom() - otherTop); 386 | 387 | return Ui::PixmapFromImage(grabForAnimation(otherRect)); 388 | } 389 | 390 | Step::SlideAnimationData Step::prepareSlideAnimationData() { 391 | Expects(_title != nullptr); 392 | 393 | auto result = SlideAnimationData(); 394 | result.type = _type; 395 | if (_lottie) { 396 | _lottie->detach(); 397 | result.lottie = std::move(_lottie); 398 | result.lottieTop = contentTop() + _lottieTop; 399 | result.lottieHeight = _lottieHeight; 400 | } 401 | result.content = prepareSlideAnimationContent(); 402 | const auto scrollTop = (_scroll ? _scroll->scrollTop() : 0); 403 | result.contentTop = slideAnimationContentTop() - scrollTop; 404 | return result; 405 | } 406 | 407 | QImage Step::prepareSlideAnimationContent() const { 408 | Expects(_title != nullptr); 409 | 410 | const auto contentTop = slideAnimationContentTop(); 411 | const auto contentWidth = _description->naturalWidth(); 412 | const auto contentRect = QRect( 413 | (inner()->width() - contentWidth) / 2, 414 | contentTop, 415 | contentWidth, 416 | animationContentBottom() - contentTop); 417 | return grabForAnimation(contentRect); 418 | } 419 | 420 | not_null Step::inner() const { 421 | return _inner; 422 | } 423 | 424 | int Step::contentTop() const { 425 | const auto desired = desiredHeight(); 426 | return (std::max(desired, inner()->height()) - desired) / 2; 427 | } 428 | 429 | int Step::coverAnimationContentTop() const { 430 | Expects(_description != nullptr); 431 | 432 | return std::max( 433 | _description->y() + _description->height(), 434 | _scroll ? _scroll->scrollTop() : 0); 435 | } 436 | 437 | int Step::slideAnimationContentTop() const { 438 | Expects(_title != nullptr); 439 | 440 | return std::max( 441 | _title->y(), 442 | _scroll ? _scroll->scrollTop() : 0); 443 | } 444 | 445 | int Step::animationContentBottom() const { 446 | const auto bottom = contentTop() + desiredHeight(); 447 | return _scroll 448 | ? std::min(bottom, _scroll->scrollTop() + _scroll->height()) 449 | : bottom; 450 | } 451 | 452 | QImage Step::grabForAnimation(QRect rect) const { 453 | return Ui::GrabWidgetToImage(inner(), rect); 454 | } 455 | 456 | void Step::showFinishedHook() { 457 | } 458 | 459 | void Step::setTitle(rpl::producer text, int top) { 460 | _title.emplace( 461 | inner(), 462 | std::move(text), 463 | (_type == Type::Intro) ? st::introTitle : st::stepTitle); 464 | 465 | if (!top) { 466 | top = (_type == Type::Intro) 467 | ? st::introTitleTop 468 | : (_type == Type::Scroll) 469 | ? st::scrollTitleTop 470 | : st::stepTitleTop; 471 | } 472 | inner()->sizeValue( 473 | ) | rpl::start_with_next([=](QSize size) { 474 | _title->resizeToWidth(size.width()); 475 | if (_type == Type::Intro) { 476 | const auto heightMin = st::windowSizeMin.height(); 477 | const auto topMin = st::introTitleTopMin; 478 | 479 | const auto realTop = contentTop() + top; 480 | const auto adjustedTop = std::max(realTop, st::introTitleTopMin); 481 | _title->move(0, adjustedTop); 482 | } else { 483 | _title->move(0, contentTop() + top); 484 | } 485 | }, _title->lifetime()); 486 | } 487 | 488 | void Step::setDescription(rpl::producer text, int top) { 489 | Expects(_title != nullptr); 490 | 491 | _description.emplace( 492 | inner(), 493 | std::move(text), 494 | (_type == Type::Intro) ? st::introDescription : st::stepDescription); 495 | 496 | if (!top) { 497 | top = (_type == Type::Intro) 498 | ? st::introDescriptionTop 499 | : (_type == Type::Scroll) 500 | ? st::scrollDescriptionTop 501 | : st::stepDescriptionTop; 502 | } 503 | _title->geometryValue( 504 | ) | rpl::start_with_next([=](QRect geometry) { 505 | _description->resizeToWidth(geometry.width()); 506 | _description->move(0, geometry.y() + top); 507 | }, _description->lifetime()); 508 | } 509 | 510 | rpl::producer Step::nextButtonState() const { 511 | return (_type == Type::Scroll) 512 | ? rpl::single(NextButtonState()) 513 | : (_nextButtonState.value() | rpl::type_erased()); 514 | } 515 | 516 | void Step::prepareCoverMask() { 517 | if (!_coverMask.isNull()) { 518 | return; 519 | } 520 | 521 | const auto maskWidth = style::DevicePixelRatio(); 522 | const auto maskHeight = st::coverHeight * style::DevicePixelRatio(); 523 | auto mask = QImage(maskWidth, maskHeight, QImage::Format_ARGB32_Premultiplied); 524 | auto maskInts = reinterpret_cast(mask.bits()); 525 | Assert(mask.depth() == (sizeof(uint32) << 3)); 526 | const auto maskIntsPerLineAdded = (mask.bytesPerLine() >> 2) - maskWidth; 527 | Assert(maskIntsPerLineAdded >= 0); 528 | const auto realHeight = static_cast(maskHeight - 1); 529 | for (auto y = 0; y != maskHeight; ++y) { 530 | auto color = anim::color( 531 | st::introCoverTopBg, 532 | st::introCoverBottomBg, 533 | y / realHeight); 534 | auto colorInt = anim::getPremultiplied(color); 535 | for (auto x = 0; x != maskWidth; ++x) { 536 | *maskInts++ = colorInt; 537 | } 538 | maskInts += maskIntsPerLineAdded; 539 | } 540 | _coverMask = Ui::PixmapFromImage(std::move(mask)); 541 | } 542 | 543 | void Step::showAnimated(not_null previous, Direction direction) { 544 | if ((previous->_type == Type::Intro) != (_type == Type::Intro)) { 545 | showAnimatedCover(previous); 546 | } else { 547 | showAnimatedSlide(previous, direction); 548 | } 549 | } 550 | 551 | void Step::showAnimatedCover(not_null previous) { 552 | prepareCoverMask(); 553 | 554 | auto was = previous->prepareCoverAnimationData(); 555 | auto now = prepareCoverAnimationData(); 556 | if (was.lottie) { 557 | _coverAnimation.lottie = std::move(was.lottie); 558 | _coverAnimation.lottieTop = was.lottieTop; 559 | _coverAnimation.lottieHeight = was.lottieHeight; 560 | } else { 561 | _coverAnimation.lottie = std::move(now.lottie); 562 | _coverAnimation.lottieTop = now.lottieTop; 563 | _coverAnimation.lottieHeight = now.lottieHeight; 564 | } 565 | _coverAnimation.title = std::make_unique( 566 | st::windowBg, 567 | std::move(was.title), 568 | std::move(now.title)); 569 | _coverAnimation.description = std::make_unique( 570 | st::windowBg, 571 | std::move(was.description), 572 | std::move(now.description)); 573 | _coverAnimation.contentWas = std::move(was.content); 574 | _coverAnimation.contentWasBottom = was.contentBottom; 575 | _coverAnimation.contentNow = std::move(now.content); 576 | _coverAnimation.contentNowBottom = now.contentBottom; 577 | 578 | if (_coverAnimation.lottie) { 579 | _coverAnimation.lottie->attach(_widget.get()); 580 | } 581 | 582 | inner()->hide(); 583 | if (_scroll) { 584 | _scroll->hide(); 585 | } 586 | _coverAnimationValue.start( 587 | [=] { coverAnimationCallback(); }, 588 | 0., 589 | 1., 590 | st::coverDuration); 591 | coverAnimationCallback(); 592 | } 593 | 594 | void Step::adjustSlideSnapshots( 595 | SlideAnimationData &was, 596 | SlideAnimationData &now) { 597 | const auto pixelRatio = style::DevicePixelRatio(); 598 | const auto wasSize = was.content.size() / pixelRatio; 599 | const auto nowSize = now.content.size() / pixelRatio; 600 | const auto wasBottom = was.contentTop + wasSize.height(); 601 | const auto nowBottom = now.contentTop + nowSize.height(); 602 | const auto widthDelta = nowSize.width() - wasSize.width(); 603 | auto wasMargins = QMargins(); 604 | auto nowMargins = QMargins(); 605 | wasMargins.setTop(std::max(was.contentTop - now.contentTop, 0)); 606 | nowMargins.setTop(std::max(now.contentTop - was.contentTop, 0)); 607 | wasMargins.setLeft(std::max(widthDelta / 2, 0)); 608 | nowMargins.setLeft(-std::min(widthDelta / 2, 0)); 609 | wasMargins.setRight(std::max(widthDelta - (widthDelta / 2), 0)); 610 | nowMargins.setRight(-std::min(widthDelta - (widthDelta / 2), 0)); 611 | wasMargins.setBottom(std::max(nowBottom - wasBottom, 0)); 612 | nowMargins.setBottom(std::max(wasBottom - nowBottom, 0)); 613 | was.content = AddImageMargins(was.content, wasMargins); 614 | now.content = AddImageMargins(now.content, nowMargins); 615 | was.contentTop = now.contentTop = std::min( 616 | was.contentTop, 617 | now.contentTop); 618 | } 619 | 620 | void Step::showAnimatedSlide(not_null previous, Direction direction) { 621 | const auto pixelRatio = style::DevicePixelRatio(); 622 | auto was = previous->prepareSlideAnimationData(); 623 | auto now = prepareSlideAnimationData(); 624 | _slideAnimation.slide = std::make_unique(); 625 | 626 | adjustSlideSnapshots(was, now); 627 | Assert(now.contentTop == was.contentTop); 628 | Assert(now.content.size() == was.content.size()); 629 | 630 | _slideAnimation.slideTop = was.contentTop; 631 | _slideAnimation.slideWidth = was.content.width() / pixelRatio; 632 | _slideAnimation.lottieWas = std::move(was.lottie); 633 | _slideAnimation.lottieWasTop = was.lottieTop; 634 | _slideAnimation.lottieWasHeight = was.lottieHeight; 635 | _slideAnimation.lottieNow = std::move(now.lottie); 636 | _slideAnimation.lottieNowTop = now.lottieTop; 637 | _slideAnimation.lottieNowHeight = now.lottieHeight; 638 | _slideAnimation.slide->setSnapshots( 639 | Ui::PixmapFromImage(std::move(was.content)), 640 | Ui::PixmapFromImage(std::move(now.content))); 641 | 642 | if (_slideAnimation.lottieWas) { 643 | _slideAnimation.lottieWas->attach(_widget.get()); 644 | } 645 | if (_slideAnimation.lottieNow) { 646 | _slideAnimation.lottieNow->attach(_widget.get()); 647 | } 648 | 649 | inner()->hide(); 650 | if (_scroll) { 651 | _scroll->hide(); 652 | } 653 | _slideAnimation.slide->start( 654 | (direction == Direction::Backward), 655 | [=] { slideAnimationCallback(); }, 656 | st::coverDuration); 657 | slideAnimationCallback(); 658 | } 659 | 660 | void Step::coverAnimationCallback() { 661 | const auto dt = _coverAnimationValue.value(1.); 662 | const auto coverShown = (_type == Type::Intro) 663 | ? anim::easeOutCirc(1., dt) 664 | : (1. - anim::linear(1., dt)); 665 | _coverShown = coverShown; 666 | if (_coverAnimation.lottie) { 667 | const auto shown = (1. - coverShown); 668 | const auto height = shown * _coverAnimation.lottieHeight; 669 | _coverAnimation.lottie->setOpacity(shown); 670 | _coverAnimation.lottie->setGeometry(lottieGeometry( 671 | _coverAnimation.lottieTop + coverShown * st::coverHeight, 672 | height)); 673 | } 674 | _widget->update(); 675 | } 676 | 677 | void Step::slideAnimationCallback() { 678 | const auto state = _slideAnimation.slide->state(); 679 | if (_slideAnimation.lottieWas) { 680 | const auto shown = (1. - state.leftProgress); 681 | const auto scale = state.leftAlpha; 682 | const auto fullHeight = _slideAnimation.lottieWasHeight; 683 | const auto height = scale * fullHeight; 684 | const auto delta = (1. - shown) * _slideAnimation.slideWidth; 685 | _slideAnimation.lottieWas->setOpacity(state.leftAlpha); 686 | _slideAnimation.lottieWas->setGeometry(lottieGeometry( 687 | _slideAnimation.lottieWasTop + (1. - scale) * fullHeight / 2., 688 | height).translated(-delta, 0)); 689 | } 690 | if (_slideAnimation.lottieNow) { 691 | const auto shown = state.rightProgress; 692 | const auto scale = state.rightAlpha; 693 | const auto fullHeight = _slideAnimation.lottieNowHeight; 694 | const auto height = scale * fullHeight; 695 | const auto delta = (1. - shown) * _slideAnimation.slideWidth; 696 | _slideAnimation.lottieNow->setOpacity(state.rightAlpha); 697 | _slideAnimation.lottieNow->setGeometry(lottieGeometry( 698 | _slideAnimation.lottieNowTop + (1. - scale) * fullHeight / 2., 699 | height).translated(delta, 0)); 700 | } 701 | _widget->update(); 702 | } 703 | 704 | void Step::setFocus() { 705 | inner()->setFocus(); 706 | } 707 | 708 | rpl::lifetime &Step::lifetime() { 709 | return widget()->lifetime(); 710 | } 711 | 712 | void Step::requestNextButton(NextButtonState state) { 713 | if (!state.top) { 714 | state.top = st::stepHeight - st::nextButtonAreaHeight; 715 | } 716 | state.top += contentTop(); 717 | _nextButtonState = state; 718 | } 719 | 720 | void Step::ensureVisible(int top, int height) { 721 | Expects(_type == Type::Scroll); 722 | Expects(_scroll != nullptr); 723 | 724 | _scroll->scrollToY(top, top + height); 725 | } 726 | 727 | void Step::showLottie(const QString &path, int top, int height) { 728 | const auto lottieWidth = 2 * st::randomLottieHeight; 729 | const auto content = [&] { 730 | auto file = QFile(path); 731 | return file.open(QIODevice::ReadOnly) 732 | ? file.readAll() 733 | : QByteArray(); 734 | }(); 735 | _lottie = std::make_unique( 736 | inner(), 737 | content); 738 | _lottieTop = top; 739 | _lottieHeight = height; 740 | 741 | inner()->sizeValue( 742 | ) | rpl::filter([=] { 743 | return (_lottie->parent() == inner()); 744 | }) | rpl::start_with_next([=](QSize size) { 745 | _lottie->setGeometry(lottieGeometry( 746 | contentTop() + _lottieTop, 747 | _lottieHeight)); 748 | }, inner()->lifetime()); 749 | } 750 | 751 | void Step::startLottie() { 752 | Expects(_lottie != nullptr); 753 | 754 | _lottie->start(); 755 | } 756 | 757 | void Step::stopLottieOnFrame(int frame) { 758 | Expects(_lottie != nullptr); 759 | 760 | _lottie->stopOnFrame(frame); 761 | } 762 | 763 | QRect Step::lottieGeometry(int top, int height) const { 764 | const auto width = 2 * height; 765 | return { 766 | (inner()->width() - width) / 2, 767 | top, 768 | width, 769 | height 770 | }; 771 | } 772 | 773 | } // namespace Keygen::Steps 774 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/step.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "base/unique_qptr.h" 10 | #include "ui/effects/animations.h" 11 | #include "ui/widgets/labels.h" 12 | 13 | struct TextWithEntities; 14 | 15 | namespace Ui { 16 | class LottieAnimation; 17 | class SlideAnimation; 18 | class CrossFadeAnimation; 19 | class RpWidget; 20 | class FlatLabel; 21 | class ScrollArea; 22 | class RoundButton; 23 | template 24 | class FadeWrap; 25 | } // namespace Ui 26 | 27 | namespace Keygen::Steps { 28 | 29 | struct NextButtonState { 30 | QString text; 31 | int top = 0; 32 | int width = 0; 33 | }; 34 | 35 | enum class Direction { 36 | Forward, 37 | Backward, 38 | }; 39 | 40 | class Step { 41 | public: 42 | enum class Type { 43 | Intro, 44 | Scroll, 45 | Default 46 | }; 47 | 48 | Step(Type intro); 49 | Step(const Step &other) = delete; 50 | Step &operator=(const Step &other) = delete; 51 | virtual ~Step() = 0; 52 | 53 | [[nodiscard]] virtual int desiredHeight() const; 54 | [[nodiscard]] virtual bool allowEscapeBack() const; 55 | [[nodiscard]] not_null widget() const; 56 | [[nodiscard]] rpl::producer nextButtonState() const; 57 | [[nodiscard]] rpl::producer<> nextClicks() const; 58 | [[nodiscard]] rpl::producer coverShown() const; 59 | 60 | void showAnimated(not_null previous, Direction direction); 61 | virtual void setFocus(); 62 | 63 | [[nodiscard]] rpl::lifetime &lifetime(); 64 | 65 | protected: 66 | [[nodiscard]] not_null inner() const; 67 | [[nodiscard]] int contentTop() const; 68 | 69 | void setTitle(rpl::producer text, int top = 0); 70 | void setDescription(rpl::producer text, int top = 0); 71 | void requestNextButton(NextButtonState state); 72 | void ensureVisible(int top, int height); 73 | 74 | void showLottie(const QString &path, int top, int height); 75 | void startLottie(); 76 | void stopLottieOnFrame(int frame); 77 | 78 | [[nodiscard]] virtual QImage grabForAnimation(QRect rect) const; 79 | virtual void showFinishedHook(); 80 | 81 | private: 82 | struct CoverAnimationData; 83 | struct CoverAnimation { 84 | CoverAnimation() = default; 85 | CoverAnimation(CoverAnimation&&) = default; 86 | CoverAnimation &operator=(CoverAnimation&&) = default; 87 | ~CoverAnimation(); 88 | 89 | std::unique_ptr lottie; 90 | std::unique_ptr title; 91 | std::unique_ptr description; 92 | 93 | // From description bottom till the bottom. 94 | QPixmap contentWas; 95 | QPixmap contentNow; 96 | int contentWasBottom = 0; 97 | int contentNowBottom = 0; 98 | int lottieTop = 0; 99 | int lottieHeight = 0; 100 | }; 101 | struct SlideAnimationData; 102 | struct SlideAnimation { 103 | SlideAnimation() = default; 104 | SlideAnimation(SlideAnimation&&) = default; 105 | SlideAnimation &operator=(SlideAnimation&&) = default; 106 | ~SlideAnimation(); 107 | 108 | std::unique_ptr lottieWas; 109 | std::unique_ptr lottieNow; 110 | 111 | std::unique_ptr slide; 112 | int slideTop = 0; 113 | int slideWidth = 0; 114 | int lottieWasTop = 0; 115 | int lottieWasHeight = 0; 116 | int lottieNowTop = 0; 117 | int lottieNowHeight = 0; 118 | }; 119 | 120 | [[nodiscard]] Ui::ScrollArea *resolveScrollArea(); 121 | [[nodiscard]] not_null resolveInner(); 122 | [[nodiscard]] auto resolveNextButton() 123 | ->std::unique_ptr>; 124 | void initGeometry(); 125 | void initNextButton(); 126 | void initCover(); 127 | 128 | void showAnimatedCover(not_null previous); 129 | void showAnimatedSlide(not_null previous, Direction direction); 130 | void prepareCoverMask(); 131 | void paintContent(QRect clip); 132 | void paintCover(QPainter &p, int top, QRect clip); 133 | void showFinished(); 134 | 135 | [[nodiscard]] int coverAnimationContentTop() const; 136 | [[nodiscard]] int slideAnimationContentTop() const; 137 | [[nodiscard]] int animationContentBottom() const; 138 | 139 | [[nodiscard]] CoverAnimationData prepareCoverAnimationData(); 140 | [[nodiscard]] QPixmap prepareCoverAnimationContent() const; 141 | void coverAnimationCallback(); 142 | void paintCoverAnimation(QPainter &p, QRect clip); 143 | void paintCoverAnimationContent( 144 | QPainter &p, 145 | const QPixmap &snapshot, 146 | int snapshotBottom, 147 | float64 alpha, 148 | float64 howMuchHidden); 149 | [[nodiscard]] SlideAnimationData prepareSlideAnimationData(); 150 | [[nodiscard]] QImage prepareSlideAnimationContent() const; 151 | void adjustSlideSnapshots( 152 | SlideAnimationData &was, 153 | SlideAnimationData &now); 154 | void slideAnimationCallback(); 155 | void paintSlideAnimation(QPainter &p, QRect clip); 156 | 157 | [[nodiscard]] QRect lottieGeometry(int top, int height) const; 158 | 159 | const Type _type = Type(); 160 | const std::unique_ptr _widget; 161 | Ui::ScrollArea * const _scroll = nullptr; 162 | const not_null _inner; 163 | 164 | std::unique_ptr _lottie; 165 | int _lottieTop = 0; 166 | int _lottieHeight = 0; 167 | base::unique_qptr _title; 168 | base::unique_qptr _description; 169 | 170 | Ui::Animations::Simple _coverAnimationValue; 171 | CoverAnimation _coverAnimation; 172 | SlideAnimation _slideAnimation; 173 | QPixmap _coverMask; 174 | rpl::variable _coverShown = 0.; 175 | 176 | const std::unique_ptr> _nextButton; 177 | NextButtonState _lastNextState; 178 | rpl::variable _nextButtonState; 179 | 180 | }; 181 | 182 | } // namespace Keygen::Steps 183 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/view.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "keygen/steps/view.h" 8 | 9 | #include "keygen/phrases.h" 10 | #include "ui/rp_widget.h" 11 | #include "ui/widgets/labels.h" 12 | #include "ui/text/text_utilities.h" 13 | #include "styles/style_keygen.h" 14 | 15 | namespace Keygen::Steps { 16 | namespace { 17 | 18 | class Word final { 19 | public: 20 | Word(not_null parent, int index, const QString &word); 21 | 22 | void move(int left, int top) const; 23 | [[nodiscard]] int top() const; 24 | 25 | private: 26 | object_ptr _index; 27 | object_ptr _word; 28 | 29 | }; 30 | 31 | Word::Word(not_null parent, int index, const QString &word) 32 | : _index(parent, QString::number(index + 1) + '.', st::wordIndexLabel) 33 | , _word(parent, word, st::wordLabel) { 34 | } 35 | 36 | void Word::move(int left, int top) const { 37 | _index->move(left - _index->width() - st::wordIndexSkip, top); 38 | _word->move(left, top); 39 | } 40 | 41 | int Word::top() const { 42 | return _index->y(); 43 | } 44 | 45 | } // namespace 46 | 47 | View::View(std::vector &&words) : Step(Type::Scroll) { 48 | setTitle(tr::lng_view_title(Ui::Text::RichLangValue)); 49 | setDescription(tr::lng_view_description(Ui::Text::RichLangValue)); 50 | initControls(std::move(words)); 51 | } 52 | 53 | int View::desiredHeight() const { 54 | return _desiredHeight; 55 | } 56 | 57 | void View::initControls(std::vector &&words) { 58 | Expects(words.size() % 2 == 0); 59 | 60 | auto labels = std::make_shared>>(); 61 | const auto rows = words.size() / 2; 62 | for (auto i = 0; i != rows; ++i) { 63 | labels->emplace_back( 64 | Word(inner(), i, words[i]), 65 | Word(inner(), i + rows, words[i + rows])); 66 | } 67 | const auto rowsBottom = st::wordsTop + rows * st::wordHeight; 68 | 69 | inner()->sizeValue( 70 | ) | rpl::start_with_next([=](QSize size) { 71 | const auto half = size.width() / 2; 72 | const auto left = half - st::wordSkipLeft; 73 | const auto right = half + st::wordSkipRight; 74 | auto top = contentTop() + st::wordsTop; 75 | for (const auto &pair : *labels) { 76 | pair.first.move(left, top); 77 | pair.second.move(right, top); 78 | top += st::wordHeight; 79 | } 80 | 81 | auto state = NextButtonState(); 82 | state.text = tr::lng_view_next(tr::now); 83 | state.top = rowsBottom + st::wordsNextSkip; 84 | requestNextButton(state); 85 | }, inner()->lifetime()); 86 | 87 | _desiredHeight = rowsBottom 88 | + st::wordsNextSkip 89 | + st::wordsNextBottomSkip; 90 | } 91 | 92 | } // namespace Keygen::Steps 93 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/steps/view.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "keygen/steps/step.h" 10 | 11 | namespace Keygen::Steps { 12 | 13 | class View final : public Step { 14 | public: 15 | explicit View(std::vector &&words); 16 | 17 | int desiredHeight() const override; 18 | 19 | private: 20 | void initControls(std::vector &&words); 21 | 22 | int _desiredHeight = 0; 23 | 24 | }; 25 | 26 | } // namespace Keygen::Steps 27 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/keygen/tr.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace tr { 14 | 15 | struct now_t { 16 | }; 17 | 18 | inline constexpr auto now = now_t(); 19 | 20 | struct I { 21 | QString operator()(const QString &value) const { return value; }; 22 | }; 23 | 24 | template 25 | using Result = decltype(std::declval

()(QString())); 26 | 27 | struct phrase { 28 | template > 29 | Result

operator()(now_t, P p = P()) const { 30 | return p(value); 31 | }; 32 | template > 33 | rpl::producer> operator()(P p = P()) const { 34 | return rpl::single(value) | rpl::map(p); 35 | }; 36 | 37 | QString value; 38 | }; 39 | 40 | } // namespace tr 41 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/keygen.style: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | using "ui/basic.style"; 8 | using "ui/widgets/widgets.style"; 9 | 10 | windowSize: size(665px, 488px); 11 | windowSizeMin: size(480px, 480px); 12 | messageBoxWidth: 320px; 13 | 14 | scrollArea: ScrollArea(defaultScrollArea) { 15 | round: 3px; 16 | width: 12px; 17 | topsh: 0px; 18 | bottomsh: 0px; 19 | } 20 | 21 | nextButton: RoundButton(defaultActiveButton) { 22 | width: 264px; 23 | height: 56px; 24 | 25 | textTop: 17px; 26 | font: font(17px semibold); 27 | } 28 | nextButtonAreaHeight: 76px; 29 | topBackButton: IconButton(backButton) { 30 | width: 56px; 31 | height: 56px; 32 | rippleAreaPosition: point(8px, 8px); 33 | } 34 | verifyLink: LinkButton(defaultLinkButton) { 35 | font: font(14px); 36 | overFont: font(14px underline); 37 | } 38 | verifyLinkTop: 21px; 39 | 40 | coverHeight: 208px; 41 | coverMaxWidth: 880px; 42 | coverIconsMinSkip: 120px; 43 | coverLeft: icon {{ "intro_left", introCoverIconsFg }}; 44 | coverRight: icon {{ "intro_right", introCoverIconsFg }}; 45 | coverIcon: icon {{ "intro_gem", windowBg }}; 46 | coverIconTop: 49px; 47 | coverDuration: 200; 48 | 49 | doneMenuTogglePosition: point(8px, 16px); 50 | doneMenuPosition: point(2px, 40px); 51 | 52 | centeredLabel: FlatLabel(defaultFlatLabel) { 53 | align: align(center); 54 | } 55 | boldCenteredLabel: FlatLabel(centeredLabel) { 56 | textFg: introTitleFg; 57 | } 58 | grayCenteredLabel: FlatLabel(centeredLabel) { 59 | textFg: introDescriptionFg; 60 | } 61 | introTitle: FlatLabel(boldCenteredLabel) { 62 | style: TextStyle(defaultTextStyle) { 63 | font: font(22px bold); 64 | linkFont: font(22px bold); 65 | linkFontOver: font(22px bold underline); 66 | } 67 | } 68 | introTitleTop: 159px; 69 | introTitleTopMin: 247px; 70 | introDescription: FlatLabel(grayCenteredLabel) { 71 | style: TextStyle(defaultTextStyle) { 72 | font: font(15px); 73 | linkFont: font(15px); 74 | linkFontOver: font(15px underline); 75 | lineHeight: 24px; 76 | } 77 | } 78 | introDescriptionTop: 39px; 79 | introNextWidth: 194px; 80 | stepTitle: FlatLabel(boldCenteredLabel) { 81 | style: TextStyle(defaultTextStyle) { 82 | font: font(19px semibold); 83 | linkFont: font(19px semibold); 84 | linkFontOver: font(19px semibold underline); 85 | } 86 | } 87 | stepTitleTop: 118px; 88 | stepDescription: FlatLabel(grayCenteredLabel) { 89 | minWidth: 440px; 90 | style: TextStyle(defaultTextStyle) { 91 | font: font(14px); 92 | linkFont: font(14px); 93 | linkFontOver: font(14px underline); 94 | lineHeight: 20px; 95 | } 96 | } 97 | stepDescriptionTop: 40px; 98 | stepHeight: 400px; 99 | scrollTitleTop: 71px; 100 | scrollDescriptionTop: 40px; 101 | 102 | randomCounterFontSize: 48px; 103 | randomCounter: FlatLabel(boldCenteredLabel) { 104 | style: TextStyle(defaultTextStyle) { 105 | font: font(randomCounterFontSize semibold); 106 | linkFont: font(randomCounterFontSize semibold); 107 | linkFontOver: font(randomCounterFontSize semibold underline); 108 | } 109 | } 110 | randomCounterTop: 288px; 111 | randomCounterLabel: stepDescription; 112 | randomCounterLabelTop: 357px; 113 | randomReadyTotalLabelTop: 292px; 114 | randomLottieTop: 20px; 115 | randomLottieHeight: 112px; 116 | 117 | createdLottieTop: 0px; 118 | createdLottieHeight: 112px; 119 | 120 | wordsTop: 225px; 121 | wordIndexLabel: FlatLabel(defaultFlatLabel) { 122 | textFg: introDescriptionFg; 123 | } 124 | wordLabel: FlatLabel(defaultFlatLabel) { 125 | style: TextStyle(defaultTextStyle) { 126 | font: semiboldFont; 127 | linkFont: semiboldFont; 128 | linkFontOver: font(fsize semibold underline); 129 | } 130 | } 131 | wordIndexSkip: 8px; 132 | wordSkipLeft: 117px; 133 | wordSkipRight: 69px; 134 | wordHeight: 32px; 135 | wordsNextSkip: 40px; 136 | wordsNextBottomSkip: 110px; 137 | 138 | checksTop: 198px; 139 | checkInputField: InputField(defaultInputField) { 140 | textMargins: margins(0px, 6px, 0px, 4px); 141 | width: 112px; 142 | heightMin: 32px; 143 | } 144 | checkInputSkip: 8px; 145 | 146 | doneTitleTop: 30px; 147 | doneDescriptionTop: 40px; 148 | doneKeyLabel: FlatLabel(defaultFlatLabel) { 149 | style: TextStyle(defaultTextStyle) { 150 | font: font(15px); 151 | linkFont: font(15px); 152 | linkFontOver: font(15px underline); 153 | lineHeight: 26px; 154 | } 155 | align: align(center); 156 | minWidth: 50px; 157 | margin: margins(27px, 14px, 27px, 10px); 158 | } 159 | doneKeyTop: 144px; 160 | doneCopyTop: 294px; 161 | doneSaveTop: 346px; 162 | 163 | suggestionsScroll: defaultSolidScroll; 164 | suggestionsSkip: 4px; 165 | suggestionsRadius: 2px; 166 | suggestionsHeightMax: 106px; 167 | suggestionHeight: 28px; 168 | suggestionShadowWidth: 1px; 169 | suggestionLeft: 10px; 170 | suggestionTop: 5px; 171 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/lottie_widget.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "ui/lottie_widget.h" 8 | 9 | #include "ui/rp_widget.h" 10 | #include "ui/style/style_core.h" 11 | #include "lottie/lottie_single_player.h" 12 | 13 | #include 14 | 15 | namespace Ui { 16 | 17 | LottieAnimation::LottieAnimation( 18 | not_null parent, 19 | const QByteArray &content) 20 | : _widget(std::make_unique(parent)) 21 | , _lottie( 22 | std::make_unique( 23 | content, 24 | Lottie::FrameRequest(), 25 | Lottie::Quality::High)) { 26 | _lottie->updates( 27 | ) | rpl::start_with_next([=](Lottie::Update update) { 28 | const auto data = &update.data; 29 | if (const auto info = base::get_if(data)) { 30 | _framesInLoop = info->framesCount; 31 | } 32 | _widget->update(); 33 | }, _widget->lifetime()); 34 | 35 | _widget->paintRequest( 36 | ) | rpl::filter([=] { 37 | return _lottie->ready(); 38 | }) | rpl::start_with_next([=] { 39 | paintFrame(); 40 | }, _widget->lifetime()); 41 | } 42 | 43 | LottieAnimation::~LottieAnimation() = default; 44 | 45 | void LottieAnimation::setGeometry(QRect geometry) { 46 | _widget->setGeometry(geometry); 47 | _widget->update(); 48 | } 49 | 50 | void LottieAnimation::setOpacity(float64 opacity) { 51 | _opacity = opacity; 52 | _widget->update(); 53 | } 54 | 55 | not_null LottieAnimation::parent() const { 56 | return _widget->parentWidget(); 57 | } 58 | 59 | void LottieAnimation::detach() { 60 | _widget->setParent(nullptr); 61 | } 62 | 63 | void LottieAnimation::attach(not_null parent) { 64 | _widget->setParent(parent); 65 | _widget->show(); 66 | } 67 | 68 | void LottieAnimation::paintFrame() { 69 | const auto pixelRatio = style::DevicePixelRatio(); 70 | const auto request = Lottie::FrameRequest{ 71 | _widget->size() * pixelRatio 72 | }; 73 | const auto frame = _lottie->frameInfo(request); 74 | const auto width = frame.image.width() / pixelRatio; 75 | const auto height = frame.image.height() / pixelRatio; 76 | const auto left = (_widget->width() - width) / 2; 77 | const auto top = (_widget->height() - height) / 2; 78 | const auto destination = QRect{ left, top, width, height }; 79 | 80 | auto p = QPainter(_widget.get()); 81 | p.setOpacity(_opacity); 82 | p.drawImage(destination, frame.image); 83 | 84 | if (_startPlaying && frame.index == 0) { 85 | ++_loop; 86 | } 87 | const auto index = ((_loop - 1) * _framesInLoop + frame.index); 88 | if (_startPlaying && (!_stopOnFrame || index < _stopOnFrame)) { 89 | _lottie->markFrameShown(); 90 | } 91 | } 92 | 93 | void LottieAnimation::start() { 94 | _startPlaying = true; 95 | _widget->update(); 96 | } 97 | 98 | void LottieAnimation::stopOnFrame(int frame) { 99 | _stopOnFrame = frame; 100 | } 101 | 102 | } // namespace Ui 103 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/lottie_widget.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | namespace Lottie { 10 | class SinglePlayer; 11 | } // namespace Lottie 12 | 13 | namespace Ui { 14 | 15 | class RpWidget; 16 | 17 | class LottieAnimation final { 18 | public: 19 | LottieAnimation(not_null parent, const QByteArray &content); 20 | ~LottieAnimation(); 21 | 22 | void setGeometry(QRect geometry); 23 | void setOpacity(float64 opacity); 24 | 25 | void detach(); 26 | void attach(not_null parent); 27 | [[nodiscard]] not_null parent() const; 28 | 29 | void start(); 30 | void stopOnFrame(int frame); 31 | 32 | private: 33 | void paintFrame(); 34 | 35 | const std::unique_ptr _widget; 36 | const std::unique_ptr _lottie; 37 | 38 | float64 _opacity = 1.; 39 | int _stopOnFrame = 0; 40 | int _loop = 0; 41 | int _framesInLoop = 0; 42 | bool _startPlaying = false; 43 | 44 | }; 45 | 46 | } // namespace Ui 47 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/message_box.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "ui/message_box.h" 8 | 9 | #include "styles/style_layers.h" 10 | #include "styles/style_keygen.h" 11 | 12 | #include 13 | 14 | namespace Ui { 15 | 16 | void InitMessageBox( 17 | not_null box, 18 | rpl::producer title, 19 | rpl::producer text) { 20 | box->setWidth(st::messageBoxWidth); 21 | box->setTitle(std::move(title)); 22 | box->addRow(object_ptr( 23 | box.get(), 24 | std::move(text), 25 | st::boxLabel)); 26 | box->events( 27 | ) | rpl::filter([](not_null e) { 28 | return (e->type() == QEvent::KeyPress); 29 | }) | rpl::map([](not_null e) { 30 | return static_cast(e.get()); 31 | }) | rpl::start_with_next([=](not_null e) { 32 | if (e->key() == Qt::Key_Escape) { 33 | e->accept(); 34 | box->closeBox(); 35 | } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { 36 | e->accept(); 37 | box->triggerButton(0); 38 | } 39 | }, box->lifetime()); 40 | box->setInnerFocus(); 41 | } 42 | 43 | } // namespace Ui 44 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/message_box.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | #include "ui/layers/generic_box.h" 10 | 11 | namespace Ui { 12 | 13 | void InitMessageBox( 14 | not_null box, 15 | rpl::producer title, 16 | rpl::producer text); 17 | 18 | } // namespace Ui 19 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/public_key_label.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "ui/public_key_label.h" 8 | 9 | #include "ui/widgets/labels.h" 10 | #include "styles/style_widgets.h" 11 | #include "styles/style_keygen.h" 12 | #include "styles/palette.h" 13 | 14 | #include 15 | 16 | namespace Ui { 17 | namespace { 18 | 19 | style::font MonospaceFont(const style::font &parent) { 20 | const auto family = style::MonospaceFont()->family(); 21 | return style::font(parent->size(), parent->flags(), family); 22 | } 23 | 24 | style::TextStyle ComputeKeyStyle(const style::TextStyle &parent) { 25 | auto result = parent; 26 | result.font = MonospaceFont(result.font); 27 | result.linkFont = MonospaceFont(result.linkFont); 28 | result.linkFontOver = MonospaceFont(result.linkFontOver); 29 | return result; 30 | } 31 | 32 | } // namespace 33 | 34 | not_null CreatePublicKeyLabel( 35 | not_null parent, 36 | const QString &text) { 37 | auto result = Ui::CreateChild(parent.get()); 38 | 39 | const auto st = result->lifetime().make_state( 40 | st::doneKeyLabel); 41 | st->style = ComputeKeyStyle(st->style); 42 | 43 | const auto label = Ui::CreateChild( 44 | result, 45 | rpl::single(text), 46 | *st); 47 | label->setBreakEverywhere(true); 48 | label->setDoubleClickSelectsParagraph(true); 49 | 50 | const auto half = text.size() / 2; 51 | const auto first = text.mid(0, half); 52 | const auto second = text.mid(half); 53 | const auto width = std::max( 54 | st->style.font->width(first), 55 | st->style.font->width(second) 56 | ) + st->style.font->spacew / 2; 57 | label->resizeToWidth(width); 58 | label->setSelectable(true); 59 | label->move(0, 0); 60 | result->resize(label->size()); 61 | 62 | result->paintRequest( 63 | ) | rpl::start_with_next([=](QRect clip) { 64 | auto p = QPainter(result); 65 | p.setPen(Qt::NoPen); 66 | p.setBrush(st::windowBgOver); 67 | p.drawRoundedRect( 68 | result->rect(), 69 | st::roundRadiusSmall, 70 | st::roundRadiusSmall); 71 | }, result->lifetime()); 72 | 73 | return result; 74 | } 75 | 76 | } // namespace Ui 77 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/public_key_label.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | class QWidget; 10 | class QString; 11 | 12 | namespace Ui { 13 | 14 | class RpWidget; 15 | 16 | [[nodiscard]] not_null CreatePublicKeyLabel( 17 | not_null parent, 18 | const QString &text); 19 | 20 | } // namespace Ui 21 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/word_suggestions.cpp: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #include "ui/word_suggestions.h" 8 | 9 | #include "base/object_ptr.h" 10 | #include "ui/widgets/scroll_area.h" 11 | #include "ui/rp_widget.h" 12 | #include "ui/painter.h" 13 | #include "styles/style_keygen.h" 14 | #include "styles/style_widgets.h" 15 | #include "styles/palette.h" 16 | 17 | #include 18 | 19 | namespace Ui { 20 | 21 | WordSuggestions::WordSuggestions(not_null parent) 22 | : _widget(std::make_unique(parent)) 23 | , _scroll(Ui::CreateChild(_widget.get(), st::suggestionsScroll)) 24 | , _inner(_scroll->setOwnedWidget(object_ptr(_widget.get()))) { 25 | _widget->sizeValue( 26 | ) | rpl::start_with_next([=](QSize size) { 27 | _scroll->setGeometry({ QPoint(), size }); 28 | }, _widget->lifetime()); 29 | 30 | _widget->paintRequest( 31 | ) | rpl::start_with_next([=](QRect clip) { 32 | paintRows(); 33 | }, _widget->lifetime()); 34 | 35 | _inner->setMouseTracking(true); 36 | _inner->events( 37 | ) | rpl::start_with_next([=](not_null e) { 38 | if (e->type() == QEvent::MouseMove) { 39 | selectByMouse(static_cast(e.get())->pos()); 40 | } else if (e->type() == QEvent::MouseButtonPress) { 41 | _pressed = _selected; 42 | } else if (e->type() == QEvent::MouseButtonRelease) { 43 | _widget->update(); 44 | if (std::exchange(_pressed, -1) == _selected) { 45 | choose(); 46 | } 47 | } 48 | }, _inner->lifetime()); 49 | } 50 | 51 | void WordSuggestions::show(std::vector &&words) { 52 | if (_words == words) { 53 | return; 54 | } 55 | _words = std::move(words); 56 | select(0); 57 | const auto height = st::suggestionsSkip * 2 58 | + int(_words.size()) * st::suggestionHeight 59 | + st::suggestionShadowWidth; 60 | const auto outerHeight = std::min(height, st::suggestionsHeightMax); 61 | _inner->resize(_widget->width(), height); 62 | _widget->resize(_widget->width(), outerHeight); 63 | _widget->update(); 64 | _widget->show(); 65 | } 66 | 67 | void WordSuggestions::hide() { 68 | _hidden.fire({}); 69 | } 70 | 71 | void WordSuggestions::selectDown() { 72 | Expects(!_words.empty()); 73 | 74 | select(_selected + 1); 75 | ensureSelectedVisible(); 76 | } 77 | 78 | void WordSuggestions::selectUp() { 79 | select(_selected - 1); 80 | ensureSelectedVisible(); 81 | } 82 | 83 | void WordSuggestions::select(int index) { 84 | Expects(!_words.empty()); 85 | 86 | index = std::clamp(index, 0, int(_words.size()) - 1); 87 | if (_selected == index) { 88 | return; 89 | } 90 | _selected = index; 91 | _inner->update(); 92 | } 93 | 94 | void WordSuggestions::selectByMouse(QPoint position) { 95 | select((position.y() - st::suggestionsSkip) / st::suggestionHeight); 96 | } 97 | 98 | void WordSuggestions::ensureSelectedVisible() { 99 | const auto skip = st::suggestionsSkip; 100 | const auto top = skip + _selected * st::suggestionHeight; 101 | _scroll->scrollToY(top - skip, top + st::suggestionHeight + skip); 102 | } 103 | 104 | void WordSuggestions::choose() { 105 | Expects(!_words.empty()); 106 | Expects(_selected >= 0 && _selected < _words.size()); 107 | 108 | _chosen.fire_copy(_words[_selected]); 109 | } 110 | 111 | void WordSuggestions::setGeometry(QPoint position, int width) { 112 | _widget->setGeometry({ position, QSize{ width, _widget->height() } }); 113 | _inner->resize(width, _inner->height()); 114 | } 115 | 116 | void WordSuggestions::paintRows() { 117 | QPainter(_widget.get()).drawImage(0, 0, prepareFrame()); 118 | } 119 | 120 | QImage WordSuggestions::prepareFrame() const { 121 | const auto pixelRatio = style::DevicePixelRatio(); 122 | if (_frame.size() != _widget->size() * pixelRatio) { 123 | _frame = QImage( 124 | _widget->size() * pixelRatio, 125 | QImage::Format_ARGB32_Premultiplied); 126 | } 127 | _frame.fill(st::windowBg->c); 128 | _frame.setDevicePixelRatio(pixelRatio); 129 | { 130 | auto p = QPainter(&_frame); 131 | 132 | const auto thickness = st::suggestionShadowWidth; 133 | 134 | p.setPen(st::windowFg); 135 | p.setFont(st::normalFont); 136 | auto index = 0; 137 | const auto wordLeft = thickness; 138 | auto wordTop = st::suggestionsSkip - _scroll->scrollTop(); 139 | const auto wordWidth = _widget->width() - 2 * thickness; 140 | const auto wordHeight = st::suggestionHeight; 141 | for (const auto &word : _words) { 142 | if (index == (_pressed >= 0 ? _pressed : _selected)) { 143 | p.fillRect( 144 | wordLeft, 145 | wordTop, 146 | wordWidth, 147 | wordHeight, 148 | st::windowBgOver); 149 | } 150 | p.drawText( 151 | wordLeft + st::suggestionLeft, 152 | wordTop + st::suggestionTop + st::normalFont->ascent, 153 | word); 154 | wordTop += wordHeight; 155 | ++index; 156 | } 157 | 158 | const auto radius = st::suggestionsRadius; 159 | const auto left = float64(thickness) / 2; 160 | const auto top = -2. * radius; 161 | const auto width = float64(_widget->width()) - thickness; 162 | const auto height = float64(_widget->height()) 163 | - top 164 | + ((thickness / 2.) - thickness); 165 | 166 | PainterHighQualityEnabler hq(p); 167 | p.setBrush(Qt::NoBrush); 168 | auto pen = st::defaultInputField.borderFg->p; 169 | pen.setWidth(thickness); 170 | p.setPen(pen); 171 | p.drawRoundedRect(QRectF{ left, top, width, height }, radius, radius); 172 | } 173 | return _frame; 174 | } 175 | 176 | rpl::producer WordSuggestions::chosen() const { 177 | return _chosen.events(); 178 | } 179 | 180 | rpl::producer<> WordSuggestions::hidden() const { 181 | return _hidden.events(); 182 | } 183 | 184 | rpl::lifetime &WordSuggestions::lifetime() { 185 | return _widget->lifetime(); 186 | } 187 | 188 | } // namespace Ui 189 | -------------------------------------------------------------------------------- /Keygen/SourceFiles/ui/word_suggestions.h: -------------------------------------------------------------------------------- 1 | // This file is part of TON Key Generator, 2 | // a desktop application for the TON Blockchain project. 3 | // 4 | // For license and copyright information please follow this link: 5 | // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | // 7 | #pragma once 8 | 9 | namespace Ui { 10 | 11 | class RpWidget; 12 | class ScrollArea; 13 | 14 | class WordSuggestions final { 15 | public: 16 | explicit WordSuggestions(not_null parent); 17 | 18 | void setGeometry(QPoint position, int width); 19 | void show(std::vector &&words); 20 | void hide(); 21 | 22 | void selectDown(); 23 | void selectUp(); 24 | void select(int index); 25 | void choose(); 26 | 27 | [[nodiscard]] rpl::producer chosen() const; 28 | [[nodiscard]] rpl::producer<> hidden() const; 29 | 30 | [[nodiscard]] rpl::lifetime &lifetime(); 31 | 32 | private: 33 | void paintRows(); 34 | void ensureSelectedVisible(); 35 | void selectByMouse(QPoint position); 36 | [[nodiscard]] QImage prepareFrame() const; 37 | 38 | const std::unique_ptr _widget; 39 | const not_null _scroll; 40 | const not_null _inner; 41 | 42 | mutable QImage _frame; 43 | std::vector _words; 44 | int _selected = -1; 45 | int _pressed = -1; 46 | 47 | rpl::event_stream _chosen; 48 | rpl::event_stream<> _hidden; 49 | 50 | }; 51 | 52 | } // namespace Ui 53 | -------------------------------------------------------------------------------- /Keygen/build/build.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | setlocal enabledelayedexpansion 3 | set "FullScriptPath=%~dp0" 4 | set "FullExecPath=%cd%" 5 | 6 | FOR /F "tokens=1* delims= " %%i in (%FullScriptPath%target) do set "BuildTarget=%%i" 7 | 8 | FOR /F "tokens=1,2* delims= " %%i in (%FullScriptPath%version) do set "%%i=%%j" 9 | 10 | set "VersionForPacker=%AppVersion%" 11 | set "AlphaBetaParam=" 12 | set "AppVersionStrFull=%AppVersionStr%" 13 | 14 | echo. 15 | echo Building version %AppVersionStrFull% for Windows.. 16 | echo. 17 | 18 | set "HomePath=%FullScriptPath%.." 19 | set "SolutionPath=%HomePath%\..\out" 20 | set "PortableFile=tonkeygen.%AppVersionStrFull%.win.zip" 21 | set "ReleasePath=%HomePath%\..\out\Release" 22 | set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%" 23 | set "SignPath=%HomePath%\..\..\DesktopPrivate\Sign.bat" 24 | set "BinaryName=Keygen" 25 | set "FinalReleasePath=Z:\Projects\backup\tonkeygen" 26 | 27 | if not exist %FinalReleasePath% ( 28 | echo Release path %FinalReleasePath% not found! 29 | exit /b 1 30 | ) 31 | if exist %ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStr%\ ( 32 | echo Deploy folder for version %AppVersionStr% already exists! 33 | exit /b 1 34 | ) 35 | 36 | cd "%HomePath%" 37 | 38 | call configure.bat 39 | if %errorlevel% neq 0 goto error 40 | 41 | cd "%SolutionPath%" 42 | call cmake --build . --config Release --target Keygen 43 | if %errorlevel% neq 0 goto error 44 | 45 | echo. 46 | echo Version %AppVersionStrFull% build successfull. Preparing.. 47 | echo. 48 | 49 | set "PATH=%PATH%;C:\Program Files\7-Zip" 50 | 51 | cd "%ReleasePath%" 52 | 53 | :sign1 54 | call "%SignPath%" "%BinaryName%.exe" 55 | if %errorlevel% neq 0 ( 56 | timeout /t 3 57 | goto sign1 58 | ) 59 | if not exist "%ReleasePath%\deploy" mkdir "%ReleasePath%\deploy" 60 | if not exist "%ReleasePath%\deploy\%AppVersionStrMajor%" mkdir "%ReleasePath%\deploy\%AppVersionStrMajor%" 61 | mkdir "%DeployPath%" 62 | mkdir "%DeployPath%\%BinaryName%" 63 | if %errorlevel% neq 0 goto error 64 | 65 | move "%ReleasePath%\%BinaryName%.exe" "%DeployPath%\%BinaryName%\" 66 | xcopy "%ReleasePath%\%BinaryName%.pdb" "%DeployPath%\" 67 | if %errorlevel% neq 0 goto error 68 | 69 | cd "%DeployPath%" 70 | 7z a -mx9 %PortableFile% %BinaryName%\ 71 | if %errorlevel% neq 0 goto error 72 | 73 | move "%DeployPath%\%BinaryName%\%BinaryName%.exe" "%DeployPath%\" 74 | rmdir "%DeployPath%\%BinaryName%" 75 | if %errorlevel% neq 0 goto error 76 | 77 | set "FinalDeployPath=%FinalReleasePath%\%AppVersionStrMajor%\%AppVersionStrFull%\tsetup" 78 | 79 | echo. 80 | echo Version %AppVersionStrFull% is ready for deploy! 81 | echo. 82 | 83 | if not exist "%DeployPath%\%PortableFile%" goto error 84 | if not exist "%DeployPath%\%BinaryName%.pdb" goto error 85 | md "%FinalDeployPath%" 86 | 87 | xcopy "%DeployPath%\%PortableFile%" "%FinalDeployPath%\" /Y 88 | 89 | echo Version %AppVersionStrFull% is ready! 90 | 91 | cd "%FullExecPath%" 92 | exit /b 93 | 94 | :error 95 | ( 96 | set ErrorCode=%errorlevel% 97 | if !ErrorCode! neq 0 ( 98 | echo Error !ErrorCode! 99 | ) else ( 100 | echo Error 666 101 | set ErrorCode=666 102 | ) 103 | cd "%FullExecPath%" 104 | exit /b !ErrorCode! 105 | ) 106 | -------------------------------------------------------------------------------- /Keygen/build/build.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | FullExecPath=$PWD 3 | pushd `dirname $0` > /dev/null 4 | FullScriptPath=`pwd` 5 | popd > /dev/null 6 | 7 | Error () { 8 | cd $FullExecPath 9 | echo "$1" 10 | exit 1 11 | } 12 | 13 | if [ ! -f "$FullScriptPath/target" ]; then 14 | Error "Build target not found!" 15 | fi 16 | 17 | while IFS='' read -r line || [[ -n "$line" ]]; do 18 | BuildTarget="$line" 19 | done < "$FullScriptPath/target" 20 | 21 | while IFS='' read -r line || [[ -n "$line" ]]; do 22 | set $line 23 | eval $1="$2" 24 | done < "$FullScriptPath/version" 25 | 26 | AppVersionStrFull="$AppVersionStr" 27 | 28 | echo "" 29 | HomePath="$FullScriptPath/.." 30 | if [ "$BuildTarget" == "linux" ]; then 31 | echo "Building version $AppVersionStrFull for Linux 64bit.." 32 | SetupFile="tonkeygen.$AppVersionStrFull.linux.tar.xz" 33 | ProjectPath="$HomePath/../out" 34 | ReleasePath="$ProjectPath/Release" 35 | BinaryName="Keygen" 36 | elif [ "$BuildTarget" == "linux32" ]; then 37 | echo "Building version $AppVersionStrFull for Linux 32bit.." 38 | SetupFile="tonkeygen.$AppVersionStrFull.linux32.tar.xz" 39 | ProjectPath="$HomePath/../out" 40 | ReleasePath="$ProjectPath/Release" 41 | BinaryName="Keygen" 42 | elif [ "$BuildTarget" == "mac" ]; then 43 | echo "Building version $AppVersionStrFull for OS X 10.8+.." 44 | if [ "$AC_USERNAME" == "" ]; then 45 | Error "AC_USERNAME not found!" 46 | fi 47 | SetupFile="tonkeygen.$AppVersionStrFull.mac.dmg" 48 | ProjectPath="$HomePath/../out" 49 | ReleasePath="$ProjectPath/Release" 50 | BinaryName="Keygen" 51 | else 52 | Error "Invalid target!" 53 | fi 54 | 55 | if [ -d "$ReleasePath/deploy/$AppVersionStrMajor/$AppVersionStr" ]; then 56 | Error "Deploy folder for version $AppVersionStr already exists!" 57 | fi 58 | 59 | DeployPath="$ReleasePath/deploy/$AppVersionStrMajor/$AppVersionStrFull" 60 | 61 | if [ "$BuildTarget" == "linux" ] || [ "$BuildTarget" == "linux32" ]; then 62 | BackupPath="/media/psf/backup/tonkeygen/$AppVersionStrMajor/$AppVersionStrFull/t$BuildTarget" 63 | if [ ! -d "/media/psf/backup" ]; then 64 | Error "Backup folder not found!" 65 | fi 66 | 67 | ./configure.sh 68 | 69 | cd $ProjectPath 70 | cmake --build . --config Release --target Keygen -- -j8 71 | cd $ReleasePath 72 | 73 | if [ ! -f "$ReleasePath/$BinaryName" ]; then 74 | Error "$BinaryName not found!" 75 | fi 76 | 77 | # BadCount=`objdump -T $ReleasePath/$BinaryName | grep GLIBC_2\.1[6-9] | wc -l` 78 | # if [ "$BadCount" != "0" ]; then 79 | # Error "Bad GLIBC usages found: $BadCount" 80 | # fi 81 | 82 | # BadCount=`objdump -T $ReleasePath/$BinaryName | grep GLIBC_2\.2[0-9] | wc -l` 83 | # if [ "$BadCount" != "0" ]; then 84 | # Error "Bad GLIBC usages found: $BadCount" 85 | # fi 86 | 87 | # BadCount=`objdump -T $ReleasePath/$BinaryName | grep GCC_4\.[3-9] | wc -l` 88 | # if [ "$BadCount" != "0" ]; then 89 | # Error "Bad GCC usages found: $BadCount" 90 | # fi 91 | 92 | # BadCount=`objdump -T $ReleasePath/$BinaryName | grep GCC_[5-9]\. | wc -l` 93 | # if [ "$BadCount" != "0" ]; then 94 | # Error "Bad GCC usages found: $BadCount" 95 | # fi 96 | 97 | echo "Stripping the executable.." 98 | strip -s "$ReleasePath/$BinaryName" 99 | echo "Done!" 100 | 101 | echo "Removing RPATH.." 102 | chrpath -d "$ReleasePath/$BinaryName" 103 | echo "Done!" 104 | 105 | if [ ! -d "$ReleasePath/deploy" ]; then 106 | mkdir "$ReleasePath/deploy" 107 | fi 108 | 109 | if [ ! -d "$ReleasePath/deploy/$AppVersionStrMajor" ]; then 110 | mkdir "$ReleasePath/deploy/$AppVersionStrMajor" 111 | fi 112 | 113 | echo "Copying $BinaryName to deploy/$AppVersionStrMajor/$AppVersionStrFull.."; 114 | mkdir "$DeployPath" 115 | mkdir "$DeployPath/$BinaryName" 116 | mv "$ReleasePath/$BinaryName" "$DeployPath/$BinaryName/" 117 | cd "$DeployPath" 118 | tar -cJvf "$SetupFile" "$BinaryName/" 119 | 120 | mkdir -p $BackupPath 121 | cp "$SetupFile" "$BackupPath/" 122 | fi 123 | 124 | if [ "$BuildTarget" == "mac" ]; then 125 | BackupPath="$HomePath/../../../Projects/backup/tonkeygen/$AppVersionStrMajor/$AppVersionStrFull" 126 | if [ ! -d "$HomePath/../../../Projects/backup" ]; then 127 | Error "Backup path not found!" 128 | fi 129 | 130 | ./configure.sh 131 | 132 | cd $ProjectPath 133 | cmake --build . --config Release --target Keygen 134 | cd $ReleasePath 135 | 136 | if [ ! -d "$ReleasePath/$BinaryName.app" ]; then 137 | Error "$BinaryName.app not found!" 138 | fi 139 | 140 | if [ ! -d "$ReleasePath/$BinaryName.app.dSYM" ]; then 141 | Error "$BinaryName.app.dSYM not found!" 142 | fi 143 | 144 | echo "Stripping the executable.." 145 | strip "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" 146 | echo "Done!" 147 | 148 | echo "Signing the application.." 149 | codesign --force --deep --timestamp --options runtime --sign "Developer ID Application: John Preston" "$ReleasePath/$BinaryName.app" --entitlements "$HomePath/Resources/mac/Keygen.entitlements" 150 | echo "Done!" 151 | 152 | AppUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" | awk -F " " '{print $2}'` 153 | DsymUUID=`dwarfdump -u "$ReleasePath/$BinaryName.app.dSYM" | awk -F " " '{print $2}'` 154 | if [ "$AppUUID" != "$DsymUUID" ]; then 155 | Error "UUID of binary '$AppUUID' and dSYM '$DsymUUID' differ!" 156 | fi 157 | 158 | if [ ! -f "$ReleasePath/$BinaryName.app/Contents/Resources/Icon.icns" ]; then 159 | Error "Icon.icns not found in Resources!" 160 | fi 161 | 162 | if [ ! -f "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" ]; then 163 | Error "$BinaryName not found in MacOS!" 164 | fi 165 | 166 | if [ ! -d "$ReleasePath/$BinaryName.app/Contents/_CodeSignature" ]; then 167 | Error "$BinaryName signature not found!" 168 | fi 169 | 170 | cd "$ReleasePath" 171 | 172 | cp -f tsetup_template.dmg tsetup.temp.dmg 173 | TempDiskPath=`hdiutil attach -nobrowse -noautoopenrw -readwrite tsetup.temp.dmg | awk -F "\t" 'END {print $3}'` 174 | cp -R "./$BinaryName.app" "$TempDiskPath/" 175 | bless --folder "$TempDiskPath/" --openfolder "$TempDiskPath/" 176 | hdiutil detach "$TempDiskPath" 177 | hdiutil convert tsetup.temp.dmg -format UDZO -imagekey zlib-level=9 -ov -o "$SetupFile" 178 | rm tsetup.temp.dmg 179 | 180 | echo "Beginning notarization process." 181 | set +e 182 | xcrun altool --notarize-app --primary-bundle-id "org.ton.TonKeyGenerator" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" --file "$SetupFile" > request_uuid.txt 183 | set -e 184 | while IFS='' read -r line || [[ -n "$line" ]]; do 185 | Prefix=$(echo $line | cut -d' ' -f 1) 186 | Value=$(echo $line | cut -d' ' -f 3) 187 | if [ "$Prefix" == "RequestUUID" ]; then 188 | RequestUUID=$Value 189 | fi 190 | done < "request_uuid.txt" 191 | if [ "$RequestUUID" == "" ]; then 192 | cat request_uuid.txt 193 | Error "Could not extract Request UUID." 194 | fi 195 | echo "Request UUID: $RequestUUID" 196 | rm request_uuid.txt 197 | 198 | RequestStatus= 199 | LogFile= 200 | while [[ "$RequestStatus" == "" ]]; do 201 | sleep 5 202 | xcrun altool --notarization-info "$RequestUUID" --username "$AC_USERNAME" --password "@keychain:AC_PASSWORD" > request_result.txt 203 | while IFS='' read -r line || [[ -n "$line" ]]; do 204 | Prefix=$(echo $line | cut -d' ' -f 1) 205 | Value=$(echo $line | cut -d' ' -f 2) 206 | if [ "$Prefix" == "LogFileURL:" ]; then 207 | LogFile=$Value 208 | fi 209 | if [ "$Prefix" == "Status:" ]; then 210 | if [ "$Value" == "in" ]; then 211 | echo "In progress..." 212 | else 213 | RequestStatus=$Value 214 | echo "Status: $RequestStatus" 215 | fi 216 | fi 217 | done < "request_result.txt" 218 | done 219 | if [ "$RequestStatus" != "success" ]; then 220 | echo "Notarization problems, response:" 221 | cat request_result.txt 222 | if [ "$LogFile" != "" ]; then 223 | echo "Requesting log..." 224 | curl $LogFile 225 | fi 226 | Error "Notarization FAILED." 227 | fi 228 | rm request_result.txt 229 | 230 | if [ "$LogFile" != "" ]; then 231 | echo "Requesting log..." 232 | curl $LogFile > request_log.txt 233 | fi 234 | 235 | xcrun stapler staple "$ReleasePath/$BinaryName.app" 236 | xcrun stapler staple "$ReleasePath/$SetupFile" 237 | 238 | if [ ! -d "$ReleasePath/deploy" ]; then 239 | mkdir "$ReleasePath/deploy" 240 | fi 241 | 242 | if [ ! -d "$ReleasePath/deploy/$AppVersionStrMajor" ]; then 243 | mkdir "$ReleasePath/deploy/$AppVersionStrMajor" 244 | fi 245 | 246 | if [ "$BuildTarget" == "mac" ]; then 247 | echo "Copying $BinaryName.app to deploy/$AppVersionStrMajor/$AppVersionStr.."; 248 | mkdir "$DeployPath" 249 | mkdir "$DeployPath/$BinaryName" 250 | cp -r "$ReleasePath/$BinaryName.app" "$DeployPath/$BinaryName/" 251 | mv "$ReleasePath/$BinaryName.app.dSYM" "$DeployPath/" 252 | rm "$ReleasePath/$BinaryName.app/Contents/MacOS/$BinaryName" 253 | rm "$ReleasePath/$BinaryName.app/Contents/Info.plist" 254 | rm -rf "$ReleasePath/$BinaryName.app/Contents/_CodeSignature" 255 | mv "$ReleasePath/$SetupFile" "$DeployPath/" 256 | 257 | mkdir -p "$BackupPath/tmac" 258 | cp "$DeployPath/$SetupFile" "$BackupPath/tmac/" 259 | fi 260 | fi 261 | 262 | echo "Version $AppVersionStrFull is ready!"; 263 | echo -en "\007"; 264 | sleep 1; 265 | echo -en "\007"; 266 | sleep 1; 267 | echo -en "\007"; 268 | 269 | if [ "$BuildTarget" == "mac" ]; then 270 | if [ -f "$ReleasePath/request_log.txt" ]; then 271 | DisplayingLog= 272 | while IFS='' read -r line || [[ -n "$line" ]]; do 273 | if [ "$DisplayingLog" == "1" ]; then 274 | echo $line 275 | else 276 | Prefix=$(echo $line | cut -d' ' -f 1) 277 | Value=$(echo $line | cut -d' ' -f 2) 278 | if [ "$Prefix" == '"issues":' ]; then 279 | if [ "$Value" != "null" ]; then 280 | echo "NB! Notarization log issues:" 281 | echo $line 282 | DisplayingLog=1 283 | else 284 | DisplayingLog=0 285 | fi 286 | fi 287 | fi 288 | done < "$ReleasePath/request_log.txt" 289 | if [ "$DisplayingLog" != "0" ] && [ "$DisplayingLog" != "1" ]; then 290 | echo "NB! Notarization issues not found:" 291 | cat "$ReleasePath/request_log.txt" 292 | else 293 | rm "$ReleasePath/request_log.txt" 294 | fi 295 | else 296 | echo "NB! Notarization log not found :(" 297 | fi 298 | fi 299 | -------------------------------------------------------------------------------- /Keygen/build/set_version.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | set "FullScriptPath=%~dp0" 4 | 5 | python %FullScriptPath%set_version.py %1 6 | if %errorlevel% neq 0 goto error 7 | 8 | exit /b 9 | 10 | :error 11 | echo FAILED 12 | exit /b 1 13 | -------------------------------------------------------------------------------- /Keygen/build/set_version.py: -------------------------------------------------------------------------------- 1 | # This file is part of TON Key Generator, 2 | # a desktop application for the TON Blockchain project. 3 | # 4 | # For license and copyright information please follow this link: 5 | # https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | 7 | import sys, os, re, subprocess 8 | 9 | def finish(code): 10 | global executePath 11 | os.chdir(executePath) 12 | sys.exit(code) 13 | 14 | if sys.platform == 'win32' and not 'COMSPEC' in os.environ: 15 | print('[ERROR] COMSPEC environment variable is not set.') 16 | finish(1) 17 | 18 | executePath = os.getcwd() 19 | scriptPath = os.path.dirname(os.path.realpath(__file__)) 20 | 21 | inputVersion = '' 22 | versionOriginal = '' 23 | versionMajor = '' 24 | versionMinor = '' 25 | versionPatch = '' 26 | for arg in sys.argv: 27 | match = re.match(r'^\s*(\d+)\.(\d+)(\.(\d+))?\s*$', arg) 28 | if match: 29 | inputVersion = arg 30 | versionOriginal = inputVersion 31 | versionMajor = match.group(1) 32 | versionMinor = match.group(2) 33 | versionPatch = match.group(4) if match.group(4) else '0' 34 | 35 | if not len(versionMajor): 36 | print("Wrong version parameter") 37 | finish(1) 38 | 39 | def checkVersionPart(part): 40 | cleared = int(part) % 1000 if len(part) > 0 else 0 41 | if str(cleared) != part: 42 | print("Bad version part: " + part) 43 | finish(1) 44 | 45 | checkVersionPart(versionMajor) 46 | checkVersionPart(versionMinor) 47 | checkVersionPart(versionPatch) 48 | 49 | versionFull = str(int(versionMajor) * 1000000 + int(versionMinor) * 1000 + int(versionPatch)) 50 | versionStr = versionMajor + '.' + versionMinor + '.' + versionPatch 51 | versionStrSmall = versionStr if versionPatch != '0' else versionMajor + '.' + versionMinor 52 | 53 | print('Setting version: ' + versionStr + ' stable') 54 | 55 | def replaceInFile(path, replacements): 56 | content = '' 57 | foundReplacements = {} 58 | updated = False 59 | with open(path, 'r') as f: 60 | for line in f: 61 | for replacement in replacements: 62 | if re.search(replacement[0], line): 63 | changed = re.sub(replacement[0], replacement[1], line) 64 | if changed != line: 65 | line = changed 66 | updated = True 67 | foundReplacements[replacement[0]] = True 68 | content = content + line 69 | for replacement in replacements: 70 | if not replacement[0] in foundReplacements: 71 | print('Could not find "' + replacement[0] + '" in "' + path + '".') 72 | finish(1) 73 | if updated: 74 | with open(path, 'w') as f: 75 | f.write(content) 76 | 77 | print('Patching build/version...') 78 | replaceInFile(scriptPath + '/version', [ 79 | [ r'(AppVersion\s+)\d+', r'\g<1>' + versionFull ], 80 | [ r'(AppVersionStrMajor\s+)\d[\d\.]*', r'\g<1>' + versionMajor + '.' + versionMinor ], 81 | [ r'(AppVersionStrSmall\s+)\d[\d\.]*', r'\g<1>' + versionStrSmall ], 82 | [ r'(AppVersionStr\s+)\d[\d\.]*', r'\g<1>' + versionStr ], 83 | [ r'(AppVersionOriginal\s+)\d[\d\.beta]*', r'\g<1>' + versionOriginal ], 84 | ]) 85 | 86 | parts = [versionMajor, versionMinor, versionPatch, '0'] 87 | withcomma = ','.join(parts) 88 | withdot = '.'.join(parts) 89 | rcReplaces = [ 90 | [ r'(FILEVERSION\s+)\d+,\d+,\d+,\d+', r'\g<1>' + withcomma ], 91 | [ r'(PRODUCTVERSION\s+)\d+,\d+,\d+,\d+', r'\g<1>' + withcomma ], 92 | [ r'("FileVersion",\s+)"\d+\.\d+\.\d+\.\d+"', r'\g<1>"' + withdot + '"' ], 93 | [ r'("ProductVersion",\s+)"\d+\.\d+\.\d+\.\d+"', r'\g<1>"' + withdot + '"' ], 94 | ] 95 | 96 | print('Patching Keygen.rc...') 97 | replaceInFile(scriptPath + '/../Resources/win/Keygen.rc', rcReplaces) 98 | -------------------------------------------------------------------------------- /Keygen/build/set_version.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | pushd `dirname $0` > /dev/null 4 | FullScriptPath=`pwd` 5 | popd > /dev/null 6 | 7 | python $FullScriptPath/set_version.py $1 8 | 9 | exit 10 | -------------------------------------------------------------------------------- /Keygen/build/version: -------------------------------------------------------------------------------- 1 | AppVersion 1001000 2 | AppVersionStrMajor 1.1 3 | AppVersionStrSmall 1.1 4 | AppVersionStr 1.1.0 5 | AppVersionOriginal 1.1 6 | -------------------------------------------------------------------------------- /Keygen/configure.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | 3 | setlocal enabledelayedexpansion 4 | set "FullScriptPath=%~dp0" 5 | 6 | python %FullScriptPath%configure.py %* 7 | if %errorlevel% neq 0 goto error 8 | 9 | exit /b 10 | 11 | :error 12 | echo FAILED 13 | exit /b 1 14 | -------------------------------------------------------------------------------- /Keygen/configure.py: -------------------------------------------------------------------------------- 1 | # This file is part of TON Key Generator, 2 | # a desktop application for the TON Blockchain project. 3 | # 4 | # For license and copyright information please follow this link: 5 | # https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 6 | 7 | import sys, os, re 8 | 9 | sys.dont_write_bytecode = True 10 | scriptPath = os.path.dirname(os.path.realpath(__file__)) 11 | sys.path.append(scriptPath + '/../cmake') 12 | import run_cmake 13 | 14 | executePath = os.getcwd() 15 | def finish(code): 16 | global executePath 17 | os.chdir(executePath) 18 | sys.exit(code) 19 | 20 | def error(message): 21 | print('[ERROR] ' + message) 22 | finish(1) 23 | 24 | if sys.platform == 'win32' and not 'COMSPEC' in os.environ: 25 | error('COMSPEC environment variable is not set.') 26 | 27 | executePath = os.getcwd() 28 | scriptPath = os.path.dirname(os.path.realpath(__file__)) 29 | scriptName = os.path.basename(scriptPath) 30 | 31 | arguments = sys.argv[1:] 32 | 33 | officialTarget = '' 34 | officialTargetFile = scriptPath + '/build/target' 35 | if os.path.isfile(officialTargetFile): 36 | with open(officialTargetFile, 'r') as f: 37 | for line in f: 38 | officialTarget = line.strip() 39 | 40 | if officialTarget != '': 41 | finish(run_cmake.run(scriptName, arguments)) 42 | elif 'linux' in sys.platform: 43 | debugCode = run_cmake.run(scriptName, arguments, "Debug") 44 | finish(debugCode if debugCode else run_cmake.run(scriptName, arguments, "Release")) 45 | else: 46 | finish(run_cmake.run(scriptName, arguments)) 47 | -------------------------------------------------------------------------------- /Keygen/configure.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | pushd `dirname $0` > /dev/null 5 | FullScriptPath=`pwd` 6 | popd > /dev/null 7 | 8 | python $FullScriptPath/configure.py "$@" 9 | 10 | exit 11 | -------------------------------------------------------------------------------- /Keygen/create.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | set "FullScriptPath=%~dp0" 4 | set "FullExecPath=%cd%" 5 | 6 | set "Command=%1" 7 | if "%Command%" == "header" ( 8 | call :write_header %2 9 | exit /b %errorlevel% 10 | ) else if "%Command%" == "source" ( 11 | call :write_source %2 12 | exit /b %errorlevel% 13 | ) else if "%Command%" == "" ( 14 | echo This is an utility for fast blank module creation. 15 | echo Please provide module path. 16 | exit /b 17 | ) 18 | 19 | call :write_module %Command% 20 | exit /b %errorlevel% 21 | 22 | :write_module 23 | ( 24 | set "CommandPath=%1" 25 | set "CommandPathUnix=!CommandPath:\=/!" 26 | if "!CommandPathUnix!" == "" ( 27 | echo Provide module path. 28 | exit /b 1 29 | ) 30 | echo Generating module !CommandPathUnix!.. 31 | call create.bat header !CommandPathUnix! 32 | call create.bat source !CommandPathUnix! 33 | exit /b 34 | ) 35 | 36 | :write_header 37 | ( 38 | set "CommandPath=%1" 39 | set "CommandPathUnix=!CommandPath:\=/!" 40 | set "CommandPathWin=!CommandPath:/=\!" 41 | 42 | if "!CommandPathUnix!" == "" ( 43 | echo Provide header path. 44 | exit /b 1 45 | ) else if exist "SourceFiles\!CommandPathWin!.h" ( 46 | echo This header already exists. 47 | exit /b 1 48 | ) 49 | echo Generating header !CommandPathUnix!.h.. 50 | mkdir "SourceFiles\!CommandPathWin!.h" 51 | rmdir "SourceFiles\!CommandPathWin!.h" 52 | 53 | call :write_comment !CommandPathWin!.h 54 | set "header1=#pragma once" 55 | ( 56 | echo !header1! 57 | echo. 58 | )>> "SourceFiles\!CommandPathWin!.h" 59 | exit /b 60 | ) 61 | 62 | :write_source 63 | ( 64 | set "CommandPath=%1" 65 | set "CommandPathUnix=!CommandPath:\=/!" 66 | set "CommandPathWin=!CommandPath:/=\!" 67 | 68 | if "!CommandPathUnix!" == "" ( 69 | echo Provide source path. 70 | exit /b 1 71 | ) else if exist "SourceFiles\!CommandPathWin!.cpp" ( 72 | echo This source already exists. 73 | exit /b 1 74 | ) 75 | echo Generating source !CommandPathUnix!.cpp.. 76 | mkdir "SourceFiles\!CommandPathWin!.cpp" 77 | rmdir "SourceFiles\!CommandPathWin!.cpp" 78 | 79 | call :write_comment !CommandPathWin!.cpp 80 | set "quote=""" 81 | set "quote=!quote:~0,1!" 82 | set "source1=#include !quote!!CommandPathUnix!.h!quote!" 83 | ( 84 | echo !source1! 85 | echo. 86 | )>> "SourceFiles\!CommandPathWin!.cpp" 87 | exit /b 88 | ) 89 | 90 | :write_comment 91 | ( 92 | set "Path=%1" 93 | ( 94 | echo // This file is part of TON Key Generator, 95 | echo // a desktop application for the TON Blockchain project. 96 | echo // 97 | echo // For license and copyright information please follow this link: 98 | echo // https://github.com/ton-blockchain/tonkeygen/blob/master/LEGAL 99 | echo // 100 | )> "SourceFiles\!Path!" 101 | exit /b 102 | ) 103 | -------------------------------------------------------------------------------- /LEGAL: -------------------------------------------------------------------------------- 1 | This file is part of TON Key Generator, 2 | a desktop application for the TON Blockchain project. 3 | 4 | Copyright (c) 2014-2019 John Preston 5 | 6 | TON Key Generator is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | It is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | In addition, as a special exception, the copyright holders give permission 17 | to link the code of portions of this program with the OpenSSL library. 18 | 19 | Full license: https://github.com/ton-blockchain/tonkeygen/blob/master/LICENSE 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The source code is published under GPLv3 with OpenSSL exception, the license is available [here][license]. 2 | 3 | ## Build instructions 4 | 5 | * [Visual Studio 2019][msvc] 6 | * [Xcode 10][xcode] 7 | * [GYP/CMake on GNU/Linux][cmake] 8 | 9 | [//]: # (LINKS) 10 | [license]: LICENSE 11 | [msvc]: docs/building-msvc.md 12 | [xcode]: docs/building-xcode.md 13 | [cmake]: docs/building-cmake.md 14 | 15 | -------------------------------------------------------------------------------- /docs/building-cmake.md: -------------------------------------------------------------------------------- 1 | ## Build instructions for CMake under Ubuntu 14.04 2 | 3 | ### Prepare folder 4 | 5 | Choose an empty folder for the future build, for example **/home/user/Projects**. It will be named ***BuildPath*** in the rest of this document. 6 | 7 | ### Install software and required packages 8 | 9 | You will need GCC 8 installed. To install them and all the required dependencies run 10 | 11 | sudo apt-get install software-properties-common -y && \ 12 | sudo apt-get install git libexif-dev liblzma-dev libz-dev libssl-dev \ 13 | libgtk2.0-dev libice-dev libsm-dev libicu-dev libdrm-dev dh-autoreconf \ 14 | autoconf automake build-essential libxml2-dev libass-dev libfreetype6-dev \ 15 | libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev \ 16 | libvorbis-dev libenchant-dev libxcb1-dev libxcb-image0-dev libxcb-shm0-dev \ 17 | libxcb-xfixes0-dev libxcb-keysyms1-dev libxcb-icccm4-dev libatspi2.0-dev \ 18 | libxcb-render-util0-dev libxcb-util0-dev libxcb-xkb-dev libxrender-dev \ 19 | libasound-dev libpulse-dev libxcb-sync0-dev libxcb-randr0-dev libegl1-mesa-dev \ 20 | libx11-xcb-dev libffi-dev libncurses5-dev pkg-config texi2html bison yasm \ 21 | zlib1g-dev xutils-dev python-xcbgen chrpath gperf -y --force-yes && \ 22 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ 23 | sudo apt-get update && \ 24 | sudo apt-get install gcc-8 g++-8 -y && \ 25 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 60 && \ 26 | sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 60 && \ 27 | sudo update-alternatives --config gcc && \ 28 | sudo add-apt-repository --remove ppa:ubuntu-toolchain-r/test -y 29 | 30 | You can set the multithreaded make parameter by running 31 | 32 | MAKE_THREADS_CNT=-j8 33 | 34 | ### Clone source code and prepare libraries and cmake 35 | 36 | Go to ***BuildPath*** and run 37 | 38 | git clone --recursive https://github.com/ton-blockchain/tonkeygen.git 39 | 40 | mkdir Libraries 41 | cd Libraries 42 | 43 | git clone https://github.com/Kitware/CMake cmake 44 | cd cmake 45 | git checkout v3.16.0 46 | ./bootstrap 47 | make $MAKE_THREADS_CNT 48 | sudo make install 49 | cd .. 50 | 51 | git clone https://github.com/desktop-app/patches.git 52 | cd patches 53 | git checkout 10aeaf6 54 | cd ../ 55 | git clone --branch 0.10.0 https://github.com/ericniebler/range-v3 56 | 57 | git clone https://github.com/openssl/openssl openssl_1_1_1 58 | cd openssl_1_1_1 59 | git checkout OpenSSL_1_1_1-stable 60 | ./config --prefix=/usr/local/desktop-app/openssl-1.1.1 61 | make $MAKE_THREADS_CNT 62 | sudo make install 63 | cd .. 64 | 65 | git clone https://github.com/xkbcommon/libxkbcommon.git 66 | cd libxkbcommon 67 | git checkout xkbcommon-0.8.4 68 | ./autogen.sh --disable-x11 69 | make $MAKE_THREADS_CNT 70 | sudo make install 71 | cd .. 72 | 73 | git clone git://code.qt.io/qt/qt5.git qt_5_12_8 74 | cd qt_5_12_8 75 | perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg 76 | git checkout v5.12.8 77 | git submodule update qtbase 78 | git submodule update qtwayland 79 | git submodule update qtimageformats 80 | git submodule update qtsvg 81 | cd qtbase 82 | git apply ../../patches/qtbase_5_12_8.diff 83 | cd src/plugins/platforminputcontexts 84 | git clone https://github.com/desktop-app/fcitx.git 85 | git clone https://github.com/desktop-app/hime.git 86 | git clone https://github.com/desktop-app/nimf.git 87 | cd ../../../.. 88 | 89 | OPENSSL_DIR=/usr/local/desktop-app/openssl-1.1.1 90 | ./configure -prefix "/usr/local/desktop-app/Qt-5.12.8" \ 91 | -release \ 92 | -force-debug-info \ 93 | -opensource \ 94 | -confirm-license \ 95 | -qt-zlib \ 96 | -qt-libpng \ 97 | -qt-libjpeg \ 98 | -qt-harfbuzz \ 99 | -qt-pcre \ 100 | -qt-xcb \ 101 | -system-freetype \ 102 | -fontconfig \ 103 | -no-gtk \ 104 | -static \ 105 | -dbus-runtime \ 106 | -openssl-linked \ 107 | -I "$OPENSSL_DIR/include" OPENSSL_LIBS="$OPENSSL_DIR/lib/libssl.a $OPENSSL_DIR/lib/libcrypto.a -ldl -lpthread" \ 108 | -nomake examples \ 109 | -nomake tests 110 | 111 | make $MAKE_THREADS_CNT 112 | sudo make install 113 | cd .. 114 | 115 | git clone https://github.com/ton-blockchain/ton.git 116 | cd ton 117 | git checkout eecf05ca 118 | git submodule init 119 | git submodule update third-party/crc32c 120 | mkdir build-debug 121 | cd build-debug 122 | cmake -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=/usr/local/desktop-app/openssl-1.1.1/include -DOPENSSL_CRYPTO_LIBRARY=/usr/local/desktop-app/openssl-1.1.1/lib/libcrypto.a -DTON_ARCH=`uname -m | sed --expression='s/_/-/g'` .. 123 | make $MAKE_THREADS_CNT tonlib 124 | cd .. 125 | mkdir build 126 | cd build 127 | cmake -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=/usr/local/desktop-app/openssl-1.1.1/include -DOPENSSL_CRYPTO_LIBRARY=/usr/local/desktop-app/openssl-1.1.1/lib/libcrypto.a -DTON_ARCH=`uname -m | sed --expression='s/_/-/g'` -DCMAKE_BUILD_TYPE=Release .. 128 | make $MAKE_THREADS_CNT tonlib 129 | cd ../.. 130 | 131 | ### Building the project 132 | 133 | Go to ***BuildPath*/tonkeygen/Keygen** and run 134 | 135 | ./configure.sh -D DESKTOP_APP_USE_PACKAGED=OFF 136 | 137 | To make Debug version go to ***BuildPath*/tonkeygen/out/Debug** and run 138 | 139 | make $MAKE_THREADS_CNT 140 | 141 | To make Release version go to ***BuildPath*/tonkeygen/out/Release** and run 142 | 143 | make $MAKE_THREADS_CNT 144 | 145 | You can debug your builds from Qt Creator, just open ***BuildPath*/tonkeygen/CMakeLists.txt**, configure to a separate directory with correct options and launch with debug. 146 | -------------------------------------------------------------------------------- /docs/building-msvc.md: -------------------------------------------------------------------------------- 1 | # Build instructions for Visual Studio 2019 2 | 3 | - [Prepare folder](#prepare-folder) 4 | - [Install third party software](#install-third-party-software) 5 | - [Clone source code and prepare libraries](#clone-source-code-and-prepare-libraries) 6 | - [Build the project](#build-the-project) 7 | 8 | ## Prepare folder 9 | 10 | Choose an empty folder for the future build, for example **D:\\Projects**. It will be named ***BuildPath*** in the rest of this document. Create two folders there, ***BuildPath*\\ThirdParty** and ***BuildPath*\\Libraries**. 11 | 12 | All commands (if not stated otherwise) will be launched from **x86 Native Tools Command Prompt for VS 2019.bat** (should be in **Start Menu > Visual Studio 2019** menu folder). Pay attention not to use any other Command Prompt. 13 | 14 | ## Install third party software 15 | 16 | * Download **Strawberry Perl** installer from [http://strawberryperl.com/](http://strawberryperl.com/) and install to ***BuildPath*\\ThirdParty\\Strawberry** 17 | * Download **NASM** installer from [http://www.nasm.us](http://www.nasm.us) and install to ***BuildPath*\\ThirdParty\\NASM** 18 | * Download **Yasm** executable from [http://yasm.tortall.net/Download.html](http://yasm.tortall.net/Download.html), rename to *yasm.exe* and put to ***BuildPath*\\ThirdParty\\yasm** 19 | * Download **jom** archive from [http://download.qt.io/official_releases/jom/jom.zip](http://download.qt.io/official_releases/jom/jom.zip) and unpack to ***BuildPath*\\ThirdParty\\jom** 20 | * Download **Python 2.7** installer from [https://www.python.org/downloads/](https://www.python.org/downloads/) and install to ***BuildPath*\\ThirdParty\\Python27** 21 | * Download **CMake** installer from [https://cmake.org/download/](https://cmake.org/download/) and install to ***BuildPath*\\ThirdParty\\cmake** 22 | 23 | ## Clone source code and prepare libraries 24 | 25 | Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath*** and run 26 | 27 | SET PATH=%cd%\ThirdParty\Perl\bin;%cd%\ThirdParty\Python27;%cd%\ThirdParty\NASM;%cd%\ThirdParty\jom;%cd%\ThirdParty\cmake\bin;%cd%\ThirdParty\yasm;%PATH% 28 | 29 | git clone --recursive https://github.com/ton-blockchain/tonkeygen.git 30 | 31 | mkdir Libraries 32 | cd Libraries 33 | 34 | SET LibrariesPath=%cd% 35 | 36 | git clone https://github.com/desktop-app/patches.git 37 | cd patches 38 | git checkout 10aeaf6 39 | cd .. 40 | git clone --branch 0.10.0 https://github.com/ericniebler/range-v3 range-v3 41 | 42 | git clone https://github.com/openssl/openssl.git openssl_1_1_1 43 | cd openssl_1_1_1 44 | git checkout OpenSSL_1_1_1-stable 45 | perl Configure no-shared debug-VC-WIN32 46 | nmake 47 | mkdir out32.dbg 48 | move libcrypto.lib out32.dbg 49 | move libssl.lib out32.dbg 50 | move ossl_static.pdb out32.dbg\ossl_static 51 | nmake clean 52 | move out32.dbg\ossl_static out32.dbg\ossl_static.pdb 53 | perl Configure no-shared VC-WIN32 54 | nmake 55 | mkdir out32 56 | move libcrypto.lib out32 57 | move libssl.lib out32 58 | move ossl_static.pdb out32 59 | cd .. 60 | 61 | git clone https://github.com/desktop-app/zlib.git 62 | cd zlib\contrib\vstudio\vc14 63 | msbuild zlibstat.vcxproj /property:Configuration=Debug 64 | msbuild zlibstat.vcxproj /property:Configuration=ReleaseWithoutAsm 65 | cd ..\..\..\.. 66 | 67 | git clone git://code.qt.io/qt/qt5.git qt_5_12_8 68 | cd qt_5_12_8 69 | perl init-repository --module-subset=qtbase,qtimageformats 70 | git checkout v5.12.8 71 | git submodule update qtbase 72 | git submodule update qtimageformats 73 | cd qtbase 74 | git apply ../../patches/qtbase_5_12_8.diff 75 | cd .. 76 | 77 | configure -prefix "%LibrariesPath%\Qt-5.12.8" -debug-and-release -force-debug-info -opensource -confirm-license -static -static-runtime -I "%LibrariesPath%\openssl_1_1_1\include" -no-opengl -openssl-linked OPENSSL_LIBS_DEBUG="%LibrariesPath%\openssl_1_1_1\out32.dbg\libssl.lib %LibrariesPath%\openssl_1_1_1\out32.dbg\libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib" OPENSSL_LIBS_RELEASE="%LibrariesPath%\openssl_1_1_1\out32\libssl.lib %LibrariesPath%\openssl_1_1_1\out32\libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib" -mp -nomake examples -nomake tests -platform win32-msvc 78 | 79 | jom -j4 80 | jom -j4 install 81 | cd .. 82 | 83 | git clone https://github.com/ton-blockchain/ton.git 84 | cd ton 85 | git checkout eecf05ca 86 | git submodule init 87 | git submodule update third-party/crc32c 88 | mkdir build-debug 89 | cd build-debug 90 | cmake -A Win32 -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ARCH= -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=%LibrariesPath%\openssl_1_1_1\include -DOPENSSL_CRYPTO_LIBRARY=%LibrariesPath%\openssl_1_1_1\out32.dbg\libcrypto.lib -DZLIB_FOUND=1 -DZLIB_INCLUDE_DIR=%LibrariesPath%\zlib -DZLIB_LIBRARY=%LibrariesPath%\zlib\contrib\vstudio\vc14\x86\ZlibStatDebug\zlibstat.lib -DCMAKE_CXX_FLAGS_DEBUG="/DZLIB_WINAPI /DNDEBUG /MTd /Zi /Od /Ob0" -DCMAKE_C_FLAGS_DEBUG="/DNDEBUG /MTd /Zi /Od /Ob0" -DCMAKE_EXE_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib" .. 91 | cmake --build . --target tonlib --config Debug 92 | cd .. 93 | mkdir build 94 | cd build 95 | cmake -A Win32 -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ARCH= -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=%LibrariesPath%\openssl_1_1_1\include -DOPENSSL_CRYPTO_LIBRARY=%LibrariesPath%\openssl_1_1_1\out32\libcrypto.lib -DZLIB_FOUND=1 -DZLIB_INCLUDE_DIR=%LibrariesPath%\zlib -DZLIB_LIBRARY=%LibrariesPath%\zlib\contrib\vstudio\vc14\x86\ZlibStatReleaseWithoutAsm\zlibstat.lib -DCMAKE_CXX_FLAGS_RELEASE="/DZLIB_WINAPI /MT /Ob2" -DCMAKE_C_FLAGS_RELEASE="/MT /Ob2" -DCMAKE_EXE_LINKER_FLAGS="/SAFESEH:NO Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib" .. 96 | cmake --build . --target tonlib --config Release 97 | cd ../.. 98 | 99 | ## Build the project 100 | 101 | Go to ***BuildPath*\\tonkeygen\\Keygen** and run 102 | 103 | configure.bat -D DESKTOP_APP_USE_PACKAGED=OFF 104 | 105 | * Open ***BuildPath*\\tonkeygen\\out\\Keygen.sln** in Visual Studio 2019 106 | * Select Keygen project and press Build > Build Keygen (Debug and Release configurations) 107 | * The result Keygen.exe will be located in ***BuildPath*\\tonkeygen\\out\\Debug** (and **Release**) 108 | -------------------------------------------------------------------------------- /docs/building-xcode.md: -------------------------------------------------------------------------------- 1 | ## Build instructions for Xcode 10.1 2 | 3 | ### Prepare folder 4 | 5 | Choose a folder for the future build, for example **/Users/user/Projects**. It will be named ***BuildPath*** in the rest of this document. All commands will be launched from Terminal. 6 | 7 | ### Clone source code and prepare libraries 8 | 9 | Go to ***BuildPath*** and run 10 | 11 | MAKE_THREADS_CNT=-j4 12 | MACOSX_DEPLOYMENT_TARGET=10.8 13 | 14 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 15 | brew install automake cmake fdk-aac git lame libass libtool libvorbis libvpx ninja opus sdl shtool texi2html theora wget x264 xvid yasm pkg-config 16 | 17 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer 18 | 19 | git clone --recursive https://github.com/ton-blockchain/tonkeygen.git 20 | 21 | mkdir -p Libraries/macos 22 | cd Libraries/macos 23 | LibrariesPath=`pwd` 24 | 25 | git clone https://github.com/desktop-app/patches.git 26 | cd patches 27 | git checkout 10aeaf6 28 | cd .. 29 | git clone --branch 0.10.0 https://github.com/ericniebler/range-v3 30 | 31 | git clone https://github.com/desktop-app/zlib.git 32 | cd zlib 33 | CFLAGS="-mmacosx-version-min=10.12 -Werror=unguarded-availability-new" LDFLAGS="-mmacosx-version-min=10.12" ./configure --prefix=/usr/local/macos 34 | make $MAKE_THREADS_CNT 35 | sudo make install 36 | cd .. 37 | 38 | git clone https://github.com/openssl/openssl openssl_1_1_1 39 | cd openssl_1_1_1 40 | git checkout OpenSSL_1_1_1-stable 41 | ./Configure --prefix=/usr/local/macos darwin64-x86_64-cc -static -mmacosx-version-min=10.12 42 | make build_libs $MAKE_THREADS_CNT 43 | cd .. 44 | 45 | git clone git://code.qt.io/qt/qt5.git qt5_12_8 46 | cd qt5_12_8 47 | perl init-repository --module-subset=qtbase,qtimageformats 48 | git checkout v5.12.8 49 | git submodule update qtbase 50 | git submodule update qtimageformats 51 | cd qtbase 52 | git apply ../../patches/qtbase_5_12_8.diff 53 | cd .. 54 | 55 | ./configure -prefix "/usr/local/desktop-app/Qt-5.12.8" \ 56 | -debug-and-release \ 57 | -force-debug-info \ 58 | -opensource \ 59 | -confirm-license \ 60 | -static \ 61 | -opengl desktop \ 62 | -no-openssl \ 63 | -securetransport \ 64 | -nomake examples \ 65 | -nomake tests \ 66 | -platform macx-clang 67 | 68 | make $MAKE_THREADS_CNT 69 | sudo make install 70 | cd .. 71 | 72 | LibrariesPath=`pwd` 73 | 74 | git clone https://github.com/ton-blockchain/ton.git 75 | cd ton 76 | git checkout eecf05ca 77 | git submodule init 78 | git submodule update third-party/crc32c 79 | mkdir build-debug 80 | cd build-debug 81 | cmake -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ARCH= -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$LibrariesPath/openssl_1_1_1/include -DOPENSSL_CRYPTO_LIBRARY=$LibrariesPath/openssl_1_1_1/libcrypto.a -DZLIB_FOUND=1 -DZLIB_INCLUDE_DIR=$LibrariesPath/zlib -DZLIB_LIBRARY=/usr/local/macos/lib/libz.a -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.12 -DCMAKE_CXX_FLAGS="-stdlib=libc++" .. 82 | make $MAKE_THREADS_CNT tonlib 83 | cd .. 84 | mkdir build 85 | cd build 86 | cmake -DTON_USE_ROCKSDB=OFF -DTON_USE_ABSEIL=OFF -DTON_ARCH= -DTON_ONLY_TONLIB=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$LibrariesPath/openssl_1_1_1/include -DOPENSSL_CRYPTO_LIBRARY=$LibrariesPath/openssl_1_1_1/libcrypto.a -DZLIB_FOUND=1 -DZLIB_INCLUDE_DIR=$LibrariesPath/zlib -DZLIB_LIBRARY=/usr/local/macos/lib/libz.a -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.12 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release .. 87 | make $MAKE_THREADS_CNT tonlib 88 | cd ../.. 89 | 90 | ### Building the project 91 | 92 | Go to ***BuildPath*/tonkeygen/Keygen** and run 93 | 94 | ./configure.sh -D DESKTOP_APP_USE_PACKAGED=OFF 95 | 96 | Then launch Xcode, open ***BuildPath*/tonkeygen/out/Keygen.xcodeproj** and build for Debug / Release. 97 | --------------------------------------------------------------------------------