diff --git a/src/app/modules/startup/controller.nim b/src/app/modules/startup/controller.nim index 1a0ae44e0bc..bf44e2297ea 100644 --- a/src/app/modules/startup/controller.nim +++ b/src/app/modules/startup/controller.nim @@ -222,6 +222,7 @@ proc storePasswordToKeychain(self: Controller) = self.keychainService.storeData(account.name, data) proc storeIdentityImage*(self: Controller) = + echo "storeIdentityImage >>>>>>>>>>>> ",self.tmpProfileImageDetails.url if self.tmpProfileImageDetails.url.len == 0: return let account = self.accountsService.getLoggedInAccount() @@ -392,4 +393,4 @@ proc buildSeedPhrasesFromIndexes*(self: Controller, seedPhraseIndexes: seq[int]) self.setSeedPhrase(sp.join(" ")) proc generateRandomPUK*(self: Controller): string = - return self.keycardService.generateRandomPUK() \ No newline at end of file + return self.keycardService.generateRandomPUK() diff --git a/src/app/modules/startup/module.nim b/src/app/modules/startup/module.nim index 3aa337a8c5f..a926a5a159b 100644 --- a/src/app/modules/startup/module.nim +++ b/src/app/modules/startup/module.nim @@ -235,16 +235,17 @@ method emitObtainingPasswordSuccess*[T](self: Module[T], password: string) = self.view.emitObtainingPasswordSuccess(password) method onNodeLogin*[T](self: Module[T], error: string) = + echo "onNodeLogin >>>>" let currStateObj = self.view.currentStartupStateObj() if currStateObj.isNil: error "cannot determine current startup state" quit() # quit the app if error.len == 0: - self.controller.cleanTmpData() self.delegate.userLoggedIn() if currStateObj.flowType() != FlowType.AppLogin: self.controller.storeIdentityImage() + self.controller.cleanTmpData() else: self.view.setAppState(AppState.StartupState) if currStateObj.flowType() == FlowType.AppLogin: @@ -300,4 +301,4 @@ method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurr self.keycardSharedModule = nil if lastStepInTheCurrentFlow: self.controller.cleanTmpData() - self.view.setCurrentStartupState(newWelcomeState(FlowType.General, nil)) \ No newline at end of file + self.view.setCurrentStartupState(newWelcomeState(FlowType.General, nil)) diff --git a/test/ui-test/fixtures/images/dog-png-30.png b/test/ui-test/fixtures/images/dog-png-30.png new file mode 100644 index 00000000000..52cb7ce2cbd Binary files /dev/null and b/test/ui-test/fixtures/images/dog-png-30.png differ diff --git a/test/ui-test/fixtures/images/doggo.jpeg b/test/ui-test/fixtures/images/doggo.jpeg new file mode 100644 index 00000000000..a6da3c26918 Binary files /dev/null and b/test/ui-test/fixtures/images/doggo.jpeg differ diff --git a/test/ui-test/src/drivers/SquishDriver.py b/test/ui-test/src/drivers/SquishDriver.py index 83fd3a13158..cee356e90d5 100755 --- a/test/ui-test/src/drivers/SquishDriver.py +++ b/test/ui-test/src/drivers/SquishDriver.py @@ -16,6 +16,8 @@ import object import names import test +import os +import os.path as path from objectmaphelper import Wildcard diff --git a/test/ui-test/src/drivers/SquishDriverVerification.py b/test/ui-test/src/drivers/SquishDriverVerification.py index bf684fcc386..c7f69cfee52 100644 --- a/test/ui-test/src/drivers/SquishDriverVerification.py +++ b/test/ui-test/src/drivers/SquishDriverVerification.py @@ -93,4 +93,4 @@ def verify_failure(errorMsg: str): test.fail(errorMsg) def log(text: str): - test.log(text) + test.log(text) diff --git a/test/ui-test/src/screens/StatusWelcomeScreen.py b/test/ui-test/src/screens/StatusWelcomeScreen.py index a3842b3ae43..69590ff60cf 100644 --- a/test/ui-test/src/screens/StatusWelcomeScreen.py +++ b/test/ui-test/src/screens/StatusWelcomeScreen.py @@ -36,7 +36,13 @@ class SignUpComponents(Enum): CONFIRM_PSW_AGAIN_INPUT: str = "onboarding_confirmPswAgain_Input" FINALIZE_PSW_BUTTON: str = "onboarding_finalise_password_button" PASSWORD_PREFERENCE: str = "mainWindow_I_prefer_to_use_my_password_StatusBaseText" - + ADD_PROFILE_IMAGE_BUTTON: str = "mainWindow_Update_Profile_Image_Button" + PROFILE_IMAGE_CROPPER: str = "mainWindow_Image_Cropper" + PROFILE_IMAGE_CROPPER_MODAL: str = "mainWindow_Image_Cropper_Modal" + PROFILE_IMAGE_SELECTION_MODAL: str = "mainWindow_Image_SELECTION_MODAL" + PROFILE_IMAGE_CROP_WORKFLOW_ITEM: str = "mainWindow_Image_Crop_Workflow_Item" + PROFILE_IMAGE_CROPPER_ACCEPT_BUTTON: str = "mainWindow_Image_Cropper_Accept_Button" + USER_PROFILE_IMAGE: str = "mainWindow_WelcomeScreen_User_Profile_Image" class SeedPhraseComponents(Enum): IMPORT_A_SEED_TEXT: str = "import_a_seed_phrase_StatusBaseText" @@ -47,6 +53,9 @@ class SeedPhraseComponents(Enum): TWENTY_FOUR_BUTTON: str = "switchTabBar_24_words_Button" SEEDS_WORDS_TEXTFIELD_template: str = "onboarding_SeedPhrase_Input_TextField_" SUBMIT_BUTTON: str = "seedPhraseView_Submit_Button" + +class MainScreen(Enum): + PROFILE_NAV_BAR_BUTTON: str = "mainWindow_ProfileNavBarButton" class StatusWelcomeScreen: @@ -114,3 +123,31 @@ def _agree_terms_and_conditions(self): def seed_phrase_visible(self): is_loaded_visible_and_enabled(SeedPhraseComponents.INVALID_SEED_TEXT.value) + def input_profileImage(self, profileImageUrl: str): + workflow = get_obj(SignUpComponents.PROFILE_IMAGE_CROP_WORKFLOW_ITEM.value) + workflow.cropImage(profileImageUrl) + click_obj_by_name(SignUpComponents.PROFILE_IMAGE_CROPPER_ACCEPT_BUTTON.value) + + def input_username_profileImage_password_and_finalize_sign_up(self, profileImageUrl: str, username: str, password: str): + print("input_username_profileImage_password_and_finalize_sign_up >>> ", profileImageUrl) + self.input_profileImage(profileImageUrl) + + self.input_username(username) + + self.input_password(password) + + self.input_confirmation_password(password) + + if sys.platform == "darwin": + click_obj_by_name(SignUpComponents.PASSWORD_PREFERENCE.value) + + def profile_image_updated(self, profileImageUrl: str): + print("profileImageUrl >>> ", profileImageUrl) + profileButton = wait_and_get_obj(MainScreen.PROFILE_NAV_BAR_BUTTON.value) + +# img = object.grabScreenshot(profileButton, {"delay": 0}) +# img.save("profileImage.png") + + click_obj(profileButton) + + abc = findImage("doggo.jpeg", {}, "all" ) \ No newline at end of file diff --git a/test/ui-test/testSuites/suite_status/shared/scripts/bdd_hooks.py b/test/ui-test/testSuites/suite_status/shared/scripts/bdd_hooks.py index 8910078af02..a3999fe558b 100644 --- a/test/ui-test/testSuites/suite_status/shared/scripts/bdd_hooks.py +++ b/test/ui-test/testSuites/suite_status/shared/scripts/bdd_hooks.py @@ -16,6 +16,7 @@ def hook(context): context.userData = {} context.userData["aut_name"] = _status_desktop_app_name context.userData["status_data_folder_path"] = _status_data_folder_path + context.userData["fixtures_root"] = os.path.join(os.path.dirname(__file__), "../../../fixtures/") @OnScenarioEnd def hook(context): diff --git a/test/ui-test/testSuites/suite_status/shared/scripts/names.py b/test/ui-test/testSuites/suite_status/shared/scripts/names.py index 6427700736c..ab50f9b3677 100644 --- a/test/ui-test/testSuites/suite_status/shared/scripts/names.py +++ b/test/ui-test/testSuites/suite_status/shared/scripts/names.py @@ -9,3 +9,21 @@ from sections.onboarding_names import * from sections.settings_names import * from sections.wallet_names import * +mainWindow_StatusWindow_QML_1623 = {"name": "mainWindow", "type": "StatusWindow_QML_1623", "visible": True} +mainWindow_tester123_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "tester123", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Overlay = {"container": mainWindow_StatusWindow_QML_1623, "type": "Overlay", "unnamed": 1, "visible": True} +o_AccountMenuItemPanel = {"checkable": False, "container": mainWindow_Overlay, "enabled": True, "type": "AccountMenuItemPanel", "unnamed": 1, "visible": True} +mainWindow_keysMainViewPrimaryActionButton_StatusButton = {"container": mainWindow_StatusWindow_QML_1623, "objectName": "keysMainViewPrimaryActionButton", "type": "StatusButton", "visible": True} +mainWindow_add_icon_StatusIcon = {"container": mainWindow_StatusWindow_QML_1623, "objectName": "add-icon", "source": "qrc:/StatusQ/src/assets/img/icons/add.svg", "type": "StatusIcon", "visible": True} +make_this_my_profile_picture_StatusBaseText = {"container": mainWindow_Overlay, "text": "Make this my profile picture", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_StyledTextField = {"container": mainWindow_StatusWindow_QML_1623, "echoMode": 2, "passwordCharacter": "•", "type": "StyledTextField", "unnamed": 1, "visible": True} +mainWindow_assasss_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "assasss", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Rectangle = {"container": mainWindow_StatusWindow_QML_1623, "type": "Rectangle", "unnamed": 1, "visible": True} +mainWindow_CanvasItem = {"container": mainWindow_StatusWindow_QML_1623, "type": "CanvasItem", "unnamed": 1, "visible": True} +mainWindow_Password_PlaceholderText = {"container": mainWindow_StatusWindow_QML_1623, "text": "Password", "type": "PlaceholderText", "unnamed": 1, "visible": True} +mainWindow_assasa_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "assasa", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Generate_new_keys_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "Generate new keys", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Khushboo_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "Khushboo", "type": "StatusBaseText", "unnamed": 1, "visible": True} +o_CanvasItem = {"container": mainWindow_Overlay, "type": "CanvasItem", "unnamed": 1, "visible": True} +mainWindow_Create_password_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "Create password", "type": "StatusBaseText", "unnamed": 1, "visible": True} +mainWindow_Finalise_Status_Password_Creation_StatusBaseText = {"container": mainWindow_StatusWindow_QML_1623, "text": "Finalise Status Password Creation", "type": "StatusBaseText", "unnamed": 1, "visible": True} diff --git a/test/ui-test/testSuites/suite_status/shared/scripts/sections/global_names.py b/test/ui-test/testSuites/suite_status/shared/scripts/sections/global_names.py index b6648339624..186f0a38bf1 100644 --- a/test/ui-test/testSuites/suite_status/shared/scripts/sections/global_names.py +++ b/test/ui-test/testSuites/suite_status/shared/scripts/sections/global_names.py @@ -5,4 +5,5 @@ chatView_log = {"container": statusDesktop_mainWindow, "objectName": "chatLogView", "type": "StatusListView", "visible": True} chatMessageListView_msgDelegate_MessageView = {"container": chatView_log, "objectName": "chatMessageViewDelegate", "index": 1, "type": "MessageView", "visible": True} moduleWarning_Banner = {"container": statusDesktop_mainWindow, "objectName": "moduleWarningBanner", "type": "Rectangle", "visible": True} -statusDesktop_mainWindow_AppMain_EmojiPopup_SearchTextInput = {"container": statusDesktop_mainWindow_overlay, "objectName": "StatusEmojiPopup_searchBox", "type": "TextEdit", "visible": True} \ No newline at end of file +statusDesktop_mainWindow_AppMain_EmojiPopup_SearchTextInput = {"container": statusDesktop_mainWindow_overlay, "objectName": "StatusEmojiPopup_searchBox", "type": "TextEdit", "visible": True} +mainWindow_ProfileNavBarButton = {"container": statusDesktop_mainWindow, "objectName": "statusProfileNavBarTabButton", "type": "StatusNavBarTabButton", "visible": True} \ No newline at end of file diff --git a/test/ui-test/testSuites/suite_status/shared/scripts/sections/onboarding_names.py b/test/ui-test/testSuites/suite_status/shared/scripts/sections/onboarding_names.py index ba13230e756..219484487d3 100644 --- a/test/ui-test/testSuites/suite_status/shared/scripts/sections/onboarding_names.py +++ b/test/ui-test/testSuites/suite_status/shared/scripts/sections/onboarding_names.py @@ -17,6 +17,18 @@ onboarding_DetailsView_NextButton = {"container": statusDesktop_mainWindow, "objectName": "onboardingDetailsViewNextButton", "type": "StatusButton"} mainWindow_I_prefer_to_use_my_password_StatusBaseText = {"container": statusDesktop_mainWindow, "objectName": "touchIdIPreferToUseMyPasswordText", "type": "StatusBaseText"} mainWindow_Ok_got_it_StatusBaseText = {"container": statusDesktop_mainWindow, "type": "StatusButton", "objectName": "allowNotificationsOnboardingOkButton", "visible": True} +mainWindow_Update_Profile_Image_Button = {"container": statusDesktop_mainWindow, "type": "StatusRoundButton", "objectName": "welcomeScreenUpdatePicButton", "visible": True} +mainWindow_WelcomeScreen_User_Profile_Image = {"container": statusDesktop_mainWindow, "type": "StatusSmartIdenticon", "objectName": "welcomeScreenUserProfileImage"} + + +mainWindow_Image_Cropper = {"container": statusDesktop_mainWindow, "type": "StatusImageCropPanel", "objectName": "profileImageCropper", "visible": True} + +mainWindow_Image_Cropper_Modal = {"container": statusDesktop_mainWindow, "type": "StatusModal", "objectName": "imageCropperModal"} +mainWindow_Image_SELECTION_MODAL = {"container": statusDesktop_mainWindow, "type": "FileDialog", "objectName": "selectProfileImageFileDialog"} +mainWindow_Image_Crop_Workflow_Item= {"container": statusDesktop_mainWindow, "type": "Item", "objectName": "imageCropWorkflow"} +mainWindow_Image_Cropper_Accept_Button= {"container": statusDesktop_mainWindow, "type": "StatusButton", "objectName": "imageCropperAcceptButton"} + + # Seed phrase form: import_a_seed_phrase_StatusBaseText = {"container": statusDesktop_mainWindow, "text": "Import a seed phrase", "type": "StatusBaseText", "unnamed": 1, "visible": True} diff --git a/test/ui-test/testSuites/suite_status/shared/searchImages/doggo.jpeg b/test/ui-test/testSuites/suite_status/shared/searchImages/doggo.jpeg new file mode 100644 index 00000000000..a6da3c26918 Binary files /dev/null and b/test/ui-test/testSuites/suite_status/shared/searchImages/doggo.jpeg differ diff --git a/test/ui-test/testSuites/suite_status/shared/searchImages/profileImage.png b/test/ui-test/testSuites/suite_status/shared/searchImages/profileImage.png new file mode 100644 index 00000000000..3317600f872 Binary files /dev/null and b/test/ui-test/testSuites/suite_status/shared/searchImages/profileImage.png differ diff --git a/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImage.png b/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImage.png new file mode 100644 index 00000000000..35ffc3c7504 Binary files /dev/null and b/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImage.png differ diff --git a/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImages.png b/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImages.png new file mode 100644 index 00000000000..7b91e78306c Binary files /dev/null and b/test/ui-test/testSuites/suite_status/shared/searchImages/profileTestImages.png differ diff --git a/test/ui-test/testSuites/suite_status/shared/searchImages/testProfileImage.png b/test/ui-test/testSuites/suite_status/shared/searchImages/testProfileImage.png new file mode 100644 index 00000000000..7cb54c6e6e3 Binary files /dev/null and b/test/ui-test/testSuites/suite_status/shared/searchImages/testProfileImage.png differ diff --git a/test/ui-test/testSuites/suite_status/shared/steps/signUpSteps.py b/test/ui-test/testSuites/suite_status/shared/steps/signUpSteps.py index 0a22260235b..39f2fd03b00 100644 --- a/test/ui-test/testSuites/suite_status/shared/steps/signUpSteps.py +++ b/test/ui-test/testSuites/suite_status/shared/steps/signUpSteps.py @@ -41,3 +41,12 @@ def step(context, seed_phrase): @Then("the invalid seed text is visible") def step(context): _welcomeScreen.seed_phrase_visible() + +@When("the user signs up with profileImage |any| and username |any| and password |any|") +def step(context, profileImageUrl, username, password): + _welcomeScreen.input_username_profileImage_password_and_finalize_sign_up("file:///"+context.userData["fixtures_root"]+"images/"+profileImageUrl, username, password) + +@Then("the profile navBar has the image |any|") +def step(context, profileImageUrl): + _welcomeScreen.profile_image_updated(context.userData["fixtures_root"]+"images/"+profileImageUrl) + diff --git a/test/ui-test/testSuites/suite_status/tst_statusSignUp/test.feature b/test/ui-test/testSuites/suite_status/tst_statusSignUp/test.feature index 56621180bce..4c4aaa7f739 100644 --- a/test/ui-test/testSuites/suite_status/tst_statusSignUp/test.feature +++ b/test/ui-test/testSuites/suite_status/tst_statusSignUp/test.feature @@ -136,3 +136,9 @@ Feature: Status Desktop Sign Up Then the following ui-component seedPhraseView_Submit_Button is not enabled And the invalid seed text is visible + Scenario: User signs up with a profile image + + Given A first time user lands on the status desktop and generates new key + When the user signs up with profileImage doggo.jpeg and username tester123 and password TesTEr16843/!@00 + Then the profile navBar has the image doggo.jpeg + diff --git a/ui/app/AppLayouts/Onboarding/stores/StartupStore.qml b/ui/app/AppLayouts/Onboarding/stores/StartupStore.qml index 33051e30d6f..52b78f1de1f 100644 --- a/ui/app/AppLayouts/Onboarding/stores/StartupStore.qml +++ b/ui/app/AppLayouts/Onboarding/stores/StartupStore.qml @@ -87,4 +87,8 @@ QtObject { function getSeedPhrase() { return root.startupModuleInst.getSeedPhrase() } + + function uploadImage(source, aX, aY, bX, bY) { + return profileSectionModule.profileModule.upload(source, aX, aY, bX, bY) + } } diff --git a/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml b/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml index bbbd04f65f0..f2ac92490d1 100644 --- a/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml +++ b/ui/app/AppLayouts/Onboarding/views/InsertDetailsView.qml @@ -88,6 +88,7 @@ Item { StatusSmartIdenticon { anchors.left: parent.left id: userImage + objectName: "welcomeScreenUserProfileImage" image { width: 86 height: 86 @@ -106,6 +107,7 @@ Item { } StatusRoundButton { id: updatePicButton + objectName: "welcomeScreenUpdatePicButton" width: 40 height: 40 anchors.top: parent.top @@ -233,10 +235,10 @@ Item { acceptButtonText: qsTr("Make this my profile picture") onImageCropped: { const croppedImg = root.startupStore.generateImage(image, - cropRect.x.toFixed(), - cropRect.y.toFixed(), - (cropRect.x + cropRect.width).toFixed(), - (cropRect.y + cropRect.height).toFixed()); + cropRect.x.toFixed(), + cropRect.y.toFixed(), + (cropRect.x + cropRect.width).toFixed(), + (cropRect.y + cropRect.height).toFixed()); userImage.image.source = croppedImg; } } diff --git a/ui/app/AppLayouts/Profile/popups/ChangeProfilePicModal.qml b/ui/app/AppLayouts/Profile/popups/ChangeProfilePicModal.qml deleted file mode 100644 index fd895a666f5..00000000000 --- a/ui/app/AppLayouts/Profile/popups/ChangeProfilePicModal.qml +++ /dev/null @@ -1,115 +0,0 @@ -import QtQuick 2.13 -import QtQuick.Dialogs 1.3 - -import utils 1.0 - -import StatusQ.Controls 0.1 - -import shared 1.0 -import shared.panels 1.0 -import shared.popups 1.0 - -// TODO: replace with StatusModal -ModalPopup { - id: popup - title: qsTr("Profile picture") - - property var profileStore - - property string selectedImage // selectedImage is for us to be able to analyze it before setting it as current - property string uploadError - property url largeImage: popup.profileStore.profileLargeImage - property bool hasIdentityImage: !!popup.profileStore.profileLargeImage - - onClosed: { - destroy() - } - - onSelectedImageChanged: { - if (!selectedImage) { - return - } - - cropImageModal.open() - } - - Item { - anchors.fill: parent - - RoundedImage { - id: profilePic - source: popup.largeImage - width: 160 - height: 160 - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - border.width: 1 - border.color: Style.current.border - onClicked: imageDialog.open() - } - - StyledText { - visible: !!uploadError - text: uploadError - anchors.left: parent.left - anchors.right: parent.right - anchors.top: profilePic.bottom - horizontalAlignment: Text.AlignHCenter - font.pixelSize: 13 - wrapMode: Text.WordWrap - anchors.topMargin: 13 - font.weight: Font.Thin - color: Style.current.danger - } - - ImageCropperModal { - id: cropImageModal - - selectedImage: popup.selectedImage - ratio: "1:1" - onCropFinished: { - popup.uploadError = popup.profileStore.uploadImage(selectedImage, aX, aY, bX, bY) - } - } - } - - footer: Item { - width: parent.width - height: uploadBtn.height - - StatusFlatButton { - visible: popup.hasIdentityImage - type: StatusBaseButton.Type.Danger - text: qsTr("Remove") - anchors.right: uploadBtn.left - anchors.rightMargin: Style.current.padding - anchors.bottom: parent.bottom - onClicked: { - popup.uploadError = popup.profileStore.removeImage() - } - } - - StatusButton { - id: uploadBtn - text: qsTr("Upload") - anchors.right: parent.right - anchors.bottom: parent.bottom - onClicked: { - imageDialog.open() - } - - FileDialog { - id: imageDialog - title: qsTr("Please choose an image") - folder: shortcuts.pictures - nameFilters: [ - qsTr("Image files (*.jpg *.jpeg *.png)") - ] - onAccepted: { - selectedImage = imageDialog.fileUrls[0] - } - } - } - } -} - diff --git a/ui/app/AppLayouts/Profile/popups/qmldir b/ui/app/AppLayouts/Profile/popups/qmldir index dc6b65595a8..a341a4d3ac6 100644 --- a/ui/app/AppLayouts/Profile/popups/qmldir +++ b/ui/app/AppLayouts/Profile/popups/qmldir @@ -1,2 +1 @@ -ChangeProfilePicModal 1.0 ChangeProfilePicModal.qml BackupSeedModal 1.0 BackupSeedModal.qml diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 0b45ed14e59..3022c2f3cfe 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -348,6 +348,7 @@ Item { navBarProfileButton: StatusNavBarTabButton { id: profileButton + objectName: "statusProfileNavBarTabButton" property bool opened: false name: appMain.rootStore.userProfileInst.name @@ -384,7 +385,10 @@ Item { } } - onClicked: userStatusContextMenu.opened ? userStatusContextMenu.close() : userStatusContextMenu.open() + onClicked: { +console.error(" >>>>>>>>>>>>> icon.source == ", Qt.resolvedUrl(icon.source)) + userStatusContextMenu.opened ? userStatusContextMenu.close() : userStatusContextMenu.open() + } UserStatusContextMenu { id: userStatusContextMenu diff --git a/ui/imports/shared/controls/ImageCropper.qml b/ui/imports/shared/controls/ImageCropper.qml deleted file mode 100644 index 4c57c6d5e38..00000000000 --- a/ui/imports/shared/controls/ImageCropper.qml +++ /dev/null @@ -1,213 +0,0 @@ -import QtQuick 2.13 - -import "../panels" - -import utils 1.0 - -Item { - id: root - property Image image - property alias selectorRectangle: selectorRectangle - property string ratio: "" - property var splitRatio: !!ratio ? ratio.split(":") : null - property int widthRatio: !!ratio ? parseInt(splitRatio[0]) : -1 - property int heightRatio: !!ratio ? parseInt(splitRatio[1]) : -1 - property bool settingCorners: false - property int draggedCorner: 0 - property bool ready: false - - readonly property int topLeft: 0 - readonly property int topRight: 1 - readonly property int bottomLeft: 2 - readonly property int bottomRight: 3 - - width: image.width - height: image.height - - Rectangle { - id: selectorRectangle - visible: false - x: 0 - y: 0 - border.width: 2 - border.color: Style.current.orange - color: Style.current.transparent - - function fitRatio(makeBigger) { - if (!!ratio) { - if ((makeBigger && selectorRectangle.width < selectorRectangle.height) || (!makeBigger && selectorRectangle.width > selectorRectangle.height)) { - selectorRectangle.width = (selectorRectangle.height/heightRatio) * widthRatio - } else { - selectorRectangle.height = (selectorRectangle.width/widthRatio) * heightRatio - } - } - } - - function initialSetup() { - selectorRectangle.width = image.width - selectorRectangle.height = image.height - - fitRatio() - topLeftCorner.x = 0 - topLeftCorner.y = 0 - topRightCorner.x = selectorRectangle.width - topRightCorner.width - topRightCorner.y = 0 - bottomLeftCorner.x = 0 - bottomLeftCorner.y = selectorRectangle.height - topRightCorner.height - bottomRightCorner.x = selectorRectangle.width - topRightCorner.width - bottomRightCorner.y = selectorRectangle.height - topRightCorner.height - } - - - function adjustRectangleSize() { - if (!selectorRectangle.visible) { - return - } - - selectorRectangle.width = bottomRightCorner.x + bottomRightCorner.width - topLeftCorner.x - selectorRectangle.height = bottomRightCorner.y + bottomRightCorner.height - topLeftCorner.y - selectorRectangle.x = topLeftCorner.x - selectorRectangle.y = topLeftCorner.y - - if (!!ratio) { - // FIXME with a ratio that is not 1:1, the rectangle can go out of bounds - fitRatio() - - switch(draggedCorner) { - case topLeft: - selectorRectangle.x = topLeftCorner.x - selectorRectangle.y = topLeftCorner.y - break - case topRight: - selectorRectangle.x = topRightCorner.x - selectorRectangle.width + topRightCorner.width - selectorRectangle.y = topRightCorner.y - break - case bottomLeft: - selectorRectangle.x = bottomLeftCorner.x - selectorRectangle.y = bottomLeftCorner.y - selectorRectangle.height + bottomLeftCorner.height - break - case bottomRight: - selectorRectangle.x = bottomRightCorner.x - selectorRectangle.width + bottomRightCorner.width - selectorRectangle.y = bottomRightCorner.y - selectorRectangle.height + bottomRightCorner.height - break - } - } - } - - Connections { - target: image - onStatusChanged: { - if (image.status === Image.Ready) { - selectorRectangle.initialSetup() - selectorRectangle.visible = true - root.ready = true - } - } - } - } - function putCorners() { - settingCorners = true - - topLeftCorner.x = selectorRectangle.x - topLeftCorner.y = selectorRectangle.y - topRightCorner.x = selectorRectangle.x + selectorRectangle.width - topRightCorner.width - topRightCorner.y = selectorRectangle.y - bottomLeftCorner.x = selectorRectangle.x - bottomLeftCorner.y = selectorRectangle.y + selectorRectangle.height - topRightCorner.height - bottomRightCorner.x = selectorRectangle.x + selectorRectangle.width - topRightCorner.width - bottomRightCorner.y = selectorRectangle.y + selectorRectangle.height - topRightCorner.height - - settingCorners = false - } - - - // Size calculations are only done on top-left and bottom-right, because the other two corners follow them - CropCornerRectangle { - id: topLeftCorner - onXChanged: { - if (settingCorners) return - if (x < 0) x = 0 - if (x > topRightCorner.x - width) x = topRightCorner.x - width - - bottomLeftCorner.x = x - selectorRectangle.adjustRectangleSize() - } - onYChanged: { - if (settingCorners) return - if (y < 0) y = 0 - if (y > bottomRightCorner.y - height) y = bottomRightCorner.y - height - - topRightCorner.y = y - selectorRectangle.adjustRectangleSize() - } - onPressed: { - draggedCorner = topLeft - } - - onReleased: { - putCorners() - } - } - - CropCornerRectangle { - id: topRightCorner - onXChanged: { - if (settingCorners) return - bottomRightCorner.x = x - } - onYChanged: { - if (settingCorners) return - topLeftCorner.y = y - } - onPressed: { - draggedCorner = topRight - } - onReleased: { - putCorners() - } - } - - CropCornerRectangle { - id: bottomLeftCorner - onXChanged: { - if (settingCorners) return - topLeftCorner.x = x - } - onYChanged: { - if (settingCorners) return - bottomRightCorner.y = y - } - onPressed: { - draggedCorner = bottomLeft - } - onReleased: { - putCorners() - } - } - - CropCornerRectangle { - id: bottomRightCorner - onXChanged: { - if (settingCorners) return - if (x < topLeftCorner.x + topLeftCorner.width) x = topLeftCorner.x + topLeftCorner.width - if (x > image.width - width) x = image.width - width - topRightCorner.x = x - - selectorRectangle.adjustRectangleSize() - } - onYChanged: { - if (settingCorners) return - if (y < topRightCorner.y + topRightCorner.height) y = topRightCorner.y + topRightCorner.height - if (y > image.height - height) y = image.height - height - bottomLeftCorner.y = y - - selectorRectangle.adjustRectangleSize() - } - onPressed: { - draggedCorner = bottomRight - } - onReleased: { - putCorners() - } - } -} diff --git a/ui/imports/shared/controls/qmldir b/ui/imports/shared/controls/qmldir index d072e1ec679..ae3c01b3f0a 100644 --- a/ui/imports/shared/controls/qmldir +++ b/ui/imports/shared/controls/qmldir @@ -8,7 +8,6 @@ FormGroup 1.0 FormGroup.qml GasSelector 1.0 GasSelector.qml GasSelectorButton 1.0 GasSelectorButton.qml GasValidator 1.0 GasValidator.qml -ImageCropper 1.0 ImageCropper.qml Input 1.0 Input.qml RadioButtonSelector 1.0 RadioButtonSelector.qml RecipientSelector 1.0 RecipientSelector.qml diff --git a/ui/imports/shared/panels/CropCornerRectangle.qml b/ui/imports/shared/panels/CropCornerRectangle.qml deleted file mode 100644 index ca38e4ec2bf..00000000000 --- a/ui/imports/shared/panels/CropCornerRectangle.qml +++ /dev/null @@ -1,29 +0,0 @@ -import QtQuick 2.13 - -import utils 1.0 - -Rectangle { - signal released() - signal pressed() - - id: root - width: 25 - height: 25 - border.width: 2 - border.color: Style.current.orange - color: Utils.setColorAlpha(Style.current.orange, 0.5) - - Drag.active: dragArea.drag.active - - MouseArea { - id: dragArea - property int oldX - property int oldY - - anchors.fill: parent - drag.target: parent - cursorShape: Qt.PointingHandCursor - onReleased: root.released() - onPressed: root.pressed() - } -} diff --git a/ui/imports/shared/panels/qmldir b/ui/imports/shared/panels/qmldir index 271ee1b746a..5e895f5a103 100644 --- a/ui/imports/shared/panels/qmldir +++ b/ui/imports/shared/panels/qmldir @@ -1,7 +1,6 @@ Address 1.0 Address.qml AddressRequiredValidator 1.0 AddressRequiredValidator.qml BalanceValidator 1.0 BalanceValidator.qml -CropCornerRectangle 1.0 CropCornerRectangle.qml GlossaryEntry 1.0 GlossaryEntry.qml GlossaryLetter 1.0 GlossaryLetter.qml ImageLoader 1.0 ImageLoader.qml diff --git a/ui/imports/shared/popups/ImageCropWorkflow.qml b/ui/imports/shared/popups/ImageCropWorkflow.qml index fc93586f4c7..d205447fb7c 100644 --- a/ui/imports/shared/popups/ImageCropWorkflow.qml +++ b/ui/imports/shared/popups/ImageCropWorkflow.qml @@ -12,6 +12,7 @@ import utils 1.0 Item { id: root + objectName: "imageCropWorkflow" property alias aspectRatio: imageCropper.aspectRatio property alias windowStyle: imageCropper.windowStyle @@ -26,22 +27,29 @@ Item { fileDialog.open() } + function cropImage(imageUrl) { + console.error( "cropImage >>> ", imageUrl) + imageCropper.source = imageUrl + imageCropperModal.open() + } + FileDialog { id: fileDialog + objectName: "selectProfileImageFileDialog" title: root.imageFileDialogTitle folder: root.userSelectedImage ? imageCropper.source.substr(0, imageCropper.source.lastIndexOf("/")) : shortcuts.pictures nameFilters: [qsTr("Supported image formats (%1)").arg("*.jpg *.jpeg *.jfif *.webp *.png *.heif")] onAccepted: { if (fileDialog.fileUrls.length > 0) { - imageCropper.source = fileDialog.fileUrls[0] - imageCropperModal.open() + cropImage(fileDialog.fileUrls[0]) } } } // FileDialog StatusModal { id: imageCropperModal + objectName: "imageCropperModal" header.title: root.title @@ -51,15 +59,16 @@ Item { StatusImageCropPanel { id: imageCropper + objectName: "profileImageCropper" implicitHeight: root.roundedImage ? 350 : 370 anchors { - fill: parent - leftMargin: Style.current.bigPadding + Style.current.halfPadding / 2 - rightMargin: Style.current.bigPadding + Style.current.halfPadding / 2 - topMargin: Style.current.bigPadding - bottomMargin: Style.current.bigPadding + fill: parent + leftMargin: Style.current.bigPadding + Style.current.halfPadding / 2 + rightMargin: Style.current.bigPadding + Style.current.halfPadding / 2 + topMargin: Style.current.bigPadding + bottomMargin: Style.current.bigPadding } margins: root.roundedImage ? 10 : 20 @@ -69,6 +78,7 @@ Item { rightButtons: [ StatusButton { + objectName: "imageCropperAcceptButton" text: root.acceptButtonText enabled: imageCropper.sourceSize.width > 0 && imageCropper.sourceSize.height > 0 diff --git a/ui/imports/shared/popups/ImageCropperModal.qml b/ui/imports/shared/popups/ImageCropperModal.qml deleted file mode 100644 index 429a7e42eda..00000000000 --- a/ui/imports/shared/popups/ImageCropperModal.qml +++ /dev/null @@ -1,88 +0,0 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Layouts 1.13 - -import utils 1.0 - -import StatusQ.Controls 0.1 - -import "../controls" -import "." - -// TODO: replace with StatusModal -ModalPopup { - property string selectedImage - property string ratio: "1:1" - property int aX: 0 - property int aY: 0 - property int bX: 0 - property int bY: 0 - signal cropFinished(aX: int, aY: int, bX: int, bY: int) - - id: cropImageModal - width: image.width + 50 - height: image.height + 170 - title: qsTr("Crop your image (optional)") - - Image { - id: image - width: 400 - source: cropImageModal.selectedImage - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - fillMode: Image.PreserveAspectFit - } - - ImageCropper { - id: imageCropper - x: image.x - y: image.y - image: image - ratio: cropImageModal.ratio - onReadyChanged: { - if (ready) { - // cropImageModal.calculateCrop() - cropImageModal.aX = Qt.binding(function() { - const aXPercent = imageCropper.selectorRectangle.x / image.width - return Math.round(aXPercent * image.sourceSize.width) - }) - cropImageModal.aY = Qt.binding(function() { - const aYPercent = imageCropper.selectorRectangle.y / image.height - return Math.round(aYPercent * image.sourceSize.height) - }) - cropImageModal.bX = Qt.binding(function() { - const bXPercent = (imageCropper.selectorRectangle.x + imageCropper.selectorRectangle.width) / image.width - return Math.round(bXPercent * image.sourceSize.width) - }) - cropImageModal.bY = Qt.binding(function() { - const bYPercent = (imageCropper.selectorRectangle.y + imageCropper.selectorRectangle.height) / image.height - return Math.round(bYPercent * image.sourceSize.height) - }) - } - } - - } - - footer: StatusButton { - id: doneBtn - text: qsTr("Finish") - anchors.right: parent.right - anchors.bottom: parent.bottom - onClicked: { - const aXPercent = imageCropper.selectorRectangle.x / image.width - const aYPercent = imageCropper.selectorRectangle.y / image.height - const bXPercent = (imageCropper.selectorRectangle.x + imageCropper.selectorRectangle.width) / image.width - const bYPercent = (imageCropper.selectorRectangle.y + imageCropper.selectorRectangle.height) / image.height - - - const aX = Math.round(aXPercent * image.sourceSize.width) - const aY = Math.round(aYPercent * image.sourceSize.height) - - const bX = Math.round(bXPercent * image.sourceSize.width) - const bY = Math.round(bYPercent * image.sourceSize.height) - - cropImageModal.cropFinished(aX, aY, bX, bY) - cropImageModal.close() - } - } -} diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir index a3ed9ea5063..42b0b008149 100644 --- a/ui/imports/shared/popups/qmldir +++ b/ui/imports/shared/popups/qmldir @@ -6,7 +6,6 @@ CommunityIntroDialog 1.0 CommunityIntroDialog.qml ContactVerificationRequestPopup 1.0 ContactVerificationRequestPopup.qml DownloadModal 1.0 DownloadModal.qml DownloadPage 1.0 DownloadPage.qml -ImageCropperModal 1.0 ImageCropperModal.qml InviteFriendsPopup 1.0 InviteFriendsPopup.qml NicknamePopup 1.0 NicknamePopup.qml ModalPopup 1.0 ModalPopup.qml