diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index ccf6a8ce0..0b8de3353 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -66,7 +66,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_month_day_year" = "{month} {day}, {year}"; "lng_box_ok" = "OK"; -"lng_box_cancel" = "CANCEL"; "lng_cancel" = "Cancel"; "lng_continue" = "Continue"; @@ -116,6 +115,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_intro_finish" = "SIGN UP"; "lng_intro_submit" = "SUBMIT"; +"lng_photo_caption" = "Caption"; + "lng_phone_ph" = "Your phone number"; "lng_phone_title" = "Your Phone"; "lng_phone_desc" = "Please confirm your country code and\nenter your phone number."; @@ -125,7 +126,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_country_ph" = "Search"; "lng_country_done" = "Done"; "lng_country_none" = "Country not found"; -"lng_country_select" = "Select Country"; +"lng_country_select" = "Select country"; "lng_code_ph" = "Your code"; "lng_code_desc" = "We have sent you a message with activation\ncode to your phone. Please enter it below."; @@ -159,7 +160,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_signin_cant_email_forgot" = "If you can't restore access to the e-mail, your remaining options are either to remember your password or to reset your account."; "lng_signin_reset_account" = "Reset your account"; "lng_signin_sure_reset" = "Warning!\n\nYou will lose all your chats and messages,\nalong with any media and files you shared!\n\nDo you want to reset your account?"; -"lng_signin_reset" = "RESET"; +"lng_signin_reset" = "Reset"; "lng_signup_title" = "Information and photo"; "lng_signup_desc" = "Please enter your name and\nupload a photo."; @@ -177,7 +178,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_dlg_search_chat" = "Search in this chat"; "lng_dlg_search_for_messages" = "Search for messages"; -"lng_settings_save" = "SAVE"; +"lng_settings_save" = "Save"; "lng_settings_upload" = "Set Profile Photo"; "lng_settings_crop_profile" = "Select a square area for your profile photo"; "lng_settings_uploading_photo" = "Uploading photo.."; @@ -234,7 +235,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_settings_section_chat" = "Chat options"; "lng_settings_replace_emojis" = "Replace emoji"; "lng_settings_view_emojis" = "View list"; -"lng_settings_emoji_list" = "List of supported emoji"; +"lng_settings_emoji_list" = "Supported emoji"; "lng_settings_send_enter" = "Send by Enter"; "lng_settings_send_ctrlenter" = "Send by Ctrl+Enter"; "lng_settings_send_cmdenter" = "Send by Cmd+Enter"; @@ -258,7 +259,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_download_path_choose" = "Choose download path"; "lng_sure_clear_downloads" = "Do you want to remove all downloaded files from temp folder? It is done automatically on logout or program uninstall."; "lng_download_path_failed" = "File download could not be started. It could happen because of a bad download location.\n\nYou can change download path in Settings."; -"lng_download_path_settings" = "SETTINGS"; +"lng_download_path_settings" = "Settings"; "lng_download_finish_failed" = "File download could not be finished.\n\nWould you like to try again?"; "lng_download_path_clearing" = "Clearing.."; "lng_download_path_cleared" = "Cleared!"; @@ -315,7 +316,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_cloud_password_bad_email" = "Incorrect e-mail, please try other."; "lng_cloud_password_about" = "This password will be required when you log in on a new device in addition to the pin code."; "lng_cloud_password_about_recover" = "Warning! Are you sure you don't want to\nadd a password recovery e-mail?\n\nIf you forget your password, you will\nlose access to your Telegram account."; -"lng_cloud_password_skip_email" = "SKIP E-MAIL"; +"lng_cloud_password_skip_email" = "Skip e-mail"; "lng_cloud_password_almost" = "A confirmation link was sent to the e-mail you provided. Two-step verification will be enabled as soon as you follow that link."; "lng_cloud_password_was_set" = "Two-step verification enabled."; "lng_cloud_password_updated" = "Your cloud password was updated."; @@ -338,21 +339,20 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_connection_port_ph" = "Port"; "lng_connection_user_ph" = "Username"; "lng_connection_password_ph" = "Password"; -"lng_connection_save" = "SAVE"; +"lng_connection_save" = "Save"; "lng_settings_show_sessions" = "Show all sessions"; "lng_settings_reset" = "Terminate all other sessions"; "lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?"; "lng_settings_reset_one_sure" = "Do you want to terminate this session?"; -"lng_settings_reset_button" = "TERMINATE"; +"lng_settings_reset_button" = "Terminate"; "lng_settings_reset_done" = "Other sessions terminated"; "lng_settings_ask_question" = "Ask a Question"; "lng_settings_ask_sure" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions."; -"lng_settings_faq_button" = "GO TO FAQ"; -"lng_settings_ask_ok" = "ASK"; +"lng_settings_faq_button" = "Go to FAQ"; +"lng_settings_ask_ok" = "Ask"; "lng_settings_faq" = "Telegram FAQ"; "lng_settings_logout" = "Log Out"; "lng_sure_logout" = "Are you sure you want to log out?"; -"lng_box_logout" = "LOG OUT"; "lng_settings_need_restart" = "You need to restart for applying some of the new settings. Restart now?"; "lng_settings_restart_now" = "RESTART"; @@ -420,7 +420,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_profile_audio_files_header" = "Playlist"; "lng_profile_copy_phone" = "Copy phone number"; -"lng_channel_add_admins" = "Add"; +"lng_channel_add_admins" = "New administrator"; +"lng_channel_add_members" = "Add members"; "lng_channel_members" = "Members"; "lng_channel_admins" = "Administrators"; "lng_channel_add_admin" = "Add Administrator"; @@ -429,9 +430,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_participant_filter" = "Search"; "lng_participant_invite" = "Invite"; "lng_participant_invite_sorry" = "Sorry, you can only add the first {count:_not_used|# member|# members} to a channel personally.\n\nFrom now on, people will need to join via your invite link."; -"lng_create_group_back" = "BACK"; -"lng_create_group_next" = "NEXT"; -"lng_create_group_create" = "CREATE"; +"lng_create_group_back" = "Back"; +"lng_create_group_next" = "Next"; +"lng_create_group_create" = "Create"; "lng_create_group_title" = "New Group"; "lng_create_group_about" = "Groups are ideal for smaller communities,\nthey can have up to {count:_not_used|# member|# members}"; "lng_create_channel_title" = "New Channel"; @@ -442,7 +443,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_create_private_channel_about" = "Only people with a special invite link may join"; "lng_create_channel_comments" = "Enable Comments"; "lng_create_channel_comments_about" = "If you enable comments, members will be able to discuss your posts in the channel"; -"lng_create_group_skip" = "SKIP"; +"lng_create_group_skip" = "Skip"; "lng_create_channel_link_invalid" = "This link is invalid"; "lng_create_channel_link_occupied" = "Sorry, this link is already occupied"; @@ -495,7 +496,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_group_invite_bad_link" = "This invite link is broken or has expired."; "lng_group_invite_want_join" = "Do you want to join the group «{title}»?"; "lng_group_invite_want_join_channel" = "Do you want to join the channel «{title}»?"; -"lng_group_invite_join" = "JOIN"; +"lng_group_invite_join" = "Join"; "lng_group_invite_link" = "Invite link:"; "lng_group_invite_create" = "Create an invite link"; @@ -539,11 +540,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_switch_stickers" = "Stickers"; "lng_switch_emoji" = "Emoji"; -"lng_box_remove" = "REMOVE"; +"lng_box_remove" = "Remove"; "lng_custom_stickers" = "Custom stickers"; "lng_stickers_remove_pack" = "Remove «{sticker_pack}»?"; -"lng_stickers_add_pack" = "Add {count:_not_used_|# Sticker|# Stickers}"; +"lng_stickers_add_pack" = "Add stickers"; "lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_not_found" = "Sticker pack not found."; "lng_stickers_copied" = "Sticker pack link copied to clipboard."; @@ -563,7 +564,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_report_spam_sure" = "Are you sure you want to report spam from this user?"; "lng_report_spam_sure_group" = "Are you sure you want to report spam in this group?"; "lng_report_spam_sure_channel" = "Are you sure you want to report spam in this channel?"; -"lng_report_spam_ok" = "REPORT"; +"lng_report_spam_ok" = "Report"; "lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment. {more_info}"; "lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment. {more_info}"; "lng_cant_invite_not_contact_channel" = "Sorry, you can only add mutual contacts\nto channels at the moment. {more_info}"; @@ -585,7 +586,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_channel_unmute" = "Unmute"; "lng_open_this_link" = "Open this link?"; -"lng_open_link" = "OPEN"; +"lng_open_link" = "Open"; "lng_bot_start" = "Start"; "lng_bot_choose_group" = "Choose Group"; @@ -675,7 +676,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_forward_share_contact" = "Share contact to {recipient}?"; "lng_forward_send_file_confirm" = "Send «{name}» to {recipient}?"; "lng_forward_send_files_confirm" = "Send selected files to {recipient}?"; -"lng_forward_send" = "SEND"; +"lng_forward_send" = "Send"; "lng_forward_messages" = "{count:_not_used_|Forwarded message|# forwarded messages}"; "lng_forwarding_from" = "{user} and {count:_not_used_|# other|# others}"; "lng_forwarding_from_two" = "{user} and {second_user}"; @@ -688,7 +689,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_edit_self_title" = "Edit your name"; "lng_confirm_contact_data" = "New Contact"; "lng_add_contact" = "Create"; -"lng_add_contact_button" = "Add Contact"; +"lng_add_contact_button" = "New contact"; "lng_contacts_header" = "Contacts"; "lng_contact_not_joined" = "Unfortunately {name} did not join Telegram yet, but you can send your friend an invitation.\n\nWe will notify you about any of your contacts who is joining Telegram."; "lng_try_other_contact" = "Try other"; @@ -713,8 +714,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_selected_cancel_sure_this" = "Do you want to cancel this upload?"; "lng_selected_delete_sure_this" = "Do you want to delete this message?"; "lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?"; -"lng_box_delete" = "DELETE"; -"lng_box_leave" = "LEAVE"; +"lng_box_delete" = "Delete"; +"lng_box_leave" = "Leave"; "lng_about_version" = "Version {version}"; "lng_about_text" = "Official free messaging app based on [a href=\"https://core.telegram.org/mtproto\"]MTProto[/a] and\n[a href=\"https://core.telegram.org/api\"]Telegram API[/a] for speed and security\n\nThis software is licensed under [a href=\"https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\"]GNU GPL[/a] version 3,\nsource code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a]."; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index c33cbb9a2..c0f4862b2 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -59,24 +59,30 @@ wndShadow: sprite(209px, 46px, 19px, 19px); wndShadowShift: 1px; layerAlpha: 0.5; -layerBG: black; +layerBg: black; +boxBg: white; +boxVerticalMargin: 10px; boxWidth: 320px; boxWideWidth: 364px; -boxPadding: margins(26px, 30px, 26px, 8px); +boxPadding: margins(26px, 30px, 34px, 8px); boxMaxListHeight: 600px; boxFontSize: 14px; boxTextFont: font(boxFontSize); -boxTitleFont: font(boxFontSize semibold); +boxTitleFg: #444444; +boxTitleFont: font(boxFontSize bold); boxTitlePosition: point(26px, 28px); boxTitleHeight: 54px; -boxBlueTitleHeight: 54px; boxBlueTitleBg: #6393b5; boxBlueTitleAdditionalFg: #dae9f5; boxBlueTitleAdditionalSkip: 12px; boxBlueTitlePosition: point(23px, 18px); +boxBlueCloseIcon: sprite(120px, 108px, 12px, 12px); +boxBlueCloseBg: #c8e1f0; +boxBlueCloseDuration: 150; +boxBlueShadow: sprite(132px, 108px, 1px, 4px); boxButtonFont: font(boxFontSize semibold); defaultBoxButton: BoxButton { @@ -205,6 +211,73 @@ defaultRadiobutton: Radiobutton { font: boxTextFont; duration: 120; } +solidScroll: flatScroll { + barColor: #3f729734; + bgColor: #214f751a; + barOverColor: #3f729734; + bgOverColor: #214f751a; + + round: 0px; + minHeight: 20px; + + deltax: 5px; + width: 14px; + deltat: 6px; + deltab: 6px; + + topsh: 0px; + bottomsh: 0px; + shColor: rgba(0, 0, 0, 18); + + duration: 150; + hiding: 0; +} +boxScroll: flatScroll(solidScroll) { + width: 18px; + deltax: 6px; +} +boxScrollSkip: 6px; +boxScrollShadowBg: #00000012; + +boxSearchField: InputField(defaultInputField) { + textMargins: margins(41px, 16px, 41px, 0px); + + placeholderFg: #999; + placeholderFgActive: #aaa; + placeholderMargins: margins(4px, 0px, 4px, 0px); + + border: 0px; + borderActive: 0px; + borderError: 0px; + + height: 48px; + + iconSprite: sprite(227px, 21px, 24px, 24px); + iconPosition: point(15px, 14px); +} +boxSearchCancel: iconedButton { + color: white; + bgColor: white; + overBgColor: white; + font: font(fsize); + + opacity: 0.3; + overOpacity: 0.4; + + textPos: point(0px, 0px); + downTextPos: point(0px, 0px); + + duration: 150; + cursor: cursor(pointer); + + icon: sprite(133px, 108px, 12px, 12px); + iconPos: point(8px, 18px); + downIcon: sprite(133px, 108px, 12px, 12px); + downIconPos: point(8px, 18px); + + width: 41px; + height: 48px; +} titleBG: #6389a8; titleColor: #0f8dcc;//rgb(20, 136, 210); @@ -586,73 +659,26 @@ inpIntroPassword: flatInput(inpIntroPhone) { } introSelectDelta: 30px; -btnSelectDone: flatButton(btnDefFlat) { - color: btnYesColor; - overColor: btnYesHover; - downColor: btnYesHover; - - bgColor: white; - overBgColor: btnBoxWhiteHover; - downBgColor: btnBoxWhiteHover; - - width: 182px; - height: 52px; - - textTop: 14px; - overTextTop: 14px; - downTextTop: 15px; - - font: font(17px); - overFont: font(17px); -} -btnSelectCancel: flatButton(btnSelectDone) { - width: 181px; - color: btnNoColor; - overColor: btnNoHover; - downColor: btnNoHover; -} btnSelectSep: #e0e0e0; btnRedLink: linkButton(btnDefLink) { color: #d15948; overColor: #d15948; downColor: #db6352; } -btnRedDone: flatButton(btnSelectDone) { - color: #d15948; - overColor: #d15948; - downColor: #db6352; + +countryRowHeight: 36px; +countryRowNameFont: font(fsize semibold); +countryRowPadding: margins(22px, 9px, 8px, 0px); +countryRowCodeFont: font(fsize); +countryRowBgOver: #f5f8fa; +countryRowCodeFg: #808080; +countryRowCodeFgOver: #7c99b2; +countriesSkip: 12px; +countriesScroll: flatScroll(boxScroll) { + deltat: 9px; + deltab: 3px; } -countryList: countryList { - notFoundColor: #aaa;//rgb(20, 136, 210); - notFoundFont: font(18px); - - verticalMargin: 0px; - - font: font(18px); - codeFont: font(16px); - rowHeight: 42px; - color: #000; - codeColor: #aaaaaa;//rgb(20, 136, 210); - bgColor: #FFF; - bgHovered: #f5f5f5; - margin: 13px; - codeWidth: 60px; - - borderMargin: 0px; - borderColor: rgba(228, 233, 240, 127); - borderWidth: 0px; -} - -countriesSlideShift: 500px; -countriesSlideDuration: 200; -countriesHideFunc: transition(easeInCirc); -countriesShowFunc: transition(easeOutCirc); -countriesBackHideFunc: transition(linear); -countriesBackShowFunc: transition(linear); -countriesAlphaHideFunc: transition(easeOutCirc); -countriesAlphaShowFunc: transition(easeInCirc); - introErrWidth: 450px; introErrDuration: 200; introErrFunc: transition(linear); @@ -724,7 +750,7 @@ setErrBG: #ffa5a5; setErrColor: #d84d4d; setErrHeight: 30px; setErrFont: font(fsize); -setGoodColor: #008000; +setGoodColor: #4ab44a; setBackgroundSize: 120px; @@ -1324,28 +1350,35 @@ layerSlideDuration: 200; layerHideDuration: 200; layerPadding: margins(10px, 10px, 10px, 10px); -boxFont: font(16px); -boxVerticalMargin: 10px; - -boxBG: white; -boxGrayTitle: #777; - -old_boxTitlePos: point(20px, 15px); -old_boxTitleFont: font(17px); -old_boxTitleHeight: 52px; - -confirmMaxHeight: 320px; -confirmCompressedSkip: 10px; -addContactPadding: margins(18px, 24px, 18px, 24px); -addContactSkip: 14px; -inpAddContact: flatInput(inpDefGray) { - height: 42px; - textMrg: margins(10px, 5px, 10px, 5px); - font: font(15px); -} +contactPadding: margins(49px, 22px, 0px, 6px); +contactSkip: 13px; +contactPhoneSkip: 30px; contactUserIcon: sprite(120px, 90px, 18px, 18px); contactPhoneIcon: sprite(138px, 90px, 18px, 18px); -contactAddIcon: sprite(307px, 248px, 22px, 16px); +contactIconTop: 10px; + +contactsPhotoSize: 42px; +contactsPadding: margins(16px, 7px, 16px, 7px); +contactsNameTop: 2px; +contactsNameFont: font(fsize semibold); +contactsStatusTop: 23px; +contactsStatusFont: font(fsize); +contactsStatusFg: #999999; +contactsStatusFgOver: #7c99b2; +contactsStatusFgOnline: #3b8dcc; +contactsBgOver: #f5f8fa; +contactsBgActive: #6f9cbd; +contactsCheckPosition: point(8px, 16px); +contactsCheckIcon: sprite(187px, 61px, 18px, 14px); +contactsCheckActiveIcon: sprite(187px, 75px, 18px, 14px); +contactsNewItemHeight: 53px; +contactsNewItemIcon: sprite(307px, 248px, 22px, 16px); +contactsNewItemIconPosition: point(29px, 19px); +contactsNewItemTop: 18px; +contactsNewItemFg: #4b82af; +contactsScroll: flatScroll(boxScroll) { + deltab: 0px; +} btnNewGroup: iconedButton(btnDefIconed) { icon: sprite(189px, 118px, 18px, 17px); @@ -1397,8 +1430,19 @@ notifyHeight: 80px; notifyDeltaX: 6px; notifyDeltaY: 7px; +boxPhotoPadding: margins(28px, 28px, 28px, 18px); +boxPhotoCompressedPadding: margins(0px, 2px, 0px, 22px); +boxPhotoTextFg: #808080; cropPointSize: 10px; +cropSkip: 13px; cropMinSize: 20px; +confirmCaptionArea: InputArea(defaultInputArea) { + textMargins: margins(1px, 6px, 1px, 4px); + heightMax: 56px; +} +confirmBg: #f2f2f2; +confirmMaxHeight: 245px; +confirmCompressedSkip: 10px; profileMaxWidth: 410px; profilePadding: margins(28px, 30px, 28px, 0px); @@ -1427,8 +1471,6 @@ profileListStatusBottom: 6px; profileHoverBG: #f5f5f5; profileActiveBG: #6294b9; profileSubFont: font(fsize); -profileCheckDeltaX: 18px; -profileCheckDeltaY: 1px; profileListNameFont: font(fsize semibold); profileListNameColor: #000; profileOnlineColor: titleTypingColor; @@ -1445,8 +1487,6 @@ btnShareContact: flatButton(btnDefNext, btnDefBig) { overFont: font(17px); } profileMinBtnPadding: 10px; -inviteCheckIcon: sprite(187px, 61px, 18px, 14px); -inviteCheckActiveIcon: sprite(187px, 75px, 18px, 14px); membersPadding: margins(0px, 10px, 0px, 10px); @@ -1497,14 +1537,6 @@ profileNameInput: flatInput(setNameInput) { width: 230px; } -boxScroll: flatScroll(scrollDef) { - topsh: -2px; - bottomsh: -2px; -} -boxNoTopScroll: flatScroll(boxScroll) { - topsh: 0; -} - participantInnerAdd: flatButton(btnDefNext) { width: 145px; height: 40px; @@ -1538,8 +1570,6 @@ contactsFilter: flatInput(dlgFilter) { inpCountry: flatInput(contactsFilter) { } -old_newGroupNamePadding: margins(12px, 15px, 12px, 13px); - newGroupLimitFg: #a4a4a4; newGroupAboutFg: #808080; newGroupPadding: margins(4px, 6px, 4px, 3px); @@ -1547,10 +1577,10 @@ newGroupSkip: 17px; newGroupInfoPadding: margins(0px, -4px, 0px, 1px); newGroupLink: InputField(defaultInputField) { - textMargins: margins(0px, 6px, 0px, 4px); + textMargins: margins(0px, 6px, 0px, 0px); } -newGroupLinkPadding: margins(4px, 27px, 4px, 27px); -newGroupLinkTop: -3px; +newGroupLinkPadding: margins(4px, 27px, 4px, 12px); +newGroupLinkTop: 3px; newGroupLinkFont: font(16px); newGroupPhotoSize: 76px; @@ -1561,7 +1591,7 @@ newGroupPhotoIconPosition: point(23px, 25px); newGroupNamePosition: point(27px, 20px); newGroupName: InputField(defaultInputField) { - textMargins: margins(1px, 6px, 1px, 4px); + textMargins: margins(1px, 6px, 1px, 0px); } newGroupDescriptionPadding: margins(0px, 23px, 0px, 14px); @@ -1587,26 +1617,6 @@ connectionPasswordInputField: InputField(defaultInputField) { } connectionIPv6Skip: 11px; -contactsClose: flatButton { - color: btnYesColor; - overColor: btnYesHover; - downColor: btnYesHover; - - bgColor: white; - overBgColor: white; - downBgColor: white; - - width: 364px; - height: 46px; - - textTop: 12px; - overTextTop: 12px; - downTextTop: 13px; - - font: font(16px); - overFont: font(16px); -} -contactsImg: sprite(31px, 104px, 9px, 16px); contactsAdd: flatButton(topBarButton) { width: -40px; height: 52px; @@ -1639,21 +1649,34 @@ aboutLabel: flatLabel(labelDefFlat) { aboutTextStyle: textStyle(defaultTextStyle) { lineHeight: 24px; } -aboutCloseButton: flatButton(contactsClose) { +aboutCloseButton: flatButton { + color: btnYesColor; + overColor: btnYesHover; + downColor: btnYesHover; + + bgColor: white; + overBgColor: white; + downBgColor: white; + width: aboutWidth; height: 52px; + textTop: 15px; overTextTop: 15px; downTextTop: 16px; + + font: font(16px); + overFont: font(16px); } btnInfoClose: flatButton(aboutCloseButton) { width: boxWideWidth; } -emojiTextFont: font(16px); -emojiReplaceWidth: 56px; +emojiTextFont: font(15px); +emojiReplaceWidth: 52px; emojiReplaceHeight: 56px; emojiReplaceInnerHeight: 42px; +emojiReplacePadding: 14px; connectingBG: #fffe; connectingColor: #777; @@ -1732,54 +1755,16 @@ dpiFont2: linkFont; dpiFont3: linkFont; dpiFont4: linkFont; -newScroll: flatScroll(scrollDef) { - barColor: #3f729734; - bgColor: #214f751a; - barOverColor: #3f729734; - bgOverColor: #214f751a; - - deltax: 5px; - width: 14px; - deltat: 6px; - deltab: 6px; - - topsh: 0px; - bottomsh: 0px; - - hiding: 0; -} - -stickersMaxHeight: 340px; -stickersAddOrShare: 70px; -btnStickersAdd: flatButton(btnDefNext, btnDefBig) { - width: 200px; - height: 42px; - - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; - - font: font(17px); - overFont: font(17px); - - bgColor: #15c23c; - overBgColor: #13a835; - downBgColor: #13a835; -} -btnStickersClose: iconedButton(notifyClose) { - iconPos: point(21px, 21px); - downIconPos: point(21px, 22px); - width: 52px; - height: 48px; -} -stickersWidth: 344px; -stickersPadding: 10px; +stickersMaxHeight: 440px; +stickersPadding: margins(19px, 17px, 19px, 17px); stickersSize: size(64px, 64px); -stickersScroll: flatScroll(newScroll) { - deltab: 76px; +stickersScroll: flatScroll(boxScroll) { + deltax: 7px; + deltat: 23px; + deltab: 9px; } -emojiScroll: flatScroll(newScroll) { +emojiScroll: flatScroll(solidScroll) { deltat: 48px; } emojiRecentOver: sprite(0px, 196px, 21px, 22px); @@ -1945,7 +1930,7 @@ botKbTinyButton: botKeyboardButton { textTop: 2px; downTextTop: 3px; } -botKbScroll: flatScroll(newScroll) { +botKbScroll: flatScroll(solidScroll) { deltax: 3px; width: 10px; } @@ -2150,6 +2135,12 @@ langsButton: Radiobutton(defaultRadiobutton) { backgroundPadding: 10px; backgroundSize: size(108px, 193px); +backgroundScroll: flatScroll(boxScroll) { + width: 10px; + deltax: 3px; + deltat: 10px; + deltab: 0px; +} passcodeHeaderFont: font(19px); passcodeHeaderHeight: 80px; diff --git a/Telegram/Resources/style_classes.txt b/Telegram/Resources/style_classes.txt index 567967127..6249be85b 100644 --- a/Telegram/Resources/style_classes.txt +++ b/Telegram/Resources/style_classes.txt @@ -198,27 +198,6 @@ countryInput { align: align; } -countryList { - notFoundColor: color; - notFoundFont: font; - - verticalMargin: number; - - font: font; - codeFont: font; - rowHeight: number; - color: color; - codeColor: color; - bgColor: color; - bgHovered: color; - margin: number; - codeWidth: number; - - borderMargin: number; - borderColor: color; - borderWidth: number; -} - slider { color: color; thikness: number; diff --git a/Telegram/SourceFiles/_other/genstyles.cpp b/Telegram/SourceFiles/_other/genstyles.cpp index edaac4260..8c775a82a 100644 --- a/Telegram/SourceFiles/_other/genstyles.cpp +++ b/Telegram/SourceFiles/_other/genstyles.cpp @@ -1965,7 +1965,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org\n\ while (!already.isEmpty() && (already.size() > k.size() || !already.endsWith(k.at(already.size() - 1)))) { if (!onlyLastChanged) { tnum << QString("\t").repeated(1 + already.size()) << "}\n"; - tnum << QString("\t").repeated(1 + already.size()) << "return result;\n"; + tnum << QString("\t").repeated(already.size()) << "break;\n"; } already = already.mid(0, already.size() - 1); onlyLastChanged = false; diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png index 8a40fcf6b..edd61be47 100644 Binary files a/Telegram/SourceFiles/art/sprite.png and b/Telegram/SourceFiles/art/sprite.png differ diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index 00d1e2322..2513dd212 100644 Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index c3ff1ac59..d7b8acf07 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -27,7 +27,62 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "window.h" -AbstractBox::AbstractBox(int32 w) : _maxHeight(0), _hiding(false), a_opacity(0, 1) { +void BlueTitleShadow::paintEvent(QPaintEvent *e) { + Painter p(this); + + QRect r(e->rect()); + p.drawPixmap(QRect(r.left(), 0, r.width(), height()), App::sprite(), st::boxBlueShadow); +} + +BlueTitleClose::BlueTitleClose(QWidget *parent) : Button(parent) +, a_iconFg(st::boxBlueCloseBg->c) +, _a_over(animFunc(this, &BlueTitleClose::animStep_over)) { + resize(st::boxTitleHeight, st::boxTitleHeight); + setCursor(style::cur_pointer); + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); +} + +void BlueTitleClose::onStateChange(int oldState, ButtonStateChangeSource source) { + if ((oldState & StateOver) != (_state & StateOver)) { + a_iconFg.start(((_state & StateOver) ? st::white : st::boxBlueCloseBg)->c); + _a_over.start(); + } +} + +bool BlueTitleClose::animStep_over(float64 ms) { + float64 dt = ms / st::boxBlueCloseDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_iconFg.finish(); + } else { + a_iconFg.update(dt, anim::linear); + } + update((st::boxTitleHeight - st::boxBlueCloseIcon.pxWidth()) / 2, (st::boxTitleHeight - st::boxBlueCloseIcon.pxHeight()) / 2, st::boxBlueCloseIcon.pxWidth(), st::boxBlueCloseIcon.pxHeight()); + return res; + +} + +void BlueTitleClose::paintEvent(QPaintEvent *e) { + Painter p(this); + + QRect r(e->rect()), s((st::boxTitleHeight - st::boxBlueCloseIcon.pxWidth()) / 2, (st::boxTitleHeight - st::boxBlueCloseIcon.pxHeight()) / 2, st::boxBlueCloseIcon.pxWidth(), st::boxBlueCloseIcon.pxHeight()); + if (!s.contains(r)) { + p.fillRect(r, st::boxBlueTitleBg->b); + } + if (s.intersects(r)) { + p.fillRect(s.intersected(r), a_iconFg.current()); + p.drawSprite(s.topLeft(), st::boxBlueCloseIcon); + } +} + +AbstractBox::AbstractBox(int32 w) : LayeredWidget() +, _maxHeight(0) +, _hiding(false) +, a_opacity(0, 1) +, _blueTitle(false) +, _blueClose(0) +, _blueShadow(0) { resize(w, 0); } @@ -45,6 +100,16 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) { } } +void AbstractBox::resizeEvent(QResizeEvent *e) { + if (_blueClose) { + _blueClose->moveToRight(0, 0); + } + if (_blueShadow) { + _blueShadow->moveToLeft(0, st::boxTitleHeight); + _blueShadow->resize(width(), st::boxBlueShadow.pxHeight()); + } +} + void AbstractBox::parentResized() { int32 newHeight = countHeight(); setGeometry((App::wnd()->width() - width()) / 2, (App::wnd()->height() - newHeight) / 2, width(), newHeight); @@ -57,7 +122,7 @@ bool AbstractBox::paint(QPainter &p) { result = (_hiding && a_opacity.current() < 0.01); // fill bg - p.fillRect(rect(), st::boxBG->b); + p.fillRect(rect(), st::boxBg->b); } else { p.setOpacity(a_opacity.current()); p.drawPixmap(0, 0, _cache); @@ -65,48 +130,26 @@ bool AbstractBox::paint(QPainter &p) { return result; } -void AbstractBox::paintOldTitle(Painter &p, const QString &title, bool withShadow) { - if (withShadow) { - // paint shadow - p.fillRect(0, st::old_boxTitleHeight, width(), st::scrollDef.topsh, st::scrollDef.shColor->b); - } - - // paint box title - p.setFont(st::old_boxTitleFont->f); - p.setPen(st::black->p); - p.drawTextLeft(st::old_boxTitlePos.x(), st::old_boxTitlePos.y(), width(), title); -} - -void AbstractBox::paintTitle(Painter &p, const QString &title) { - // paint box title +void AbstractBox::paintTitle(Painter &p, const QString &title, const QString &additional) { p.setFont(st::boxTitleFont); - p.setPen(st::black); - p.drawTextLeft(st::boxTitlePosition.x(), st::boxTitlePosition.y(), width(), title); -} + if (_blueTitle) { + p.fillRect(0, 0, width(), st::boxTitleHeight, st::boxBlueTitleBg->b); + p.setPen(st::white); -void AbstractBox::paintBlueTitle(Painter &p, const QString &title, const QString &additional) { - // paint box title - p.fillRect(0, 0, width(), st::boxBlueTitleHeight, st::boxBlueTitleBg->b); - p.setFont(st::boxTitleFont); - p.setPen(st::white); + int32 titleWidth = st::boxTitleFont->width(title); + p.drawTextLeft(st::boxBlueTitlePosition.x(), st::boxBlueTitlePosition.y(), width(), title, titleWidth); - int32 titleWidth = st::boxTitleFont->width(title); - p.drawTextLeft(st::boxBlueTitlePosition.x(), st::boxBlueTitlePosition.y(), width(), title, titleWidth); - - if (!additional.isEmpty()) { - p.setFont(st::boxTextFont); - p.setPen(st::boxBlueTitleAdditionalFg); - p.drawTextLeft(st::boxBlueTitlePosition.x() + titleWidth + st::boxBlueTitleAdditionalSkip, st::boxBlueTitlePosition.y(), width(), additional); + if (!additional.isEmpty()) { + p.setFont(st::boxTextFont); + p.setPen(st::boxBlueTitleAdditionalFg); + p.drawTextLeft(st::boxBlueTitlePosition.x() + titleWidth + st::boxBlueTitleAdditionalSkip, st::boxBlueTitlePosition.y(), width(), additional); + } + } else { + p.setPen(st::boxTitleFg); + p.drawTextLeft(st::boxTitlePosition.x(), st::boxTitlePosition.y(), width(), title); } } -void AbstractBox::paintGrayTitle(QPainter &p, const QString &title) { - // draw box title - p.setFont(st::boxFont->f); - p.setPen(st::boxGrayTitle->p); - p.drawText(QRect(st::old_boxTitlePos.x(), st::old_boxTitlePos.y(), width() - 2 * st::old_boxTitlePos.x(), st::boxFont->height), title, style::al_top); -} - void AbstractBox::paintEvent(QPaintEvent *e) { QPainter p(this); if (paint(p)) return; @@ -159,12 +202,35 @@ void AbstractBox::startHide() { setAttribute(Qt::WA_OpaquePaintEvent, false); } -ScrollableBox::ScrollableBox(const style::flatScroll &scroll) : AbstractBox(), -_scroll(this, scroll), _innerPtr(0), _topSkip(st::old_boxTitleHeight), _bottomSkip(0) { +void AbstractBox::setBlueTitle(bool blue) { + _blueTitle = blue; + delete _blueShadow; + _blueShadow = new BlueTitleShadow(this); + delete _blueClose; + _blueClose = new BlueTitleClose(this); + _blueClose->setAttribute(Qt::WA_OpaquePaintEvent); + connect(_blueClose, SIGNAL(clicked()), this, SLOT(onClose())); +} + +void AbstractBox::raiseShadow() { + if (_blueShadow) { + _blueShadow->raise(); + } +} + +void ScrollableBoxShadow::paintEvent(QPaintEvent *e) { + Painter p(this); + p.fillRect(e->rect(), st::boxScrollShadowBg->b); +} + +ScrollableBox::ScrollableBox(const style::flatScroll &scroll, int32 w) : AbstractBox(w), +_scroll(this, scroll), _innerPtr(0), _topSkip(st::boxTitleHeight), _bottomSkip(st::boxScrollSkip) { + setBlueTitle(true); } void ScrollableBox::resizeEvent(QResizeEvent *e) { _scroll.setGeometry(0, _topSkip, width(), height() - _topSkip - _bottomSkip); + AbstractBox::resizeEvent(e); } void ScrollableBox::init(QWidget *inner, int32 bottomSkip, int32 topSkip) { @@ -178,12 +244,14 @@ void ScrollableBox::init(QWidget *inner, int32 bottomSkip, int32 topSkip) { void ScrollableBox::hideAll() { _scroll.hide(); + AbstractBox::hideAll(); } void ScrollableBox::showAll() { _scroll.show(); + AbstractBox::showAll(); } -ItemListBox::ItemListBox(const style::flatScroll &scroll) : ScrollableBox(scroll) { +ItemListBox::ItemListBox(const style::flatScroll &scroll, int32 w) : ScrollableBox(scroll, w) { setMaxHeight(st::boxMaxListHeight); } diff --git a/Telegram/SourceFiles/boxes/abstractbox.h b/Telegram/SourceFiles/boxes/abstractbox.h index d2306587f..5de24cc00 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.h +++ b/Telegram/SourceFiles/boxes/abstractbox.h @@ -22,6 +22,31 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "layerwidget.h" +class BlueTitleShadow : public TWidget { +public: + BlueTitleShadow(QWidget *parent) : TWidget(parent) { + } + void paintEvent(QPaintEvent *e); +}; + +class BlueTitleClose : public Button { + Q_OBJECT + +public: + BlueTitleClose(QWidget *parent); + void paintEvent(QPaintEvent *e); + +public slots: + + void onStateChange(int oldState, ButtonStateChangeSource source); + +private: + bool animStep_over(float64 ms); + anim::cvalue a_iconFg; + Animation _a_over; + +}; + class AbstractBox : public LayeredWidget { Q_OBJECT @@ -31,8 +56,12 @@ public: void parentResized(); void animStep(float64 ms); void keyPressEvent(QKeyEvent *e); + void resizeEvent(QResizeEvent *e); void paintEvent(QPaintEvent *e); void startHide(); + + void setBlueTitle(bool blue); + void raiseShadow(); public slots: @@ -42,18 +71,19 @@ protected: void prepare(); bool paint(QPainter &p); - void paintTitle(Painter &p, const QString &title); - void paintBlueTitle(Painter &p, const QString &title, const QString &additional = QString()); - void paintOldTitle(Painter &p, const QString &title, bool withShadow); - void paintGrayTitle(QPainter &p, const QString &title); + void paintTitle(Painter &p, const QString &title, const QString &additional = QString()); void setMaxHeight(int32 maxHeight); void resizeMaxHeight(int32 newWidth, int32 maxHeight); virtual void closePressed() { } virtual void hideAll() { + if (_blueClose) _blueClose->hide(); + if (_blueShadow) _blueShadow->hide(); } virtual void showAll() { + if (_blueClose) _blueClose->show(); + if (_blueShadow) _blueShadow->show(); } virtual void showDone() { setFocus(); @@ -68,17 +98,28 @@ private: QPixmap _cache; anim::fvalue a_opacity; + + bool _blueTitle; + BlueTitleClose *_blueClose; + BlueTitleShadow *_blueShadow; +}; + +class ScrollableBoxShadow : public TWidget { +public: + ScrollableBoxShadow(QWidget *parent) : TWidget(parent) { + } + void paintEvent(QPaintEvent *e); }; class ScrollableBox : public AbstractBox { public: - ScrollableBox(const style::flatScroll &scroll); + ScrollableBox(const style::flatScroll &scroll, int32 w = st::boxWideWidth); void resizeEvent(QResizeEvent *e); protected: - void init(QWidget *inner, int32 bottomSkip = 0, int32 topSkip = st::old_boxTitleHeight); + void init(QWidget *inner, int32 bottomSkip = st::boxScrollSkip, int32 topSkip = st::boxTitleHeight); virtual void hideAll(); virtual void showAll(); @@ -95,6 +136,12 @@ private: class ItemListBox : public ScrollableBox { public: - ItemListBox(const style::flatScroll &scroll); + ItemListBox(const style::flatScroll &scroll, int32 w = st::boxWideWidth); }; + +enum CreatingGroupType { + CreatingGroupNone, + CreatingGroupGroup, + CreatingGroupChannel, +}; diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 9fff7163c..fc6a4f6a6 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -24,142 +24,91 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "application.h" #include "addcontactbox.h" #include "contactsbox.h" +#include "confirmbox.h" +#include "photocropbox.h" +#include "gui/filedialog.h" #include "mainwidget.h" #include "window.h" -AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : - _peer(0), - _addButton(this, lang(lng_add_contact), st::btnSelectDone), - _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), - _cancelButton(this, lang(lng_box_cancel), st::btnSelectCancel), - _firstInput(this, st::inpAddContact, lang(lng_signup_firstname), fname), - _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), lname), - _phoneInput(this, st::inpAddContact, lang(lng_contact_phone), phone.isEmpty() ? phone : App::formatPhone(phone)), - _invertOrder(langFirstNameGoesSecond()), - _contactId(0), _addRequest(0) { - +AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth) +, _user(0) +, _save(this, lang(lng_add_contact), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _retry(this, lang(lng_try_other_contact), st::defaultBoxButton) +, _first(this, st::defaultInputField, lang(lng_signup_firstname), fname) +, _last(this, st::defaultInputField, lang(lng_signup_lastname), lname) +, _phone(this, st::defaultInputField, lang(lng_contact_phone), phone) +, _invertOrder(langFirstNameGoesSecond()) +, _contactId(0) +, _addRequest(0) { if (!phone.isEmpty()) { - _phoneInput.setDisabled(true); + _phone.setDisabled(true); } initBox(); } -AddContactBox::AddContactBox(PeerData *peer) : - _peer(peer), - _addButton(this, lang(lng_settings_save), st::btnSelectDone), - _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), - _cancelButton(this, lang(lng_box_cancel), st::btnSelectCancel), - _firstInput(this, st::inpAddContact, lang(peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), peer->isUser() ? peer->asUser()->firstName : peer->name), - _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()), - _phoneInput(this, st::inpAddContact, lang(lng_contact_phone)), - _invertOrder((!peer || !peer->isChat()) && langFirstNameGoesSecond()), - _contactId(0), _addRequest(0) { - +AddContactBox::AddContactBox(UserData *user) : AbstractBox(st::boxWidth) +, _user(user) +, _save(this, lang(lng_settings_save), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _retry(this, lang(lng_try_other_contact), st::defaultBoxButton) +, _first(this, st::defaultInputField, lang(lng_signup_firstname), user->firstName) +, _last(this, st::defaultInputField, lang(lng_signup_lastname), user->lastName) +, _phone(this, st::defaultInputField, lang(lng_contact_phone), user->phone) +, _invertOrder(langFirstNameGoesSecond()) +, _contactId(0) +, _addRequest(0) { + _phone.setDisabled(true); initBox(); } void AddContactBox::initBox() { if (_invertOrder) { - setTabOrder(&_lastInput, &_firstInput); + setTabOrder(&_last, &_first); } - if (_peer) { - if (_peer->isUser()) { - _boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _firstInput.height() + 1 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); - } else if (_peer->isChat()) { - _boxTitle = lang(lng_edit_group_title); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height()); - } + if (_user) { + _boxTitle = lang(lng_edit_contact_title); } else { - bool readyToAdd = !_phoneInput.text().isEmpty() && (!_firstInput.text().isEmpty() || !_lastInput.text().isEmpty()); + bool readyToAdd = !_phone.getLastText().isEmpty() && (!_first.getLastText().isEmpty() || !_last.getLastText().isEmpty()); _boxTitle = lang(readyToAdd ? lng_confirm_contact_data : lng_enter_contact_data); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); } - _retryButton.hide(); + setMaxHeight(st::boxTitleHeight + st::contactPadding.top() + _first.height() + st::contactSkip + _last.height() + st::contactPhoneSkip + _phone.height() + st::contactPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + _retry.hide(); - connect(&_addButton, SIGNAL(clicked()), this, SLOT(onSend())); - connect(&_retryButton, SIGNAL(clicked()), this, SLOT(onRetry())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_retry, SIGNAL(clicked()), this, SLOT(onRetry())); + + connect(&_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_phone, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); prepare(); } void AddContactBox::hideAll() { - _firstInput.hide(); - _lastInput.hide(); - _phoneInput.hide(); - _addButton.hide(); - _retryButton.hide(); - _cancelButton.hide(); + _first.hide(); + _last.hide(); + _phone.hide(); + _save.hide(); + _cancel.hide(); + _retry.hide(); } void AddContactBox::showAll() { - _firstInput.show(); - if (_peer && (_peer->isChat() || _peer->isChannel())) { - _lastInput.hide(); - } else { - _lastInput.show(); - } - if (_peer) { - _phoneInput.hide(); - } else { - _phoneInput.show(); - } - _addButton.show(); - _cancelButton.show(); + _first.show(); + _last.show(); + _phone.show(); + _save.show(); + _cancel.show(); } void AddContactBox::showDone() { - if ((_firstInput.text().isEmpty() && _lastInput.text().isEmpty()) || _phoneInput.isHidden() || !_phoneInput.isEnabled()) { - (_invertOrder ? _lastInput : _firstInput).setFocus(); + if ((_first.getLastText().isEmpty() && _last.getLastText().isEmpty()) || !_phone.isEnabled()) { + (_invertOrder ? _last : _first).setFocus(); } else { - _phoneInput.setFocus(); - } -} - -void AddContactBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - if (_firstInput.hasFocus()) { - if (_peer && (_peer->isChat() || _peer->isChannel())) { - if (_firstInput.text().trimmed().isEmpty()) { - _firstInput.setFocus(); - _firstInput.notaBene(); - } else { - onSend(); - } - } else { - _lastInput.setFocus(); - } - } else if (_lastInput.hasFocus()) { - if (_peer) { - if (_firstInput.text().trimmed().isEmpty()) { - _firstInput.setFocus(); - _firstInput.notaBene(); - } else if (_lastInput.text().trimmed().isEmpty()) { - _lastInput.setFocus(); - _lastInput.notaBene(); - } else { - onSend(); - } - } else if (_phoneInput.isEnabled()) { - _phoneInput.setFocus(); - } else { - onSend(); - } - } else if (_phoneInput.hasFocus()) { - if (_firstInput.text().trimmed().isEmpty()) { - _firstInput.setFocus(); - _firstInput.notaBene(); - } else if (_lastInput.text().trimmed().isEmpty()) { - _lastInput.setFocus(); - _lastInput.notaBene(); - } else { - onSend(); - } - } - } else { - AbstractBox::keyPressEvent(e); + _phone.setFocus(); } } @@ -167,55 +116,68 @@ void AddContactBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - if (_retryButton.isHidden()) { - paintOldTitle(p, _boxTitle, true); + paintTitle(p, _boxTitle); + + if (_retry.isHidden()) { + p.drawSpriteLeft(st::boxPadding.left(), _first.y() + st::contactIconTop, width(), st::contactUserIcon); + p.drawSpriteLeft(st::boxPadding.left(), _phone.y() + st::contactIconTop, width(), st::contactPhoneIcon); } else { - // draw box text p.setPen(st::black->p); - p.setFont(st::old_boxTitleFont->f); - int32 h = size().height() - st::boxPadding.top() * 2 - _retryButton.height() - st::boxPadding.bottom(); - p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), h), lng_contact_not_joined(lt_name, _sentName), style::al_topleft); + p.setFont(st::boxTextFont->f); + int32 h = height() - st::boxTitleHeight - st::contactPadding.top() - st::contactPadding.bottom() - st::boxPadding.bottom() - st::boxButtonPadding.top() - _retry.height() - st::boxButtonPadding.bottom(); + p.drawText(QRect(st::boxPadding.left(), st::boxTitleHeight + st::contactPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), h), lng_contact_not_joined(lt_name, _sentName), style::al_topleft); } - - // paint shadows - p.fillRect(0, size().height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void AddContactBox::resizeEvent(QResizeEvent *e) { + _first.resize(width() - st::boxPadding.left() - st::contactPadding.left() - st::boxPadding.right(), _first.height()); + _last.resize(_first.width(), _last.height()); + _phone.resize(_first.width(), _last.height()); if (_invertOrder) { - _lastInput.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _lastInput.height()); - _firstInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); - _phoneInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); + _last.moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::boxTitleHeight + st::contactPadding.top()); + _first.moveToLeft(_last.x(), _last.y() + _last.height() + st::contactSkip); + _phone.moveToLeft(_first.x(), _first.y() + _first.height() + st::contactPhoneSkip); } else { - _firstInput.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height()); - _lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactSkip, _firstInput.width(), _firstInput.height()); - _phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); + _first.moveToLeft(st::boxPadding.left() + st::contactPadding.left(), st::boxTitleHeight + st::contactPadding.top()); + _last.moveToLeft(_first.x(), _first.y() + _first.height() + st::contactSkip); + _phone.moveToLeft(_last.x(), _last.y() + _last.height() + st::contactPhoneSkip); } - _cancelButton.move(0, height() - _cancelButton.height()); - _addButton.move(width() - _addButton.width(), height() - _addButton.height()); - _retryButton.move(width() - _retryButton.width(), height() - _retryButton.height()); + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _retry.moveToRight(st::boxButtonPadding.right(), _save.y()); + _cancel.moveToRight(st::boxButtonPadding.right() + (_retry.isHidden() ? _save.width() : _retry.width()) + st::boxButtonPadding.left(), _save.y()); } -void AddContactBox::onSend() { +void AddContactBox::onSubmit() { + if (_first.hasFocus()) { + _last.setFocus(); + } else if (_last.hasFocus()) { + if (_phone.isEnabled()) { + _phone.setFocus(); + } else { + onSave(); + } + } else if (_phone.hasFocus()) { + onSave(); + } +} + +void AddContactBox::onSave() { if (_addRequest) return; - QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(), phone = _phoneInput.text().trimmed(); + QString firstName = _first.getLastText().trimmed(), lastName = _last.getLastText().trimmed(), phone = _phone.getLastText().trimmed(); if (firstName.isEmpty() && lastName.isEmpty()) { if (_invertOrder) { - _lastInput.setFocus(); - _lastInput.notaBene(); + _last.setFocus(); + _last.showError(); } else { - _firstInput.setFocus(); - _firstInput.notaBene(); + _first.setFocus(); + _first.showError(); } return; - } else if (!_peer && !App::isValidPhone(phone)) { - _phoneInput.setFocus(); - _phoneInput.notaBene(); + } else if (!_user && !App::isValidPhone(phone)) { + _phone.setFocus(); + _phone.showError(); return; } if (firstName.isEmpty()) { @@ -223,16 +185,10 @@ void AddContactBox::onSend() { lastName = QString(); } _sentName = firstName; - if (_peer == App::self()) { - _addRequest = MTP::send(MTPaccount_UpdateProfile(MTP_string(firstName), MTP_string(lastName)), rpcDone(&AddContactBox::onSaveSelfDone), rpcFail(&AddContactBox::onSaveSelfFail)); - } else if (_peer) { - if (_peer->isChat()) { - _addRequest = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(firstName)), rpcDone(&AddContactBox::onSaveChatDone), rpcFail(&AddContactBox::onSaveFail)); - } else { - _contactId = MTP::nonce(); - QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_peer->asUser()->phone), MTP_string(firstName), MTP_string(lastName))); - _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveFail)); - } + if (_user) { + _contactId = MTP::nonce(); + QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone), MTP_string(firstName), MTP_string(lastName))); + _addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail)); } else { _contactId = MTP::nonce(); QVector v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), MTP_string(firstName), MTP_string(lastName))); @@ -240,49 +196,22 @@ void AddContactBox::onSend() { } } -void AddContactBox::onSaveSelfDone(const MTPUser &user) { - App::feedUsers(MTP_vector(1, user)); - emit closed(); -} - -bool AddContactBox::onSaveSelfFail(const RPCError &error) { - if (mtpIsFlood(error)) return false; - - QString err(error.type()); - QString firstName = textOneLine(_firstInput.text()), lastName = textOneLine(_lastInput.text()); - if (err == "NAME_NOT_MODIFIED") { - App::self()->setName(firstName, lastName, QString(), textOneLine(App::self()->username)); - emit closed(); - return true; - } else if (err == "FIRSTNAME_INVALID") { - _firstInput.setFocus(); - _firstInput.notaBene(); - return true; - } else if (err == "LASTNAME_INVALID") { - _lastInput.setFocus(); - _lastInput.notaBene(); - return true; - } - _firstInput.setFocus(); - return true; -} - -bool AddContactBox::onSaveFail(const RPCError &error) { +bool AddContactBox::onSaveUserFail(const RPCError &error) { if (mtpIsFlood(error)) return false; _addRequest = 0; QString err(error.type()); - QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(); + QString firstName = _first.getLastText().trimmed(), lastName = _last.getLastText().trimmed(); if (err == "CHAT_TITLE_NOT_MODIFIED") { - _peer->updateName(firstName, QString(), QString()); + _user->updateName(firstName, QString(), QString()); emit closed(); return true; } else if (err == "NO_CHAT_TITLE") { - _firstInput.setFocus(); - _firstInput.notaBene(); + _first.setFocus(); + _first.showError(); return true; } - _firstInput.setFocus(); + _first.setFocus(); return true; } @@ -307,23 +236,16 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) { App::main()->addNewContact(uid); App::wnd()->hideLayer(); } else { - _addButton.hide(); - _firstInput.hide(); - _lastInput.hide(); - _phoneInput.hide(); - _retryButton.show(); - int32 theight = st::old_boxTitleFont->m.boundingRect(0, 0, width() - st::boxPadding.left() - st::boxPadding.right(), 1, Qt::TextWordWrap, lng_contact_not_joined(lt_name, _sentName)).height(); - int32 h = st::boxPadding.top() * 2 + theight + _retryButton.height() + st::boxPadding.bottom(); - setMaxHeight(h); + _save.hide(); + _first.hide(); + _last.hide(); + _phone.hide(); + _retry.show(); + resizeEvent(0); update(); } } -void AddContactBox::onSaveChatDone(const MTPUpdates &updates) { - App::main()->sentUpdatesReceived(updates); - emit closed(); -} - void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) { const MTPDcontacts_importedContacts &d(res.c_contacts_importedContacts()); App::feedUsers(d.vusers); @@ -333,26 +255,728 @@ void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) { void AddContactBox::onRetry() { _addRequest = 0; _contactId = 0; - _addButton.show(); - _cancelButton.move(_cancelButton.x(), _addButton.y()); + _save.show(); + _retry.hide(); + resizeEvent(0); showAll(); - _firstInput.setText(QString()); - _firstInput.updatePlaceholder(); - _lastInput.setText(QString()); - _lastInput.updatePlaceholder(); - _phoneInput.setText(QString()); - _phoneInput.updatePlaceholder(); - _phoneInput.setDisabled(false); - _retryButton.hide(); - _firstInput.setFocus(); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); + _first.setText(QString()); + _first.updatePlaceholder(); + _last.setText(QString()); + _last.updatePlaceholder(); + _phone.clearText(); + _phone.setDisabled(false); + _first.setFocus(); update(); } +NewGroupBox::NewGroupBox() : AbstractBox(), +_group(this, qsl("group_type"), 0, lang(lng_create_group_title), true), +_channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)), +_aboutGroupWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()), +_aboutGroup(st::normalFont, lng_create_group_about(lt_count, cMaxGroupCount()), _defaultOptions, _aboutGroupWidth), +_aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth), +_next(this, lang(lng_create_group_next), st::defaultBoxButton), +_cancel(this, lang(lng_cancel), st::cancelBoxButton) { + _aboutGroupHeight = _aboutGroup.countHeight(_aboutGroupWidth); + setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _group.height() + _aboutGroupHeight + st::newGroupSkip + _channel.height() + _aboutChannel.countHeight(_aboutGroupWidth) + st::newGroupPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom()); + + connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + prepare(); +} + +void NewGroupBox::hideAll() { + _group.hide(); + _channel.hide(); + _cancel.hide(); + _next.hide(); +} + +void NewGroupBox::showAll() { + _group.show(); + _channel.show(); + _cancel.show(); + _next.show(); +} + +void NewGroupBox::showDone() { + setFocus(); +} + +void NewGroupBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onNext(); + } else { + AbstractBox::keyPressEvent(e); + } +} + +void NewGroupBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + p.setPen(st::newGroupAboutFg->p); + + QRect aboutGroup = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _group.y() + _group.height() + st::lineWidth, _aboutGroupWidth, _aboutGroupHeight); + _aboutGroup.draw(p, aboutGroup.x(), aboutGroup.y(), aboutGroup.width()); + + QRect aboutChannel = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _channel.y() + _channel.height() + st::lineWidth, _aboutGroupWidth, _aboutGroupHeight); + _aboutChannel.draw(p, aboutChannel.x(), aboutChannel.y(), aboutChannel.width()); +} + +void NewGroupBox::resizeEvent(QResizeEvent *e) { + _group.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); + _channel.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _group.y() + _group.height() + _aboutGroupHeight + st::newGroupSkip); + + _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); +} + +void NewGroupBox::onNext() { + App::wnd()->replaceLayer(new GroupInfoBox(_group.checked() ? CreatingGroupGroup : CreatingGroupChannel, true)); +} + +GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox(), +_creating(creating), +a_photoOver(0, 0), +_a_photoOver(animFunc(this, &GroupInfoBox::animStep_photoOver)), +_photoOver(false), +_title(this, st::newGroupName, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), +_description(this, st::newGroupDescription, lang(lng_create_group_description)), +_next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::defaultBoxButton), +_cancel(this, lang(fromTypeChoose ? lng_create_group_back : lng_cancel), st::cancelBoxButton), +_creationRequestId(0), _createdChannel(0) { + + setMouseTracking(true); + + _title.setMaxLength(MaxGroupChannelTitle); + + _description.setMaxLength(MaxChannelDescription); + _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description.height()); + + updateMaxHeight(); + connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); + connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onNext())); + connect(&_description, SIGNAL(cancelled()), this, SLOT(onClose())); + + connect(&_title, SIGNAL(submitted(bool)), this, SLOT(onNameSubmit())); + + connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + prepare(); +} + +void GroupInfoBox::hideAll() { + _title.hide(); + _description.hide(); + _cancel.hide(); + _next.hide(); +} + +void GroupInfoBox::showAll() { + _title.show(); + if (_creating == CreatingGroupChannel) { + _description.show(); + } else { + _description.hide(); + } + _cancel.show(); + _next.show(); +} + +void GroupInfoBox::showDone() { + _title.setFocus(); +} + +void GroupInfoBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + QRect phRect(photoRect()); + if (phRect.intersects(e->rect())) { + if (_photoSmall.isNull()) { + float64 o = a_photoOver.current(); + if (o > 0) { + if (o < 1) { + QColor c; + c.setRedF(st::newGroupPhotoBg->c.redF() * (1. - o) + st::newGroupPhotoBgOver->c.redF() * o); + c.setGreenF(st::newGroupPhotoBg->c.greenF() * (1. - o) + st::newGroupPhotoBgOver->c.greenF() * o); + c.setBlueF(st::newGroupPhotoBg->c.blueF() * (1. - o) + st::newGroupPhotoBgOver->c.blueF() * o); + p.fillRect(phRect, c); + } else { + p.fillRect(phRect, st::newGroupPhotoBgOver->b); + } + } else { + p.fillRect(phRect, st::newGroupPhotoBg->b); + } + p.drawSprite(phRect.topLeft() + st::newGroupPhotoIconPosition, st::newGroupPhotoIcon); + } else { + p.drawPixmap(phRect.topLeft(), _photoSmall); + } + if (phRect.contains(e->rect())) { + return; + } + } +} + +void GroupInfoBox::resizeEvent(QResizeEvent *e) { + int32 nameLeft = st::newGroupPhotoSize + st::newGroupNamePosition.x(); + _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right() - nameLeft, _title.height()); + _title.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); + + _description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::newGroupDescriptionPadding.top()); + + _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); +} + +void GroupInfoBox::mouseMoveEvent(QMouseEvent *e) { + updateSelected(e->globalPos()); +} + +void GroupInfoBox::updateSelected(const QPoint &cursorGlobalPosition) { + QPoint p(mapFromGlobal(cursorGlobalPosition)); + + bool photoOver = photoRect().contains(p); + if (photoOver != _photoOver) { + _photoOver = photoOver; + if (_photoSmall.isNull()) { + a_photoOver.start(_photoOver ? 1 : 0); + _a_photoOver.start(); + } + } + + setCursor(_photoOver ? style::cur_pointer : style::cur_default); +} + +void GroupInfoBox::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (_photoOver) { + onPhoto(); + } +} + +void GroupInfoBox::leaveEvent(QEvent *e) { + updateSelected(QCursor::pos()); +} + +bool GroupInfoBox::animStep_photoOver(float64 ms) { + float64 dt = ms / st::setPhotoDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_photoOver.finish(); + } else { + a_photoOver.update(dt, anim::linear); + } + update(photoRect()); + return res; +} + +void GroupInfoBox::onNameSubmit() { + if (_title.getLastText().trimmed().isEmpty()) { + _title.setFocus(); + _title.showError(); + } else if (_description.isHidden()) { + onNext(); + } else { + _description.setFocus(); + } +} + +void GroupInfoBox::onNext() { + if (_creationRequestId) return; + + QString title = _title.getLastText().trimmed(); + if (title.isEmpty()) { + _title.setFocus(); + _title.showError(); + return; + } + if (_creating == CreatingGroupGroup) { + App::wnd()->replaceLayer(new ContactsBox(title, _photoBig)); + } else { + _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(title), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); + } +} + +void GroupInfoBox::creationDone(const MTPUpdates &updates) { + App::main()->sentUpdatesReceived(updates); + + const QVector *v = 0; + switch (updates.type()) { + case mtpc_updates: v = &updates.c_updates().vchats.c_vector().v; break; + case mtpc_updatesCombined: v = &updates.c_updatesCombined().vchats.c_vector().v; break; + default: LOG(("API Error: unexpected update cons %1 (GroupInfoBox::creationDone)").arg(updates.type())); break; + } + + ChannelData *channel = 0; + if (v && !v->isEmpty() && v->front().type() == mtpc_channel) { + channel = App::channel(v->front().c_channel().vid.v); + if (channel) { + if (!_photoBig.isNull()) { + App::app()->uploadProfilePhoto(_photoBig, channel->id); + } + _createdChannel = channel; + _creationRequestId = MTP::send(MTPchannels_ExportInvite(_createdChannel->inputChannel), rpcDone(&GroupInfoBox::exportDone)); + return; + } + } else { + LOG(("API Error: channel not found in updates (GroupInfoBox::creationDone)")); + } + + onClose(); +} + +bool GroupInfoBox::creationFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _creationRequestId = 0; + if (error.type() == "NO_CHAT_TITLE") { + _title.setFocus(); + _title.showError(); + return true; + } else if (error.type() == "PEER_FLOOD") { + App::wnd()->replaceLayer(new InformBox(lng_cant_invite_not_contact_channel(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); + return true; + } + return false; +} + +void GroupInfoBox::exportDone(const MTPExportedChatInvite &result) { + _creationRequestId = 0; + if (result.type() == mtpc_chatInviteExported) { + _createdChannel->invitationUrl = qs(result.c_chatInviteExported().vlink); + } + App::wnd()->showLayer(new SetupChannelBox(_createdChannel)); +} + +void GroupInfoBox::onDescriptionResized() { + updateMaxHeight(); + update(); +} + +QRect GroupInfoBox::photoRect() const { + return myrtlrect(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top(), st::newGroupPhotoSize, st::newGroupPhotoSize); +} + +void GroupInfoBox::updateMaxHeight() { + int32 h = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom(); + if (_creating == CreatingGroupChannel) { + h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); + } + setMaxHeight(h); +} + +void GroupInfoBox::onPhoto() { + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } else { + return; + } + + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + return; + } + PhotoCropBox *box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0), false); + connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&))); + App::wnd()->replaceLayer(box); +} + +void GroupInfoBox::onPhotoReady(const QImage &img) { + _photoBig = img; + _photoSmall = QPixmap::fromImage(img.scaled(st::newGroupPhotoSize * cIntRetinaFactor(), st::newGroupPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); + _photoSmall.setDevicePixelRatio(cRetinaFactor()); +} + +SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox(), +_channel(channel), +_existing(existing), +_public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true), +_private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title)), +_comments(this, lang(lng_create_channel_comments), false), +_aboutPublicWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()), +_aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth), +_aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth), +_aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth), +_link(this, st::newGroupLink, QString(), channel->username, true), +_linkOver(false), +_save(this, lang(lng_settings_save), st::defaultBoxButton), +_skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::cancelBoxButton), +_tooMuchUsernames(false), +_saveRequestId(0), _checkRequestId(0), +a_goodOpacity(0, 0), _a_goodFade(animFunc(this, &SetupChannelBox::animStep_goodFade)) { + setMouseTracking(true); + + _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); + + _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); + setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); + _comments.hide(); + + connect(&_link, SIGNAL(changed()), this, SLOT(onChange())); + + _checkTimer.setSingleShot(true); + connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); + + connect(&_public, SIGNAL(changed()), this, SLOT(onPrivacyChange())); + connect(&_private, SIGNAL(changed()), this, SLOT(onPrivacyChange())); + + prepare(); +} + +void SetupChannelBox::hideAll() { + _public.hide(); + _private.hide(); + _comments.hide(); + _link.hide(); + _save.hide(); + _skip.hide(); +} + +void SetupChannelBox::showAll() { + _public.show(); + _private.show(); + //_comments.show(); + if (_public.checked()) { + _link.show(); + } else { + _link.hide(); + } + _save.show(); + _skip.show(); +} + +void SetupChannelBox::showDone() { + _link.setFocus(); +} + +void SetupChannelBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_link.hasFocus()) { + if (_link.text().trimmed().isEmpty()) { + _link.setFocus(); + _link.showError(); + } else { + onSave(); + } + } + } else { + AbstractBox::keyPressEvent(e); + } +} + +void SetupChannelBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + p.setPen(st::newGroupAboutFg); + + QRect aboutPublic = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _public.y() + _public.height(), _aboutPublicWidth, _aboutPublicHeight); + _aboutPublic.draw(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width()); + + QRect aboutPrivate = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _private.y() + _private.height(), _aboutPublicWidth, _aboutPublicHeight); + _aboutPrivate.draw(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width()); + + //QRect aboutComments = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _comments.y() + _comments.height(), _aboutPublicWidth, _aboutPublicHeight); + //_aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); + + p.setPen(st::black); + p.setFont(st::newGroupLinkFont); + p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::newGroupLink.textMargins.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link)); + + if (_link.isHidden()) { + QTextOption option(style::al_left); + option.setWrapMode(QTextOption::WrapAnywhere); + p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); + p.setPen(st::btnDefLink.color); + p.drawText(_invitationLink, _channel->invitationUrl, option); + if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { + p.setOpacity(a_goodOpacity.current()); + p.setPen(st::setGoodColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); + p.setOpacity(1); + } + } else { + if (!_errorText.isEmpty()) { + p.setPen(st::setErrColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText); + } else if (!_goodText.isEmpty()) { + p.setPen(st::setGoodColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText); + } + } +} + +void SetupChannelBox::resizeEvent(QResizeEvent *e) { + _public.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); + _private.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip); + //_comments.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip); + + _link.resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - st::boxPadding.right(), _link.height()); + //_link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); + _link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); + _invitationLink = QRect(_link.x(), _link.y() + (_link.height() / 2) - st::boxTextFont->height, _link.width(), 2 * st::boxTextFont->height); + + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _skip.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); +} + +void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) { + updateSelected(e->globalPos()); +} + +void SetupChannelBox::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (_linkOver) { + App::app()->clipboard()->setText(_channel->invitationUrl); + _goodTextLink = lang(lng_create_channel_link_copied); + a_goodOpacity = anim::fvalue(1, 0); + _a_goodFade.start(); + } +} + +void SetupChannelBox::leaveEvent(QEvent *e) { + updateSelected(QCursor::pos()); +} + +void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) { + QPoint p(mapFromGlobal(cursorGlobalPosition)); + + bool linkOver = _invitationLink.contains(p); + if (linkOver != _linkOver) { + _linkOver = linkOver; + update(); + setCursor(_linkOver ? style::cur_pointer : style::cur_default); + } +} + +bool SetupChannelBox::animStep_goodFade(float64 ms) { + float dt = ms / st::newGroupLinkFadeDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_goodOpacity.finish(); + } else { + a_goodOpacity.update(dt, anim::linear); + } + update(); + return res; +} + +void SetupChannelBox::closePressed() { + if (!_existing) { + App::wnd()->showLayer(new ContactsBox(_channel)); + } +} + +void SetupChannelBox::onSave() { + if (!_public.checked()) { + if (!_existing && !_comments.isHidden() && _comments.checked()) { + MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true))); + } + if (_existing) { + _sentUsername = QString(); + _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); + } else { + onClose(); + } + } + + if (_saveRequestId) return; + + QString link = _link.text().trimmed(); + if (link.isEmpty()) { + _link.setFocus(); + _link.showError(); + return; + } + + if (!_existing && !_comments.isHidden() && _comments.checked()) { + MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true)), RPCResponseHandler(), 0, 5); + } + _sentUsername = link; + _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); +} + +void SetupChannelBox::onChange() { + QString name = _link.text().trimmed(); + if (name.isEmpty()) { + if (!_errorText.isEmpty() || !_goodText.isEmpty()) { + _errorText = _goodText = QString(); + update(); + } + _checkTimer.stop(); + } else { + int32 i, len = name.size(); + for (int32 i = 0; i < len; ++i) { + QChar ch = name.at(i); + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') { + if (_errorText != lang(lng_create_channel_link_bad_symbols)) { + _errorText = lang(lng_create_channel_link_bad_symbols); + update(); + } + _checkTimer.stop(); + return; + } + } + if (name.size() < MinUsernameLength) { + if (_errorText != lang(lng_create_channel_link_too_short)) { + _errorText = lang(lng_create_channel_link_too_short); + update(); + } + _checkTimer.stop(); + } else { + if (!_errorText.isEmpty() || !_goodText.isEmpty()) { + _errorText = _goodText = QString(); + update(); + } + _checkTimer.start(UsernameCheckTimeout); + } + } +} + +void SetupChannelBox::onCheck() { + if (_checkRequestId) { + MTP::cancel(_checkRequestId); + } + QString link = _link.text().trimmed(); + if (link.size() >= MinUsernameLength) { + _checkUsername = link; + _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string(link)), rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail)); + } +} + +void SetupChannelBox::onPrivacyChange() { + if (_public.checked()) { + if (_tooMuchUsernames) { + _private.setChecked(true); + App::wnd()->replaceLayer(new InformBox(lang(lng_channels_too_much_public))); + return; + } + _link.show(); + _link.setFocus(); + } else { + _link.hide(); + setFocus(); + } + update(); +} + +void SetupChannelBox::onUpdateDone(const MTPBool &result) { + _channel->setName(textOneLine(_channel->name), _sentUsername); + onClose(); +} + +bool SetupChannelBox::onUpdateFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _saveRequestId = 0; + QString err(error.type()); + if (err == "USERNAME_NOT_MODIFIED" || _sentUsername == _channel->username) { + _channel->setName(textOneLine(_channel->name), textOneLine(_sentUsername)); + onClose(); + return true; + } else if (err == "USERNAME_INVALID") { + _link.setFocus(); + _link.showError(); + _errorText = lang(lng_create_channel_link_invalid); + update(); + return true; + } else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") { + _link.setFocus(); + _link.showError(); + _errorText = lang(lng_create_channel_link_occupied); + update(); + return true; + } + _link.setFocus(); + return true; +} + +void SetupChannelBox::onCheckDone(const MTPBool &result) { + _checkRequestId = 0; + QString newError = (result.v || _checkUsername == _channel->username) ? QString() : lang(lng_create_channel_link_occupied); + QString newGood = newError.isEmpty() ? lang(lng_create_channel_link_available) : QString(); + if (_errorText != newError || _goodText != newGood) { + _errorText = newError; + _goodText = newGood; + update(); + } +} + +bool SetupChannelBox::onCheckFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _checkRequestId = 0; + QString err(error.type()); + if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") { + if (_existing) { + App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); + } else { + _tooMuchUsernames = true; + _private.setChecked(true); + onPrivacyChange(); + } + return true; + } else if (err == "USERNAME_INVALID") { + _errorText = lang(lng_create_channel_link_invalid); + update(); + return true; + } else if (err == "USERNAME_OCCUPIED" && _checkUsername != _channel->username) { + _errorText = lang(lng_create_channel_link_occupied); + update(); + return true; + } + _goodText = QString(); + _link.setFocus(); + return true; +} + +bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _checkRequestId = 0; + QString err(error.type()); + if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") { + if (_existing) { + App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); + } else { + _tooMuchUsernames = true; + _private.setChecked(true); + onPrivacyChange(); + } + return true; + } + _goodText = QString(); + _link.setFocus(); + return true; +} + EditNameTitleBox::EditNameTitleBox(PeerData *peer) : _peer(peer), _save(this, lang(lng_settings_save), st::defaultBoxButton), -_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_cancel(this, lang(lng_cancel), st::cancelBoxButton), _first(this, st::defaultInputField, lang(peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), peer->isUser() ? peer->asUser()->firstName : peer->name), _last(this, st::defaultInputField, lang(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()), _invertOrder(!peer->isChat() && langFirstNameGoesSecond()), @@ -360,14 +984,17 @@ _requestId(0) { if (_invertOrder) { setTabOrder(&_last, &_first); } - int32 h = st::boxTitleHeight + st::addContactPadding.top() + _first.height(); + _first.setMaxLength(MaxGroupChannelTitle); + _last.setMaxLength(MaxGroupChannelTitle); + + int32 h = st::boxTitleHeight + st::contactPadding.top() + _first.height(); if (_peer->isUser()) { _boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title); - h += st::addContactSkip + _last.height(); + h += st::contactSkip + _last.height(); } else if (_peer->isChat()) { _boxTitle = lang(lng_edit_group_title); } - h += st::boxPadding.bottom() + st::addContactPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); + h += st::boxPadding.bottom() + st::contactPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); setMaxHeight(h); connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); @@ -434,14 +1061,14 @@ void EditNameTitleBox::paintEvent(QPaintEvent *e) { } void EditNameTitleBox::resizeEvent(QResizeEvent *e) { - _first.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _first.height()); + _first.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _first.height()); _last.resize(_first.size()); if (_invertOrder) { - _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::addContactPadding.top()); - _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last.y() + _last.height() + st::addContactSkip); + _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::contactPadding.top()); + _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last.y() + _last.height() + st::contactSkip); } else { - _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::addContactPadding.top()); - _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first.y() + _first.height() + st::addContactSkip); + _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::contactPadding.top()); + _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first.y() + _first.height() + st::contactSkip); } _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); @@ -527,7 +1154,7 @@ void EditNameTitleBox::onSaveChatDone(const MTPUpdates &updates) { EditChannelBox::EditChannelBox(ChannelData *channel) : _channel(channel), _save(this, lang(lng_settings_save), st::defaultBoxButton), -_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_cancel(this, lang(lng_cancel), st::cancelBoxButton), _title(this, st::newGroupName, lang(lng_dlg_new_channel_name), _channel->name), _description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about), _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::defaultBoxLinkButton), @@ -536,8 +1163,9 @@ _saveTitleRequestId(0), _saveDescriptionRequestId(0) { setMouseTracking(true); + _title.setMaxLength(MaxGroupChannelTitle); _description.setMaxLength(MaxChannelDescription); - _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _description.height()); + _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _description.height()); updateMaxHeight(); connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); @@ -609,7 +1237,7 @@ void EditChannelBox::updateMaxHeight() { } void EditChannelBox::resizeEvent(QResizeEvent *e) { - _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _title.height()); + _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - st::boxPadding.right(), _title.height()); _title.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); _description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title.y() + _title.height() + st::newGroupDescriptionPadding.top()); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h index 509cf11e6..00c600c30 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.h +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -28,18 +28,18 @@ class AddContactBox : public AbstractBox, public RPCSender { public: AddContactBox(QString fname = QString(), QString lname = QString(), QString phone = QString()); - AddContactBox(PeerData *peer); - void keyPressEvent(QKeyEvent *e); + AddContactBox(UserData *user); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); void setInnerFocus() { - _firstInput.setFocus(); + _first.setFocus(); } public slots: - void onSend(); + void onSubmit(); + void onSave(); void onRetry(); protected: @@ -52,20 +52,17 @@ private: void onImportDone(const MTPcontacts_ImportedContacts &res); - void onSaveSelfDone(const MTPUser &user); - bool onSaveSelfFail(const RPCError &error); - - void onSaveChatDone(const MTPUpdates &updates); void onSaveUserDone(const MTPcontacts_ImportedContacts &res); - bool onSaveFail(const RPCError &e); + bool onSaveUserFail(const RPCError &e); void initBox(); - PeerData *_peer; + UserData *_user; QString _boxTitle; - FlatButton _addButton, _retryButton, _cancelButton; - FlatInput _firstInput, _lastInput, _phoneInput; + BoxButton _save, _cancel, _retry; + InputField _first, _last; + PhoneInput _phone; bool _invertOrder; @@ -75,6 +72,169 @@ private: QString _sentName; }; +class NewGroupBox : public AbstractBox { + Q_OBJECT + +public: + + NewGroupBox(); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + +public slots: + + void onNext(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + Radiobutton _group, _channel; + int32 _aboutGroupWidth, _aboutGroupHeight; + Text _aboutGroup, _aboutChannel; + BoxButton _next, _cancel; + +}; + +class GroupInfoBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + + GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void leaveEvent(QEvent *e); + + bool animStep_photoOver(float64 ms); + + void setInnerFocus() { + _title.setFocus(); + } + +public slots: + + void onPhoto(); + void onPhotoReady(const QImage &img); + + void onNext(); + void onNameSubmit(); + void onDescriptionResized(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + QRect photoRect() const; + + void updateMaxHeight(); + void updateSelected(const QPoint &cursorGlobalPosition); + CreatingGroupType _creating; + + anim::fvalue a_photoOver; + Animation _a_photoOver; + bool _photoOver; + + InputField _title; + InputArea _description; + + QImage _photoBig; + QPixmap _photoSmall; + BoxButton _next, _cancel; + + // channel creation + int32 _creationRequestId; + ChannelData *_createdChannel; + + void creationDone(const MTPUpdates &updates); + bool creationFail(const RPCError &e); + void exportDone(const MTPExportedChatInvite &result); +}; + +class SetupChannelBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + + SetupChannelBox(ChannelData *channel, bool existing = false); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void leaveEvent(QEvent *e); + + void closePressed(); + + void setInnerFocus() { + if (_link.isHidden()) { + setFocus(); + } else { + _link.setFocus(); + } + } + +public slots: + + void onSave(); + void onChange(); + void onCheck(); + + void onPrivacyChange(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + void updateSelected(const QPoint &cursorGlobalPosition); + bool animStep_goodFade(float64 ms); + + void onUpdateDone(const MTPBool &result); + bool onUpdateFail(const RPCError &error); + + void onCheckDone(const MTPBool &result); + bool onCheckFail(const RPCError &error); + bool onFirstCheckFail(const RPCError &error); + + ChannelData *_channel; + bool _existing; + + Radiobutton _public, _private; + Checkbox _comments; + int32 _aboutPublicWidth, _aboutPublicHeight; + Text _aboutPublic, _aboutPrivate, _aboutComments; + UsernameInput _link; + QRect _invitationLink; + bool _linkOver; + BoxButton _save, _skip; + + bool _tooMuchUsernames; + + mtpRequestId _saveRequestId, _checkRequestId; + QString _sentUsername, _checkUsername, _errorText, _goodText; + + QString _goodTextLink; + anim::fvalue a_goodOpacity; + Animation _a_goodFade; + + QTimer _checkTimer; +}; + class EditNameTitleBox : public AbstractBox, public RPCSender { Q_OBJECT diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp index b62830b10..098b301c2 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.cpp +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -28,6 +28,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org BackgroundInner::BackgroundInner() : _bgCount(0), _rows(0), _over(-1), _overDown(-1) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); if (App::cServerBackgrounds().isEmpty()) { resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers)); @@ -174,39 +175,21 @@ BackgroundInner::~BackgroundInner() { void BackgroundInner::resizeEvent(QResizeEvent *e) { } -BackgroundBox::BackgroundBox() : ItemListBox(st::boxScroll), _inner(), -_close(this, lang(lng_cancel), st::contactsClose) { +BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll) +, _inner() { - init(&_inner, _close.height(), st::boxFont->height + st::old_newGroupNamePadding.top() + st::old_newGroupNamePadding.bottom()); + init(&_inner); - connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int))); prepare(); } -void BackgroundBox::hideAll() { - ItemListBox::hideAll(); - _close.hide(); -} - -void BackgroundBox::showAll() { - ItemListBox::showAll(); - _close.show(); - _close.raise(); -} - void BackgroundBox::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); if (paint(p)) return; - paintGrayTitle(p, lang(lng_backgrounds_header)); -} - -void BackgroundBox::resizeEvent(QResizeEvent *e) { - ItemListBox::resizeEvent(e); - _inner.resize(width(), _inner.height()); - _close.move(0, height() - _close.height()); + paintTitle(p, lang(lng_backgrounds_header)); } void BackgroundBox::onBackgroundChosen(int index) { diff --git a/Telegram/SourceFiles/boxes/backgroundbox.h b/Telegram/SourceFiles/boxes/backgroundbox.h index ea3f1aa61..e2a6e5a82 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.h +++ b/Telegram/SourceFiles/boxes/backgroundbox.h @@ -58,19 +58,13 @@ public: BackgroundBox(); void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); public slots: void onBackgroundChosen(int index); -protected: - - void hideAll(); - void showAll(); - private: BackgroundInner _inner; - BottomButton _close; + }; diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index ffaa620c1..8370cbe4f 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -38,7 +38,7 @@ ConfirmBox::ConfirmBox(const QString &text, const QString &doneText, const style _informative(false), _text(100), _confirm(this, doneText.isEmpty() ? lang(lng_box_ok) : doneText, doneStyle), -_cancel(this, cancelText.isEmpty() ? lang(lng_box_cancel) : cancelText, cancelStyle) { +_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, cancelStyle) { init(text); } @@ -54,7 +54,7 @@ void ConfirmBox::init(const QString &text) { _text.setText(st::boxTextFont, text, _informative ? _confirmBoxTextOptions : _textPlainOptions); textstyleSet(&st::boxTextStyle); - _textWidth = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); + _textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); _textHeight = qMin(_text.countHeight(_textWidth), 16 * int(st::boxTextStyle.lineHeight)); setMaxHeight(st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + st::boxButtonPadding.top() + _confirm.height() + st::boxButtonPadding.bottom()); textstyleRestore(); @@ -189,14 +189,14 @@ void ConfirmLinkBox::onOpenLink() { MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth), _close(this, lang(lng_box_ok), st::defaultBoxButton), -_text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxPadding.right()), +_text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()), _link(link), _linkOver(false), a_goodOpacity(0, 0), a_good(animFunc(this, &MaxInviteBox::goodAnimStep)) { setMouseTracking(true); - _textWidth = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); + _textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right(); _textHeight = qMin(_text.countHeight(_textWidth), 16 * int(st::boxTextStyle.lineHeight)); - setMaxHeight(st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom() + _close.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom() + st::boxButtonPadding.top() + _close.height() + st::boxButtonPadding.bottom()); connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); @@ -277,5 +277,5 @@ void MaxInviteBox::paintEvent(QPaintEvent *e) { void MaxInviteBox::resizeEvent(QResizeEvent *e) { _close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height()); - _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), 2 * st::boxTextFont->height); + _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - st::boxPadding.right(), 2 * st::boxTextFont->height); } diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index e6c6ca81d..23ac63af9 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -37,7 +37,7 @@ _httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http _tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)), _tryIPv6(this, lang(lng_connection_try_ipv6), cTryIPv6()), _save(this, lang(lng_connection_save), st::defaultBoxButton), -_cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { +_cancel(this, lang(lng_cancel), st::cancelBoxButton) { connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); @@ -51,8 +51,6 @@ _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { connect(&_userInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); connect(&_passwordInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); - _passwordInput.setEchoMode(QLineEdit::Password); - prepare(); } @@ -128,9 +126,9 @@ void ConnectionBox::resizeEvent(QResizeEvent *e) { if (inputy) { _hostInput.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultRadiobutton.textPosition.x() - st::defaultInputField.textMargins.left(), inputy); - _portInput.moveToRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), inputy); + _portInput.moveToRight(st::boxPadding.right(), inputy); _userInput.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultRadiobutton.textPosition.x() - st::defaultInputField.textMargins.left(), _hostInput.y() + _hostInput.height() + st::boxOptionListPadding.top()); - _passwordInput.moveToRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _userInput.y()); + _passwordInput.moveToRight(st::boxPadding.right(), _userInput.y()); } int32 tryipv6y = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::boxOptionListPadding.top() + st::connectionIPv6Skip; diff --git a/Telegram/SourceFiles/boxes/connectionbox.h b/Telegram/SourceFiles/boxes/connectionbox.h index 7def2ba77..f8bbce5ab 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.h +++ b/Telegram/SourceFiles/boxes/connectionbox.h @@ -48,7 +48,7 @@ private: InputField _hostInput; PortInput _portInput; InputField _userInput; - MaskedInputField _passwordInput; + PasswordField _passwordInput; Radiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio; Checkbox _tryIPv6; diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index fe3cd490d..6ce3098cd 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -33,59 +33,100 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "confirmbox.h" -ContactsInner::ContactsInner(CreatingGroupType creating) : -_chat(0), _channel(0), _channelFilter(MembersFilterRecent), _bot(0), _creating(creating), -_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0), -_contacts(&App::main()->contactsList()), -_sel(0), -_filteredSel(-1), -_mouseSel(false), -_selCount(0), -_searching(false), -_byUsernameSel(-1), -_addContactLnk(this, lang(lng_add_contact_button)) { +ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget() +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0) +, _newItemSel(false) +, _chat(0) +, _channel(0) +, _channelFilter(MembersFilterRecent) +, _bot(0) +, _creating(creating) +, _addToChat(0) +, _addAdmin(0) +, _addAdminRequestId(0) +, _addAdminBox(0) +, _contacts(&App::main()->contactsList()) +, _sel(0) +, _filteredSel(-1) +, _mouseSel(false) +, _selCount(0) +, _searching(false) +, _byUsernameSel(-1) +, _addContactLnk(this, lang(lng_add_contact_button)) { init(); } -ContactsInner::ContactsInner(ChannelData *channel, MembersFilter channelFilter, const MembersAlreadyIn &already) : -_chat(0), _channel(channel), _channelFilter(channelFilter), _bot(0), _creating(CreatingGroupChannel), _already(already), -_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0), -_contacts(&App::main()->contactsList()), -_sel(0), -_filteredSel(-1), -_mouseSel(false), -_selCount(0), -_searching(false), -_byUsernameSel(-1), -_addContactLnk(this, lang(lng_add_contact_button)) { +ContactsInner::ContactsInner(ChannelData *channel, MembersFilter channelFilter, const MembersAlreadyIn &already) : TWidget() +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _newItemHeight(0) +, _newItemSel(false) +, _chat(0) +, _channel(channel) +, _channelFilter(channelFilter) +, _bot(0) +, _creating(CreatingGroupChannel) +, _already(already) +, _addToChat(0) +, _addAdmin(0) +, _addAdminRequestId(0) +, _addAdminBox(0) +, _contacts(&App::main()->contactsList()) +, _sel(0) +, _filteredSel(-1) +, _mouseSel(false) +, _selCount(0) +, _searching(false) +, _byUsernameSel(-1) +, _addContactLnk(this, lang(lng_add_contact_button)) { init(); } -ContactsInner::ContactsInner(ChatData *chat) : -_chat(chat), _channel(0), _channelFilter(MembersFilterRecent), _bot(0), _creating(CreatingGroupNone), -_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0), -_contacts(&App::main()->contactsList()), -_sel(0), -_filteredSel(-1), -_mouseSel(false), -_selCount(0), -_searching(false), -_byUsernameSel(-1), -_addContactLnk(this, lang(lng_add_contact_button)) { +ContactsInner::ContactsInner(ChatData *chat) : TWidget() +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _newItemHeight(0) +, _newItemSel(false) +, _chat(chat) +, _channel(0) +, _channelFilter(MembersFilterRecent) +, _bot(0) +, _creating(CreatingGroupNone) +, _addToChat(0) +, _addAdmin(0) +, _addAdminRequestId(0) +, _addAdminBox(0) +, _contacts(&App::main()->contactsList()) +, _sel(0) +, _filteredSel(-1) +, _mouseSel(false) +, _selCount(0) +, _searching(false) +, _byUsernameSel(-1) +, _addContactLnk(this, lang(lng_add_contact_button)) { init(); } -ContactsInner::ContactsInner(UserData *bot) : -_chat(0), _channel(0), _channelFilter(MembersFilterRecent), _bot(bot), _creating(CreatingGroupNone), -_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0), -_contacts(new DialogsIndexed(DialogsSortByAdd)), -_sel(0), -_filteredSel(-1), -_mouseSel(false), -_selCount(0), -_searching(false), -_byUsernameSel(-1), -_addContactLnk(this, lang(lng_add_contact_button)) { +ContactsInner::ContactsInner(UserData *bot) : TWidget() +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _newItemHeight(0) +, _newItemSel(false) +, _chat(0) +, _channel(0) +, _channelFilter(MembersFilterRecent) +, _bot(bot) +, _creating(CreatingGroupNone) +, _addToChat(0) +, _addAdmin(0) +, _addAdminRequestId(0) +, _addAdminBox(0) +, _contacts(new DialogsIndexed(DialogsSortByAdd)) +, _sel(0) +, _filteredSel(-1) +, _mouseSel(false) +, _selCount(0) +, _searching(false) +, _byUsernameSel(-1) +, _addContactLnk(this, lang(lng_add_contact_button)) { DialogsIndexed &v(App::main()->dialogsList()); for (DialogRow *r = v.list.begin; r != v.list.end; r = r->next) { if (r->history->peer->isChat() && !r->history->peer->asChat()->isForbidden && !r->history->peer->asChat()->haveLeft) { @@ -96,8 +137,11 @@ _addContactLnk(this, lang(lng_add_contact_button)) { } void ContactsInner::init() { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); + setAttribute(Qt::WA_OpaquePaintEvent); + for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) { r->attached = 0; } @@ -182,20 +226,19 @@ void ContactsInner::peerUpdated(PeerData *peer) { } update(); } else { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; ContactsData::iterator i = _contactsData.find(peer); if (i != _contactsData.cend()) { for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { if (row->attached == i.value()) { row->attached = 0; - update(0, rh * row->pos, width(), rh); + update(0, _newItemHeight + _rowHeight * row->pos, width(), _rowHeight); } } if (!_filter.isEmpty()) { for (int32 j = 0, s = _filtered.size(); j < s; ++j) { if (_filtered[j]->attached == i.value()) { _filtered[j]->attached = 0; - update(0, rh * j, width(), rh); + update(0, _rowHeight * j, width(), _rowHeight); } } } @@ -212,23 +255,22 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) { if (yTo < 0) return; if (yFrom < 0) yFrom = 0; - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_filter.isEmpty()) { if (_contacts->list.count) { - _contacts->list.adjustCurrent(yFrom, rh); + _contacts->list.adjustCurrent(yFrom - _newItemHeight, _rowHeight); for ( DialogRow *preloadFrom = _contacts->list.current; - preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo; + preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo; preloadFrom = preloadFrom->next ) { preloadFrom->history->peer->photo->load(); } } } else if (!_filtered.isEmpty()) { - int32 from = yFrom / rh; + int32 from = yFrom / _rowHeight; if (from < 0) from = 0; if (from < _filtered.size()) { - int32 to = (yTo / rh) + 1; + int32 to = (yTo / _rowHeight) + 1; if (to > _filtered.size()) to = _filtered.size(); for (; from < to; ++from) { @@ -259,7 +301,7 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) { data->inchat = false; } data->check = _checkedContacts.contains(peer); - data->name.setText(st::profileListNameFont, peer->name, _textNameOptions); + data->name.setText(st::contactsNameFont, peer->name, _textNameOptions); if (peer->isUser()) { data->online = App::onlineText(peer->asUser(), _time); } else if (peer->isChat()) { @@ -281,69 +323,58 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) { } void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel) { - int32 left = st::profileListPadding.width(); - UserData *user = peer->asUser(); if (data->inchat || data->check || selectedCount() >= cMaxGroupCount()) { sel = false; } - if (sel || data->inchat || data->check) { - p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, ((data->inchat || data->check) ? st::profileActiveBG : st::profileHoverBG)->b); - } + p.fillRect(0, 0, width(), _rowHeight, ((data->inchat || data->check) ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white))->b); + p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize)); - p.drawPixmap(left, st::profileListPadding.height(), peer->photo->pix(st::profileListPhotoSize)); + p.setPen((data->inchat || data->check) ? st::white : st::black); - if (data->inchat || data->check) { - p.setPen(st::white->p); - } else { - p.setPen(st::profileListNameColor->p); - } - int32 iconw = (_chat || _creating != CreatingGroupNone) ? st::inviteCheckIcon.pxWidth() : st::contactsImg.pxWidth(); - int32 namew = width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - iconw; + int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int32 iconw = (_chat || _creating != CreatingGroupNone) ? (st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth()) : 0; + int32 namew = width() - namex - st::contactsPadding.right() - iconw; if (peer->isChannel() && peer->asChannel()->isVerified()) { namew -= st::verifiedCheck.pxWidth() + st::verifiedCheckPos.x(); - p.drawSprite(QPoint(left + st::profileListPhotoSize + st::participantDelta + qMin(data->name.maxWidth(), namew), st::profileListNameTop) + st::verifiedCheckPos, st::verifiedCheck); + p.drawSpriteLeft(namex + qMin(data->name.maxWidth(), namew) + st::verifiedCheckPos.x(), st::contactsPadding.top() + st::contactsNameTop + st::verifiedCheckPos.y(), width(), st::verifiedCheck); } - data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, namew); + data->name.drawElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew); - if (_channel && _channelFilter == MembersFilterAdmins) { - if (sel) { - p.drawPixmap(QPoint(width() - st::contactsImg.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg); - } - } else if (_chat || _creating != CreatingGroupNone) { + if (_chat || (_creating != CreatingGroupNone && (!_channel || _channelFilter != MembersFilterAdmins))) { if (sel || data->check) { - p.drawPixmap(QPoint(width() - st::inviteCheckIcon.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::inviteCheckIcon.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::inviteCheckActiveIcon : st::inviteCheckIcon)); + p.drawSpriteRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + st::contactsCheckPosition.y(), width(), (data->check ? st::contactsCheckActiveIcon : st::contactsCheckIcon)); } - } else if (sel) { - p.drawPixmap(QPoint(width() - st::contactsImg.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg); } bool uname = (user || peer->isChannel()) && (data->online.at(0) == '@'); - p.setFont(st::profileSubFont->f); + p.setFont(st::contactsStatusFont->f); if (uname && !data->inchat && !data->check && !_lastQuery.isEmpty() && peer->userName().startsWith(_lastQuery, Qt::CaseInsensitive)) { - int32 availw = width() - (left + st::profileListPhotoSize + st::profileListPadding.width() * 2); + int32 availw = width() - namex - st::contactsPadding.right() - iconw; QString first = '@' + peer->userName().mid(0, _lastQuery.size()), second = peer->userName().mid(_lastQuery.size()); - int32 w = st::profileSubFont->width(first); + int32 w = st::contactsStatusFont->width(first); if (w >= availw || second.isEmpty()) { - p.setPen(st::profileOnlineColor->p); - p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, st::profileSubFont->elided(first, availw)); + p.setPen(st::contactsStatusFgOnline); + p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), st::contactsStatusFont->elided(first, availw)); } else { - p.setPen(st::profileOnlineColor->p); - p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, first); - p.setPen(st::profileOfflineColor->p); - p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width() + w, st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, st::profileSubFont->elided(second, availw - w)); + second = st::contactsStatusFont->elided(second, availw - w); + int32 secondw = st::contactsStatusFont->width(second); + p.setPen(st::contactsStatusFgOnline); + p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width() - secondw, first); + p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); + p.drawTextLeft(namex + w, st::contactsPadding.top() + st::contactsStatusTop, width() + w, second); } } else { if (data->inchat || data->check) { - p.setPen(st::white->p); + p.setPen(st::white); } else if ((user && (uname || App::onlineColorUse(user, _time))) || (peer->isChannel() && uname)) { - p.setPen(st::profileOnlineColor->p); + p.setPen(st::contactsStatusFgOnline); } else { - p.setPen(st::profileOfflineColor->p); + p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); } - p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online); + p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->online); } } @@ -356,35 +387,48 @@ void ContactsInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white->b); int32 yFrom = r.y(), yTo = r.y() + r.height(); - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_filter.isEmpty()) { if (_contacts->list.count || !_byUsername.isEmpty()) { + if (_newItemHeight) { + p.fillRect(0, 0, width(), _newItemHeight, (_newItemSel ? st::contactsBgOver : st::white)->b); + p.drawSpriteLeft(st::contactsNewItemIconPosition.x(), st::contactsNewItemIconPosition.y(), width(), st::contactsNewItemIcon); + p.setFont(st::contactsNameFont); + p.setPen(st::contactsNewItemFg); + p.drawTextLeft(st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(), st::contactsNewItemTop, width(), lang(lng_add_contact_button)); + + yFrom -= _newItemHeight; + yTo -= _newItemHeight; + p.translate(0, _newItemHeight); + } if (_contacts->list.count) { - _contacts->list.adjustCurrent(yFrom, rh); + _contacts->list.adjustCurrent(yFrom, _rowHeight); DialogRow *drawFrom = _contacts->list.current; - p.translate(0, drawFrom->pos * rh); - while (drawFrom != _contacts->list.end && drawFrom->pos * rh < yTo) { + p.translate(0, drawFrom->pos * _rowHeight); + while (drawFrom != _contacts->list.end && drawFrom->pos * _rowHeight < yTo) { paintDialog(p, drawFrom->history->peer, contactData(drawFrom), (drawFrom == _sel)); - p.translate(0, rh); + p.translate(0, _rowHeight); drawFrom = drawFrom->next; } + yFrom -= _contacts->list.count * _rowHeight; + yTo -= _contacts->list.count * _rowHeight; } if (!_byUsername.isEmpty()) { p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b); p.setFont(st::searchedBarFont->f); p.setPen(st::searchedBarColor->p); p.drawText(QRect(0, 0, width(), st::searchedBarHeight), lang(lng_search_global_results), style::al_center); + + yFrom -= st::searchedBarHeight; + yTo -= st::searchedBarHeight; p.translate(0, st::searchedBarHeight); - yFrom -= _contacts->list.count * rh + st::searchedBarHeight; - yTo -= _contacts->list.count * rh + st::searchedBarHeight; - int32 from = floorclamp(yFrom, rh, 0, _byUsername.size()); - int32 to = ceilclamp(yTo, rh, 0, _byUsername.size()); - p.translate(0, from * rh); + int32 from = floorclamp(yFrom, _rowHeight, 0, _byUsername.size()); + int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsername.size()); + p.translate(0, from * _rowHeight); for (; from < to; ++from) { paintDialog(p, _byUsername[from], d_byUsername[from], (_byUsernameSel == from)); - p.translate(0, rh); + p.translate(0, _rowHeight); } } } else { @@ -415,12 +459,12 @@ void ContactsInner::paintEvent(QPaintEvent *e) { p.drawText(QRect(0, 0, width(), st::noContactsHeight), text, style::al_center); } else { if (!_filtered.isEmpty()) { - int32 from = floorclamp(yFrom, rh, 0, _filtered.size()); - int32 to = ceilclamp(yTo, rh, 0, _filtered.size()); - p.translate(0, from * rh); + int32 from = floorclamp(yFrom, _rowHeight, 0, _filtered.size()); + int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size()); + p.translate(0, from * _rowHeight); for (; from < to; ++from) { paintDialog(p, _filtered[from]->history->peer, contactData(_filtered[from]), (_filteredSel == from)); - p.translate(0, rh); + p.translate(0, _rowHeight); } } if (!_byUsernameFiltered.isEmpty()) { @@ -430,14 +474,14 @@ void ContactsInner::paintEvent(QPaintEvent *e) { p.drawText(QRect(0, 0, width(), st::searchedBarHeight), lang(lng_search_global_results), style::al_center); p.translate(0, st::searchedBarHeight); - yFrom -= _filtered.size() * rh + st::searchedBarHeight; - yTo -= _filtered.size() * rh + st::searchedBarHeight; - int32 from = floorclamp(yFrom, rh, 0, _byUsernameFiltered.size()); - int32 to = ceilclamp(yTo, rh, 0, _byUsernameFiltered.size()); - p.translate(0, from * rh); + yFrom -= _filtered.size() * _rowHeight + st::searchedBarHeight; + yTo -= _filtered.size() * _rowHeight + st::searchedBarHeight; + int32 from = floorclamp(yFrom, _rowHeight, 0, _byUsernameFiltered.size()); + int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsernameFiltered.size()); + p.translate(0, from * _rowHeight); for (; from < to; ++from) { paintDialog(p, _byUsernameFiltered[from], d_byUsernameFiltered[from], (_byUsernameSel == from)); - p.translate(0, rh); + p.translate(0, _rowHeight); } } } @@ -449,29 +493,33 @@ void ContactsInner::enterEvent(QEvent *e) { } void ContactsInner::updateSelectedRow() { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_filter.isEmpty()) { + if (_newItemSel) { + update(0, 0, width(), _newItemHeight); + } if (_sel) { - update(0, _sel->pos * rh, width(), rh); + update(0, _newItemHeight + _sel->pos * _rowHeight, width(), _rowHeight); } if (_byUsernameSel >= 0) { - update(0, _contacts->list.count * rh + st::searchedBarHeight + _byUsernameSel * rh, width(), rh); + update(0, _newItemHeight + _contacts->list.count * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight); } } else { if (_filteredSel >= 0) { - update(0, _filteredSel * rh, width(), rh); + update(0, _filteredSel * _rowHeight, width(), _rowHeight); } if (_byUsernameSel >= 0) { - update(0, _filtered.size() * rh + st::searchedBarHeight + _byUsernameSel * rh, width(), rh); + update(0, _filtered.size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight); } } } void ContactsInner::leaveEvent(QEvent *e) { + _mouseSel = false; setMouseTracking(false); - if (_sel || _filteredSel >= 0 || _byUsernameSel >= 0) { + if (_newItemSel || _sel || _filteredSel >= 0 || _byUsernameSel >= 0) { updateSelectedRow(); _sel = 0; + _newItemSel = false; _filteredSel = _byUsernameSel = -1; } } @@ -495,7 +543,6 @@ void ContactsInner::chooseParticipant() { bool addingAdmin = (_channel && _channelFilter == MembersFilterAdmins); if (!addingAdmin && (_chat || _creating != CreatingGroupNone)) { _time = unixtime(); - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; if (_filter.isEmpty()) { if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) { if (d_byUsername[_byUsernameSel]->inchat) return; @@ -535,9 +582,12 @@ void ContactsInner::chooseParticipant() { emit selectAllQuery(); } } else { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; PeerData *peer = 0; if (_filter.isEmpty()) { + if (_newItemSel) { + emit addRequested(); + return; + } if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) { peer = _byUsername[_byUsernameSel]; } else if (_sel) { @@ -609,22 +659,31 @@ int32 ContactsInner::selectedCount() const { } void ContactsInner::updateSel() { + if (!_mouseSel) return; + QPoint p(mapFromGlobal(_lastMousePos)); bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos)); - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_filter.isEmpty()) { - DialogRow *newSel = (in && (p.y() >= 0) && (p.y() < _contacts->list.count * rh)) ? _contacts->list.rowAtY(p.y(), rh) : 0; - int32 byUsernameSel = (in && p.y() >= _contacts->list.count * rh + st::searchedBarHeight) ? ((p.y() - _contacts->list.count * rh - st::searchedBarHeight) / rh) : -1; + bool newItemSel = false; + if (_newItemHeight) { + if (in && (p.y() >= 0) && (p.y() < _newItemHeight)) { + newItemSel = true; + } + p.setY(p.y() - _newItemHeight); + } + DialogRow *newSel = (in && !newItemSel && (p.y() >= 0) && (p.y() < _contacts->list.count * _rowHeight)) ? _contacts->list.rowAtY(p.y(), _rowHeight) : 0; + int32 byUsernameSel = (in && !newItemSel && p.y() >= _contacts->list.count * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->list.count * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1; if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1; - if (newSel != _sel || byUsernameSel != _byUsernameSel) { + if (newSel != _sel || byUsernameSel != _byUsernameSel || newItemSel != _newItemSel) { updateSelectedRow(); + _newItemSel = newItemSel; _sel = newSel; _byUsernameSel = byUsernameSel; updateSelectedRow(); } } else { - int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * rh) ? (p.y() / rh) : -1; - int32 byUsernameSel = (in && p.y() >= _filtered.size() * rh + st::searchedBarHeight) ? ((p.y() - _filtered.size() * rh - st::searchedBarHeight) / rh) : -1; + int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * _rowHeight) ? (p.y() / _rowHeight) : -1; + int32 byUsernameSel = (in && p.y() >= _filtered.size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _filtered.size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1; if (byUsernameSel >= _byUsernameFiltered.size()) byUsernameSel = -1; if (newFilteredSel != _filteredSel || byUsernameSel != _byUsernameSel) { updateSelectedRow(); @@ -654,7 +713,6 @@ void ContactsInner::updateFilter(QString filter) { filter = f.join(' '); } if (_filter != filter) { - int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); _filter = filter; _byUsernameFiltered.clear(); @@ -666,21 +724,6 @@ void ContactsInner::updateFilter(QString filter) { if (_filter.isEmpty()) { _sel = 0; - if (_contacts->list.count) { - _sel = _contacts->list.begin; - while (_sel->next->next && contactData(_sel)->inchat) { - _sel = _sel->next; - } - } - if (!_sel && !_byUsername.isEmpty()) { - _byUsernameSel = 0; - while (_byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->inchat) { - ++_byUsernameSel; - } - if (_byUsernameSel == _byUsername.size()) _byUsernameSel = -1; - } else { - _byUsernameSel = -1; - } refresh(); } else { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); @@ -760,7 +803,7 @@ void ContactsInner::updateFilter(QString filter) { } if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1; } - + _mouseSel = false; refresh(); if (!bot()) { @@ -796,9 +839,8 @@ void ContactsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) { } } _mouseSel = false; - int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2); int32 cnt = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()); - int32 newh = cnt ? (cnt * rh + st::contactsClose.height) : st::noContactsHeight; + int32 newh = cnt ? (cnt * _rowHeight) : st::noContactsHeight; resize(width(), newh); } @@ -818,14 +860,15 @@ void ContactsInner::peopleReceived(const QString &query, const QVector PeerData *p = App::peer(peerId); if (!p) continue; - if ((!p->isUser() || (p->asUser()->botInfo && p->asUser()->botInfo->cantJoinGroups)) && (_chat || _creating != CreatingGroupNone)) continue; // skip bot's that can't be invited to groups - if (p->isUser() && p->asUser()->botInfo && _channel) continue; // skip bots in channels + if ((!p->isUser() || (p->asUser()->botInfo && p->asUser()->botInfo->cantJoinGroups)) && (_chat || _creating == CreatingGroupGroup)) continue; // skip bot's that can't be invited to groups + if (_channel && !p->isUser()) continue; + if (p->isUser() && p->asUser()->botInfo && _channel && _channelFilter != MembersFilterAdmins) continue; // skip bots in channels ContactData *d = new ContactData(); _byUsernameDatas.push_back(d); d->inchat = _chat ? _chat->participants.contains(p->asUser()) : ((_creating == CreatingGroupGroup || _channel) ? (p == App::self()) : false); d->check = _checkedContacts.contains(p); - d->name.setText(st::profileListNameFont, p->name, _textNameOptions); + d->name.setText(st::contactsNameFont, p->name, _textNameOptions); d->online = '@' + p->userName(); _byUsernameFiltered.push_back(p); @@ -837,11 +880,10 @@ void ContactsInner::peopleReceived(const QString &query, const QVector } void ContactsInner::refresh() { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_filter.isEmpty()) { if (_contacts->list.count || !_byUsername.isEmpty()) { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); - resize(width(), (_contacts->list.count * rh) + (_byUsername.isEmpty() ? 0 : (st::searchedBarHeight + _byUsername.size() * rh))); + resize(width(), _newItemHeight + (_contacts->list.count * _rowHeight) + (_byUsername.isEmpty() ? 0 : (st::searchedBarHeight + _byUsername.size() * _rowHeight))); } else { if (cContactsReceived() && !bot()) { if (_addContactLnk.isHidden()) _addContactLnk.show(); @@ -855,7 +897,7 @@ void ContactsInner::refresh() { if (!_addContactLnk.isHidden()) _addContactLnk.hide(); resize(width(), st::noContactsHeight); } else { - resize(width(), (_filtered.size() * rh) + (_byUsernameFiltered.isEmpty() ? 0 : (st::searchedBarHeight + _byUsernameFiltered.size() * rh))); + resize(width(), (_filtered.size() * _rowHeight) + (_byUsernameFiltered.isEmpty() ? 0 : (st::searchedBarHeight + _byUsernameFiltered.size() * _rowHeight))); } } update(); @@ -898,21 +940,26 @@ void ContactsInner::resizeEvent(QResizeEvent *e) { void ContactsInner::selectSkip(int32 dir) { _time = unixtime(); _mouseSel = false; - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir; if (_filter.isEmpty()) { int cur = 0; if (_sel) { for (DialogRow *i = _contacts->list.begin; i != _sel; i = i->next) { ++cur; } - } else { - cur = (_byUsernameSel >= 0) ? (_contacts->list.count + _byUsernameSel) : -1; + if (_newItemHeight) ++cur; + } else if (_byUsernameSel >= 0) { + cur = (_contacts->list.count + _byUsernameSel); + if (_newItemHeight) ++cur; + } else if (!_newItemSel) { + cur = -1; } cur += dir; if (cur <= 0) { - _sel = _contacts->list.count ? _contacts->list.begin : 0; - _byUsernameSel = (!_contacts->list.count && !_byUsername.isEmpty()) ? 0 : -1; - } else if (cur >= _contacts->list.count) { + _newItemSel = _newItemHeight ? true : false; + _sel = (!_newItemHeight && _contacts->list.count) ? _contacts->list.begin : 0; + _byUsernameSel = (!_newItemHeight && !_contacts->list.count && !_byUsername.isEmpty()) ? 0 : -1; + } else if (cur >= _contacts->list.count + (_newItemHeight ? 1 : 0)) { + _newItemSel = false; if (_byUsername.isEmpty()) { _sel = _contacts->list.count ? _contacts->list.end->prev : 0; _byUsernameSel = -1; @@ -922,6 +969,8 @@ void ContactsInner::selectSkip(int32 dir) { if (_byUsernameSel >= _byUsername.size()) _byUsernameSel = _byUsername.size() - 1; } } else { + _newItemSel = false; + if (_newItemHeight) --cur; for (_sel = _contacts->list.begin; cur; _sel = _sel->next) { --cur; } @@ -947,17 +996,19 @@ void ContactsInner::selectSkip(int32 dir) { } if (_byUsernameSel < 0) { if (_contacts->list.count) { - if (!_sel) _sel = _contacts->list.end->prev; + if (!_newItemSel && !_sel) _sel = _contacts->list.end->prev; for (; _sel && contactData(_sel)->inchat;) { _sel = _sel->prev; } } } } - if (_sel) { - emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh); + if (_newItemSel) { + emit mustScrollTo(0, _newItemHeight); + } else if (_sel) { + emit mustScrollTo(_newItemHeight + _sel->pos * _rowHeight, _newItemHeight + (_sel->pos + 1) * _rowHeight); } else if (_byUsernameSel >= 0) { - emit mustScrollTo((_contacts->list.count + _byUsernameSel) * rh + st::searchedBarHeight, (_contacts->list.count + _byUsernameSel + 1) * rh + st::searchedBarHeight); + emit mustScrollTo(_newItemHeight + (_contacts->list.count + _byUsernameSel) * _rowHeight + st::searchedBarHeight, _newItemHeight + (_contacts->list.count + _byUsernameSel + 1) * _rowHeight + st::searchedBarHeight); } } else { int cur = (_filteredSel >= 0) ? _filteredSel : ((_byUsernameSel >= 0) ? (_filtered.size() + _byUsernameSel) : -1); @@ -1001,18 +1052,17 @@ void ContactsInner::selectSkip(int32 dir) { } } if (_filteredSel >= 0) { - emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh); + emit mustScrollTo(_filteredSel * _rowHeight, (_filteredSel + 1) * _rowHeight); } else if (_byUsernameSel >= 0) { - int skip = _filtered.size() * rh + st::searchedBarHeight; - emit mustScrollTo(skip + _byUsernameSel * rh, skip + (_byUsernameSel + 1) * rh); + int skip = _filtered.size() * _rowHeight + st::searchedBarHeight; + emit mustScrollTo(skip + _byUsernameSel * _rowHeight, skip + (_byUsernameSel + 1) * _rowHeight); } } update(); } void ContactsInner::selectSkipPage(int32 h, int32 dir) { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; - int32 points = h / rh; + int32 points = h / _rowHeight; if (!points) return; selectSkip(points * dir); } @@ -1078,87 +1128,110 @@ PeerData *ContactsInner::selectedUser() { return 0; } -ContactsBox::ContactsBox() : ItemListBox(st::boxNoTopScroll), _inner(CreatingGroupNone), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_contacts_done), st::contactsClose), -_creationRequestId(0) { +ContactsBox::ContactsBox() : ItemListBox(st::contactsScroll) +, _inner(CreatingGroupNone) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_create_group_next), st::defaultBoxButton) +, _cancel(this, lang(lng_contacts_done), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) { init(); } -ContactsBox::ContactsBox(const QString &name, const QImage &photo) : ItemListBox(st::boxNoTopScroll), _inner(CreatingGroupGroup), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_create_group_create), st::btnSelectDone), -_cancel(this, lang(lng_create_group_back), st::btnSelectCancel), -_creationRequestId(0), _creationName(name), _creationPhoto(photo) { +ContactsBox::ContactsBox(const QString &name, const QImage &photo) : ItemListBox(st::boxScroll) +, _inner(CreatingGroupGroup) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_create_group_create), st::defaultBoxButton) +, _cancel(this, lang(lng_create_group_back), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) +, _creationName(name) +, _creationPhoto(photo) { init(); } -ContactsBox::ContactsBox(ChannelData *channel) : ItemListBox(st::boxNoTopScroll), _inner(channel), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(lng_create_group_skip), st::btnSelectCancel), -_creationRequestId(0) { +ContactsBox::ContactsBox(ChannelData *channel) : ItemListBox(st::boxScroll) +, _inner(channel) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_participant_invite), st::defaultBoxButton) +, _cancel(this, lang(lng_create_group_skip), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) { init(); } -ContactsBox::ContactsBox(ChannelData *channel, MembersFilter filter, const MembersAlreadyIn &already) : ItemListBox(st::boxNoTopScroll), _inner(channel, filter, already), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(filter == MembersFilterAdmins ? lng_contacts_done : lng_box_cancel), (filter == MembersFilterAdmins ? st::contactsClose : st::btnSelectCancel)), -_creationRequestId(0) { +ContactsBox::ContactsBox(ChannelData *channel, MembersFilter filter, const MembersAlreadyIn &already) : ItemListBox((filter == MembersFilterAdmins) ? st::contactsScroll : st::boxScroll) +, _inner(channel, filter, already) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_participant_invite), st::defaultBoxButton) +, _cancel(this, lang(filter == MembersFilterAdmins ? lng_contacts_done : lng_cancel), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) { init(); } -ContactsBox::ContactsBox(ChatData *chat) : ItemListBox(st::boxNoTopScroll), _inner(chat), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(lng_box_cancel), st::btnSelectCancel), -_creationRequestId(0) { +ContactsBox::ContactsBox(ChatData *chat) : ItemListBox(st::boxScroll) +, _inner(chat) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_participant_invite), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) { init(); } -ContactsBox::ContactsBox(UserData *bot) : ItemListBox(st::boxNoTopScroll), _inner(bot), -_addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_filter(this, st::contactsFilter, lang(lng_participant_filter)), -_next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_box_cancel), st::contactsClose), -_creationRequestId(0) { +ContactsBox::ContactsBox(UserData *bot) : ItemListBox(st::contactsScroll) +, _inner(bot) +, _filter(this, st::boxSearchField, lang(lng_participant_filter)) +, _filterCancel(this, st::boxSearchCancel) +, _next(this, lang(lng_create_group_next), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _topShadow(this) +, _bottomShadow(0) +, _creationRequestId(0) { init(); } void ContactsBox::init() { - ItemListBox::init(&_inner, _cancel.height(), st::contactsAdd.height + st::old_newGroupNamePadding.top() + _filter.height() + st::old_newGroupNamePadding.bottom()); + bool inviting = (_inner.creating() == CreatingGroupGroup) || (_inner.channel() && _inner.channelFilter() == MembersFilterRecent) || _inner.chat(); + int32 topSkip = st::boxTitleHeight + _filter.height(); + int32 bottomSkip = inviting ? (st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom()) : st::boxScrollSkip; + ItemListBox::init(&_inner, bottomSkip, topSkip); - connect(&_inner, SIGNAL(chosenChanged()), this, SLOT(update())); - if (_inner.chat()) { - _addContact.hide(); - } else if (_inner.creating() != CreatingGroupNone) { - _addContact.hide(); - } else { - connect(&_addContact, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); - } + connect(&_inner, SIGNAL(chosenChanged()), this, SLOT(onChosenChanged())); + connect(&_inner, SIGNAL(addRequested()), App::wnd(), SLOT(onShowAddContact())); if (_inner.chat() || _inner.channel()) { connect(&_next, SIGNAL(clicked()), this, SLOT(onInvite())); + _bottomShadow = new ScrollableBoxShadow(this); } else if (_inner.creating() != CreatingGroupNone) { connect(&_next, SIGNAL(clicked()), this, SLOT(onCreate())); + _bottomShadow = new ScrollableBoxShadow(this); } else { _next.hide(); + _cancel.hide(); } connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); + connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel())); connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); connect(&_inner, SIGNAL(selectAllQuery()), &_filter, SLOT(selectAll())); connect(&_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername())); connect(&_inner, SIGNAL(adminAdded()), this, SIGNAL(adminAdded())); + _filterCancel.setAttribute(Qt::WA_OpaquePaintEvent); + _searchTimer.setSingleShot(true); connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername())); @@ -1166,7 +1239,7 @@ void ContactsBox::init() { } bool ContactsBox::onSearchByUsername(bool searchCache) { - QString q = _filter.text().trimmed(); + QString q = _filter.getLastText().trimmed(); if (q.isEmpty()) { if (_peopleRequest) { _peopleRequest = 0; @@ -1234,34 +1307,38 @@ bool ContactsBox::peopleFailed(const RPCError &error, mtpRequestId req) { } void ContactsBox::hideAll() { - ItemListBox::hideAll(); - _addContact.hide(); _filter.hide(); + _filterCancel.hide(); _next.hide(); _cancel.hide(); + _topShadow.hide(); + if (_bottomShadow) _bottomShadow->hide(); + ItemListBox::hideAll(); } void ContactsBox::showAll() { - ItemListBox::showAll(); _filter.show(); + if (_filter.getLastText().isEmpty()) { + _filterCancel.hide(); + } else { + _filterCancel.show(); + } if (_inner.channel() && _inner.channelFilter() == MembersFilterAdmins) { _next.hide(); - _addContact.hide(); + _cancel.hide(); } else if (_inner.chat()) { _next.show(); - _addContact.hide(); + _cancel.show(); } else if (_inner.creating() != CreatingGroupNone) { _next.show(); - _addContact.hide(); + _cancel.show(); } else { _next.hide(); - if (_inner.bot()) { - _addContact.hide(); - } else { - _addContact.show(); - } + _cancel.hide(); } - _cancel.show(); + _topShadow.show(); + if (_bottomShadow) _bottomShadow->show(); + ItemListBox::showAll(); } void ContactsBox::showDone() { @@ -1299,29 +1376,25 @@ void ContactsBox::paintEvent(QPaintEvent *e) { bool addingAdmin = _inner.channel() && _inner.channelFilter() == MembersFilterAdmins; if (_inner.chat() || _inner.creating() != CreatingGroupNone) { QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant)); - paintOldTitle(p, title, true); - - if (!addingAdmin) { - p.setPen(st::newGroupLimitFg); - p.drawTextLeft(st::old_boxTitlePos.x() + st::old_boxTitleFont->width(title) + st::addContactSkip, st::old_boxTitlePos.y(), width(), QString("%1 / %2").arg(_inner.selectedCount()).arg(cMaxGroupCount())); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); - } + QString additional(addingAdmin ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(cMaxGroupCount())); + paintTitle(p, title, additional); } else if (_inner.bot()) { - paintOldTitle(p, lang(lng_bot_choose_group), true); + paintTitle(p, lang(lng_bot_choose_group)); } else { - paintOldTitle(p, lang(lng_contacts_header), true); + paintTitle(p, lang(lng_contacts_header)); } } void ContactsBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); - _addContact.move(width() - _addContact.width(), 0); - _filter.move(st::old_newGroupNamePadding.left(), _addContact.height() + st::old_newGroupNamePadding.top()); + _filter.resize(width(), _filter.height()); + _filter.moveToLeft(0, st::boxTitleHeight); + _filterCancel.moveToRight(0, st::boxTitleHeight); _inner.resize(width(), _inner.height()); - _next.move(width() - _next.width(), height() - _next.height()); - _cancel.move(0, height() - _cancel.height()); + _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); + _topShadow.setGeometry(0, st::boxTitleHeight + _filter.height(), width(), st::lineWidth); + if (_bottomShadow) _bottomShadow->setGeometry(0, height() - st::boxButtonPadding.bottom() - _next.height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); } void ContactsBox::closePressed() { @@ -1330,20 +1403,29 @@ void ContactsBox::closePressed() { } } -void ContactsBox::onFilterUpdate() { - _scroll.scrollToY(0); - _inner.updateFilter(_filter.text()); +void ContactsBox::onFilterCancel() { + _filter.setText(QString()); } -void ContactsBox::onAdd() { - App::wnd()->replaceLayer(new AddContactBox()); +void ContactsBox::onFilterUpdate() { + _scroll.scrollToY(0); + if (_filter.getLastText().isEmpty()) { + _filterCancel.hide(); + } else { + _filterCancel.show(); + } + _inner.updateFilter(_filter.getLastText()); +} + +void ContactsBox::onChosenChanged() { + update(); } void ContactsBox::onInvite() { QVector users(_inner.selected()); if (users.isEmpty()) { _filter.setFocus(); - _filter.notaBene(); + _filter.showError(); return; } @@ -1363,7 +1445,7 @@ void ContactsBox::onCreate() { const QVector &v(users.c_vector().v); if (v.isEmpty() || (v.size() == 1 && v.at(0).type() == mtpc_inputUserSelf)) { _filter.setFocus(); - _filter.notaBene(); + _filter.showError(); return; } _creationRequestId = MTP::send(MTPmessages_CreateChat(MTP_vector(v), MTP_string(_creationName)), rpcDone(&ContactsBox::creationDone), rpcFail(&ContactsBox::creationFail)); @@ -1373,42 +1455,28 @@ void ContactsBox::onScroll() { _inner.loadProfilePhotos(_scroll.scrollTop()); } -PeerData *chatOrChannelCreated(const MTPUpdates &updates, const QImage &photo) { - App::main()->sentUpdatesReceived(updates); +void ContactsBox::creationDone(const MTPUpdates &updates) { + App::wnd()->hideLayer(); + App::main()->sentUpdatesReceived(updates); const QVector *v = 0; switch (updates.type()) { case mtpc_updates: v = &updates.c_updates().vchats.c_vector().v; break; case mtpc_updatesCombined: v = &updates.c_updatesCombined().vchats.c_vector().v; break; - default: LOG(("API Error: unexpected update cons %1 (chatOrChannelCreated)").arg(updates.type())); break; + default: LOG(("API Error: unexpected update cons %1 (ContactsBox::creationDone)").arg(updates.type())); break; } + + PeerData *peer = 0; if (v && !v->isEmpty() && v->front().type() == mtpc_chat) { - ChatData *chat = App::chat(v->front().c_chat().vid.v); - if (chat) { - if (!photo.isNull()) { - App::app()->uploadProfilePhoto(photo, chat->id); + peer = App::chat(v->front().c_chat().vid.v); + if (peer) { + if (!_creationPhoto.isNull()) { + App::app()->uploadProfilePhoto(_creationPhoto, peer->id); } - return chat; + App::main()->showPeerHistory(peer->id, ShowAtUnreadMsgId); } - } else if (v && !v->isEmpty() && v->front().type() == mtpc_channel) { - ChannelData *channel = App::channel(v->front().c_channel().vid.v); - if (channel) { - if (!photo.isNull()) { - App::app()->uploadProfilePhoto(photo, channel->id); - } - return channel; - } - } - - return 0; -} - -void ContactsBox::creationDone(const MTPUpdates &updates) { - App::wnd()->hideLayer(); - - PeerData *peer = chatOrChannelCreated(updates, _creationPhoto); - if (peer) { - App::main()->showPeerHistory(peer->id, ShowAtUnreadMsgId); + } else { + LOG(("API Error: chat not found in updates (ContactsBox::creationDone)")); } } @@ -1421,7 +1489,7 @@ bool ContactsBox::creationFail(const RPCError &error) { return true; } else if (error.type() == "USERS_TOO_FEW") { _filter.setFocus(); - _filter.notaBene(); + _filter.showError(); return true; } else if (error.type() == "PEER_FLOOD") { App::wnd()->replaceLayer(new InformBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); @@ -1430,20 +1498,26 @@ bool ContactsBox::creationFail(const RPCError &error) { return false; } -MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : _channel(channel), _filter(filter), -_kickText(lang(lng_profile_kick)), -_time(0), -_kickWidth(st::normalFont->width(_kickText)), -_sel(-1), -_kickSel(-1), -_kickDown(-1), -_mouseSel(false), -_kickConfirm(0), -_kickRequestId(0), -_kickBox(0), -_loading(true), -_loadingRequestId(0) { - connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&))); +MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget() +, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) +, _newItemHeight((channel->amCreator() && (channel->count < cMaxGroupCount() || !channel->isPublic() || filter == MembersFilterAdmins)) ? st::contactsNewItemHeight : 0) +, _newItemSel(false) +, _channel(channel) +, _filter(filter) +, _kickText(lang(lng_profile_kick)) +, _time(0) +, _kickWidth(st::normalFont->width(_kickText)) +, _sel(-1) +, _kickSel(-1) +, _kickDown(-1) +, _mouseSel(false) +, _kickConfirm(0) +, _kickRequestId(0) +, _kickBox(0) +, _loading(true) +, _loadingRequestId(0) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*))); refresh(); @@ -1465,23 +1539,32 @@ void MembersInner::paintEvent(QPaintEvent *e) { p.fillRect(r, st::white->b); int32 yFrom = r.y() - st::membersPadding.top(), yTo = r.y() + r.height() - st::membersPadding.top(); - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; - p.translate(0, st::membersPadding.top()); if (_rows.isEmpty()) { p.setFont(st::noContactsFont->f); p.setPen(st::noContactsColor->p); p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); } else { - int32 from = floorclamp(yFrom, rh, 0, _rows.size()); - int32 to = ceilclamp(yTo, rh, 0, _rows.size()); - p.translate(0, from * rh); + if (_newItemHeight) { + p.fillRect(0, 0, width(), _newItemHeight, (_newItemSel ? st::contactsBgOver : st::white)->b); + p.drawSpriteLeft(st::contactsNewItemIconPosition.x(), st::contactsNewItemIconPosition.y(), width(), st::contactsNewItemIcon); + p.setFont(st::contactsNameFont); + p.setPen(st::contactsNewItemFg); + p.drawTextLeft(st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(), st::contactsNewItemTop, width(), lang(_filter == MembersFilterAdmins ? lng_channel_add_admins : lng_channel_add_members)); + + yFrom -= _newItemHeight; + yTo -= _newItemHeight; + p.translate(0, _newItemHeight); + } + int32 from = floorclamp(yFrom, _rowHeight, 0, _rows.size()); + int32 to = ceilclamp(yTo, _rowHeight, 0, _rows.size()); + p.translate(0, from * _rowHeight); for (; from < to; ++from) { bool sel = (from == _sel); bool kickSel = (from == _kickSel && (_kickDown < 0 || from == _kickDown)); bool kickDown = kickSel && (from == _kickDown); paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown); - p.translate(0, rh); + p.translate(0, _rowHeight); } } } @@ -1491,10 +1574,10 @@ void MembersInner::enterEvent(QEvent *e) { } void MembersInner::leaveEvent(QEvent *e) { + _mouseSel = false; setMouseTracking(false); if (_sel >= 0) { - updateSelectedRow(); - _sel = -1; + clearSel(); } } @@ -1545,18 +1628,20 @@ void MembersInner::onKickConfirm() { } void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown) { - int32 left = st::profileListPadding.width(); - UserData *user = peer->asUser(); - if (sel) { - p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, st::profileHoverBG->b); + + p.fillRect(0, 0, width(), _rowHeight, (sel ? st::contactsBgOver : st::white)->b); + p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize)); + + p.setPen(st::black); + + int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); + int32 namew = width() - namex - st::contactsPadding.right() - (data->canKick ? (_kickWidth + st::contactsCheckPosition.x() * 2) : 0); + if (peer->isChannel() && peer->asChannel()->isVerified()) { + namew -= st::verifiedCheck.pxWidth() + st::verifiedCheckPos.x(); + p.drawSpriteLeft(namex + qMin(data->name.maxWidth(), namew) + st::verifiedCheckPos.x(), st::contactsPadding.top() + st::contactsNameTop + st::verifiedCheckPos.y(), width(), st::verifiedCheck); } - - p.drawPixmap(left, st::profileListPadding.height(), peer->photo->pix(st::profileListPhotoSize)); - - p.setPen(st::profileListNameColor->p); - - data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - (data->canKick ? _kickWidth : 0)); + data->name.drawElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew); if (data->canKick) { p.setFont((kickSel ? st::linkOverFont : st::linkFont)->f); @@ -1565,27 +1650,32 @@ void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, boo } else { p.setPen(st::btnDefLink.color->p); } - p.drawText(width() - _kickWidth - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::normalFont->height) / 2 + st::normalFont->ascent, _kickText); + p.drawTextRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, width(), _kickText, _kickWidth); } - p.setFont(st::normalFont); - p.setPen(st::profileOfflineColor->p); - p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online); + p.setFont(st::contactsStatusFont->f); + p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); + p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->online); } void MembersInner::selectSkip(int32 dir) { _time = unixtime(); _mouseSel = false; - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir; - int cur = (_sel >= 0) ? _sel : -1; + int cur = -1; + if (_newItemHeight && _newItemSel) { + cur = 0; + } else if (_sel >= 0) { + cur = _sel + (_newItemHeight ? 1 : 0); + } cur += dir; if (cur <= 0) { - _sel = _rows.isEmpty() ? -1 : 0; - } else if (cur >= _rows.size()) { + _newItemSel = _newItemHeight ? true : false; + _sel = (_newItemSel || _rows.isEmpty()) ? -1 : 0; + } else if (cur >= _rows.size() + (_newItemHeight ? 1 : 0)) { _sel = -1; } else { - _sel = cur; + _sel = cur - (_newItemHeight ? 1 : 0); } if (dir > 0) { if (_sel < 0 || _sel >= _rows.size()) { @@ -1593,19 +1683,20 @@ void MembersInner::selectSkip(int32 dir) { } } else { if (!_rows.isEmpty()) { - if (_sel < 0) _sel = _rows.size() - 1; + if (_sel < 0 && !_newItemSel) _sel = _rows.size() - 1; } } - if (_sel >= 0) { - emit mustScrollTo(_sel * rh, (_sel + 1) * rh); + if (_newItemSel) { + emit mustScrollTo(0, _newItemHeight); + } else if (_sel >= 0) { + emit mustScrollTo(_newItemHeight + _sel * _rowHeight, _newItemHeight + (_sel + 1) * _rowHeight); } update(); } void MembersInner::selectSkipPage(int32 h, int32 dir) { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; - int32 points = h / rh; + int32 points = h / _rowHeight; if (!points) return; selectSkip(points * dir); } @@ -1617,12 +1708,11 @@ void MembersInner::loadProfilePhotos(int32 yFrom) { if (yTo < 0) return; if (yFrom < 0) yFrom = 0; - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (!_rows.isEmpty()) { - int32 from = yFrom / rh; + int32 from = (yFrom - _newItemHeight) / _rowHeight; if (from < 0) from = 0; if (from < _rows.size()) { - int32 to = (yTo / rh) + 1; + int32 to = ((yTo - _newItemHeight) / _rowHeight) + 1; if (to > _rows.size()) to = _rows.size(); for (; from < to; ++from) { @@ -1633,7 +1723,10 @@ void MembersInner::loadProfilePhotos(int32 yFrom) { } void MembersInner::chooseParticipant() { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; + if (_newItemSel) { + emit addRequested(); + return; + } if (_sel < 0 || _sel >= _rows.size()) return; if (PeerData *peer = _rows[_sel]) { App::wnd()->hideLayer(); @@ -1642,11 +1735,10 @@ void MembersInner::chooseParticipant() { } void MembersInner::refresh() { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; if (_rows.isEmpty()) { resize(width(), st::membersPadding.top() + st::noContactsHeight + st::membersPadding.bottom()); } else { - resize(width(), st::membersPadding.top() + _rows.size() * rh + st::membersPadding.bottom()); + resize(width(), st::membersPadding.top() + _newItemHeight + _rows.size() * _rowHeight + st::membersPadding.bottom()); } update(); } @@ -1671,6 +1763,7 @@ QMap MembersInner::already() const { void MembersInner::clearSel() { updateSelectedRow(); + _newItemSel = false; _sel = _kickSel = _kickDown = -1; _lastMousePos = QCursor::pos(); updateSel(); @@ -1681,7 +1774,7 @@ MembersInner::MemberData *MembersInner::data(int32 index) { return result; } MemberData *result = _datas[index] = new MemberData(); - result->name.setText(st::profileListNameFont, _rows[index]->name, _textNameOptions); + result->name.setText(st::contactsNameFont, _rows[index]->name, _textNameOptions); result->online = lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat())); if (_filter == MembersFilterRecent) { result->canKick = (_channel->amCreator() || _channel->amEditor() || _channel->amModerator()) ? (_roles[index] == MemberRoleNone) : false; @@ -1710,17 +1803,20 @@ MembersInner::~MembersInner() { } void MembersInner::updateSel() { + if (!_mouseSel) return; + QPoint p(mapFromGlobal(_lastMousePos)); p.setY(p.y() - st::membersPadding.top()); bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos)); - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; - int32 newSel = (in && p.y() >= 0 && p.y() < _rows.size() * rh) ? (p.y() / rh) : -1; + bool newItemSel = (in && p.y() >= 0 && p.y() < _newItemHeight); + int32 newSel = (in && !newItemSel && p.y() >= _newItemHeight && p.y() < _newItemHeight + _rows.size() * _rowHeight) ? ((p.y() - _newItemHeight) / _rowHeight) : -1; int32 newKickSel = newSel; - if (newSel >= 0 && (!data(newSel)->canKick || !QRect(width() - _kickWidth - st::profileCheckDeltaX, newSel * rh + st::profileListPadding.height() + (st::profileListPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) { + if (newSel >= 0 && (!data(newSel)->canKick || !QRect(width() - _kickWidth - st::contactsPadding.right() - st::contactsCheckPosition.x(), _newItemHeight + newSel * _rowHeight + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) { newKickSel = -1; } - if (newSel != _sel || newKickSel != _kickSel) { + if (newSel != _sel || newKickSel != _kickSel || newItemSel != _newItemSel) { updateSelectedRow(); + _newItemSel = newItemSel; _sel = newSel; _kickSel = newKickSel; updateSelectedRow(); @@ -1733,19 +1829,20 @@ void MembersInner::peerUpdated(PeerData *peer) { } void MembersInner::updateSelectedRow() { + if (_newItemSel) { + update(0, st::membersPadding.top(), width(), _newItemHeight); + } if (_sel >= 0) { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; - update(0, st::membersPadding.top() + _sel * rh, width(), rh); + update(0, st::membersPadding.top() + _newItemHeight + _sel * _rowHeight, width(), _rowHeight); } } void MembersInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { - int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; for (int32 i = 0, l = _rows.size(); i < l; ++i) { if (_rows.at(i) == peer) { if (_datas.at(i)) { - _datas.at(i)->name.setText(st::profileListNameFont, peer->name, _textNameOptions); - update(0, st::membersPadding.top() + i * rh, width(), rh); + _datas.at(i)->name.setText(st::contactsNameFont, peer->name, _textNameOptions); + update(0, st::membersPadding.top() + i * _rowHeight, width(), _rowHeight); } else { break; } @@ -1877,15 +1974,13 @@ void MembersInner::removeKicked() { _kickConfirm = 0; } -MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox(st::boxScroll), _inner(channel, filter), -_add(this, lang(filter == MembersFilterRecent ? lng_participant_invite : lng_channel_add_admins), st::contactsAdd), -_done(this, lang(lng_contacts_done), st::contactsClose), -_addBox(0) { - ItemListBox::init(&_inner, _done.height()); +MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox(st::boxScroll) +, _inner(channel, filter) +, _addBox(0) { + ItemListBox::init(&_inner); - connect(&_add, SIGNAL(clicked()), this, SLOT(onAdd())); + connect(&_inner, SIGNAL(addRequested()), this, SLOT(onAdd())); - connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); @@ -1915,20 +2010,12 @@ void MembersBox::paintEvent(QPaintEvent *e) { if (paint(p)) return; QString title(lang(_inner.filter() == MembersFilterRecent ? lng_channel_members : lng_channel_admins)); - paintOldTitle(p, title, false); + paintTitle(p, title, false); } void MembersBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _inner.resize(width(), _inner.height()); - _done.move(0, height() - _done.height()); - _add.move(width() - _add.width(), 0); -} - -void MembersBox::onLoaded() { - if (!_done.isHidden() && _inner.channel()->amCreator() && (_inner.channel()->count < cMaxGroupCount() || !_inner.channel()->isPublic() || _inner.filter() == MembersFilterAdmins)) { - _add.show(); - } } void MembersBox::onScroll() { @@ -1957,707 +2044,7 @@ void MembersBox::onAdminAdded() { _loadTimer.start(ReloadChannelMembersTimeout); } -void MembersBox::hideAll() { - ItemListBox::hideAll(); - _add.hide(); - _done.hide(); -} - -void MembersBox::showAll() { - ItemListBox::showAll(); - if (_inner.channel()->amCreator() && _inner.isLoaded() && (_inner.channel()->count < cMaxGroupCount() || !_inner.channel()->isPublic() || _inner.filter() == MembersFilterAdmins)) { - _add.show(); - } else { - _add.hide(); - } - _done.show(); -} - void MembersBox::showDone() { _inner.clearSel(); setFocus(); } - -NewGroupBox::NewGroupBox() : AbstractBox(), -_group(this, qsl("group_type"), 0, lang(lng_create_group_title), true), -_channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)), -_aboutGroupWidth(width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x()), -_aboutGroup(st::normalFont, lng_create_group_about(lt_count, cMaxGroupCount()), _defaultOptions, _aboutGroupWidth), -_aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth), -_next(this, lang(lng_create_group_next), st::defaultBoxButton), -_cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { - _aboutGroupHeight = _aboutGroup.countHeight(_aboutGroupWidth); - setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _group.height() + _aboutGroupHeight + st::newGroupSkip + _channel.height() + _aboutChannel.countHeight(_aboutGroupWidth) + st::newGroupPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom()); - - connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); - connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); - - prepare(); -} - -void NewGroupBox::hideAll() { - _group.hide(); - _channel.hide(); - _cancel.hide(); - _next.hide(); -} - -void NewGroupBox::showAll() { - _group.show(); - _channel.show(); - _cancel.show(); - _next.show(); -} - -void NewGroupBox::showDone() { - setFocus(); -} - -void NewGroupBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - onNext(); - } else { - AbstractBox::keyPressEvent(e); - } -} - -void NewGroupBox::paintEvent(QPaintEvent *e) { - Painter p(this); - if (paint(p)) return; - - p.setPen(st::newGroupAboutFg->p); - - QRect aboutGroup = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _group.y() + _group.height() + st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutGroupHeight); - _aboutGroup.draw(p, aboutGroup.x(), aboutGroup.y(), aboutGroup.width()); - - QRect aboutChannel = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _channel.y() + _channel.height() + st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutGroupHeight); - _aboutChannel.draw(p, aboutChannel.x(), aboutChannel.y(), aboutChannel.width()); -} - -void NewGroupBox::resizeEvent(QResizeEvent *e) { - _group.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); - _channel.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _group.y() + _group.height() + _aboutGroupHeight + st::newGroupSkip); - - _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); - _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); -} - -void NewGroupBox::onNext() { - App::wnd()->replaceLayer(new GroupInfoBox(_group.checked() ? CreatingGroupGroup : CreatingGroupChannel, true)); -} - -GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox(), -_creating(creating), -a_photoOver(0, 0), -_a_photoOver(animFunc(this, &GroupInfoBox::animStep_photoOver)), -_photoOver(false), -_title(this, st::newGroupName, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), -_description(this, st::newGroupDescription, lang(lng_create_group_description)), -_next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::defaultBoxButton), -_cancel(this, lang(fromTypeChoose ? lng_create_group_back : lng_box_cancel), st::cancelBoxButton), -_creationRequestId(0), _createdChannel(0) { - - setMouseTracking(true); - - _description.setMaxLength(MaxChannelDescription); - _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _description.height()); - - updateMaxHeight(); - connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); - connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onNext())); - connect(&_description, SIGNAL(cancelled()), this, SLOT(onClose())); - - connect(&_title, SIGNAL(submitted(bool)), this, SLOT(onNameSubmit())); - - connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); - connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); - - prepare(); -} - -void GroupInfoBox::hideAll() { - _title.hide(); - _description.hide(); - _cancel.hide(); - _next.hide(); -} - -void GroupInfoBox::showAll() { - _title.show(); - if (_creating == CreatingGroupChannel) { - _description.show(); - } else { - _description.hide(); - } - _cancel.show(); - _next.show(); -} - -void GroupInfoBox::showDone() { - _title.setFocus(); -} - -void GroupInfoBox::paintEvent(QPaintEvent *e) { - Painter p(this); - if (paint(p)) return; - - QRect phRect(photoRect()); - if (phRect.intersects(e->rect())) { - if (_photoSmall.isNull()) { - float64 o = a_photoOver.current(); - if (o > 0) { - if (o < 1) { - QColor c; - c.setRedF(st::newGroupPhotoBg->c.redF() * (1. - o) + st::newGroupPhotoBgOver->c.redF() * o); - c.setGreenF(st::newGroupPhotoBg->c.greenF() * (1. - o) + st::newGroupPhotoBgOver->c.greenF() * o); - c.setBlueF(st::newGroupPhotoBg->c.blueF() * (1. - o) + st::newGroupPhotoBgOver->c.blueF() * o); - p.fillRect(phRect, c); - } else { - p.fillRect(phRect, st::newGroupPhotoBgOver->b); - } - } else { - p.fillRect(phRect, st::newGroupPhotoBg->b); - } - p.drawSprite(phRect.topLeft() + st::newGroupPhotoIconPosition, st::newGroupPhotoIcon); - } else { - p.drawPixmap(phRect.topLeft(), _photoSmall); - } - if (phRect.contains(e->rect())) { - return; - } - } -} - -void GroupInfoBox::resizeEvent(QResizeEvent *e) { - int32 nameLeft = st::newGroupPhotoSize + st::newGroupNamePosition.x(); - _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)) - nameLeft, _title.height()); - _title.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); - - _description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::newGroupDescriptionPadding.top()); - - _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); - _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); -} - -void GroupInfoBox::mouseMoveEvent(QMouseEvent *e) { - updateSelected(e->globalPos()); -} - -void GroupInfoBox::updateSelected(const QPoint &cursorGlobalPosition) { - QPoint p(mapFromGlobal(cursorGlobalPosition)); - - bool photoOver = photoRect().contains(p); - if (photoOver != _photoOver) { - _photoOver = photoOver; - if (_photoSmall.isNull()) { - a_photoOver.start(_photoOver ? 1 : 0); - _a_photoOver.start(); - } - } - - setCursor(_photoOver ? style::cur_pointer : style::cur_default); -} - -void GroupInfoBox::mousePressEvent(QMouseEvent *e) { - mouseMoveEvent(e); - if (_photoOver) { - onPhoto(); - } -} - -void GroupInfoBox::leaveEvent(QEvent *e) { - updateSelected(QCursor::pos()); -} - -bool GroupInfoBox::animStep_photoOver(float64 ms) { - float64 dt = ms / st::setPhotoDuration; - bool res = true; - if (dt >= 1) { - res = false; - a_photoOver.finish(); - } else { - a_photoOver.update(dt, anim::linear); - } - update(photoRect()); - return res; -} - -void GroupInfoBox::onNameSubmit() { - if (_title.getLastText().trimmed().isEmpty()) { - _title.setFocus(); - _title.showError(); - } else if (_description.isHidden()) { - onNext(); - } else { - _description.setFocus(); - } -} - -void GroupInfoBox::onNext() { - if (_creationRequestId) return; - - QString title = _title.getLastText().trimmed(); - if (title.isEmpty()) { - _title.setFocus(); - _title.showError(); - return; - } - if (_creating == CreatingGroupGroup) { - App::wnd()->replaceLayer(new ContactsBox(title, _photoBig)); - } else { - _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(title), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); - } -} - -void GroupInfoBox::creationDone(const MTPUpdates &updates) { - PeerData *result = chatOrChannelCreated(updates, _photoBig); - if (!result || !result->isChannel()) { - onClose(); - } else { - _createdChannel = result->asChannel(); - _creationRequestId = MTP::send(MTPchannels_ExportInvite(_createdChannel->inputChannel), rpcDone(&GroupInfoBox::exportDone)); - } -} - -bool GroupInfoBox::creationFail(const RPCError &error) { - if (mtpIsFlood(error)) return false; - - _creationRequestId = 0; - if (error.type() == "NO_CHAT_TITLE") { - _title.setFocus(); - _title.showError(); - return true; - } else if (error.type() == "PEER_FLOOD") { - App::wnd()->replaceLayer(new InformBox(lng_cant_invite_not_contact_channel(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); - return true; - } - return false; -} - -void GroupInfoBox::exportDone(const MTPExportedChatInvite &result) { - _creationRequestId = 0; - if (result.type() == mtpc_chatInviteExported) { - _createdChannel->invitationUrl = qs(result.c_chatInviteExported().vlink); - } - App::wnd()->showLayer(new SetupChannelBox(_createdChannel)); -} - -void GroupInfoBox::onDescriptionResized() { - updateMaxHeight(); - update(); -} - -QRect GroupInfoBox::photoRect() const { - return myrtlrect(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top(), st::newGroupPhotoSize, st::newGroupPhotoSize); -} - -void GroupInfoBox::updateMaxHeight() { - int32 h = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom(); - if (_creating == CreatingGroupChannel) { - h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); - } - setMaxHeight(h); -} - -void GroupInfoBox::onPhoto() { - QStringList imgExtensions(cImgExtensions()); - QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); - - QImage img; - QString file; - QByteArray remoteContent; - if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { - if (!remoteContent.isEmpty()) { - img = App::readImage(remoteContent); - } else { - if (!file.isEmpty()) { - img = App::readImage(file); - } - } - } else { - return; - } - - if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { - return; - } - PhotoCropBox *box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0), false); - connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&))); - App::wnd()->replaceLayer(box); -} - -void GroupInfoBox::onPhotoReady(const QImage &img) { - _photoBig = img; - _photoSmall = QPixmap::fromImage(img.scaled(st::newGroupPhotoSize * cIntRetinaFactor(), st::newGroupPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); - _photoSmall.setDevicePixelRatio(cRetinaFactor()); -} - -SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox(), -_channel(channel), -_existing(existing), -_public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true), -_private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title)), -_comments(this, lang(lng_create_channel_comments), false), -_aboutPublicWidth(width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x()), -_aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth), -_aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth), -_aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth), -_link(this, st::newGroupLink, QString(), channel->username, true), -_linkOver(false), -_save(this, lang(lng_settings_save), st::defaultBoxButton), -_skip(this, lang(existing ? lng_box_cancel : lng_create_group_skip), st::cancelBoxButton), -_tooMuchUsernames(false), -_saveRequestId(0), _checkRequestId(0), -a_goodOpacity(0, 0), _a_goodFade(animFunc(this, &SetupChannelBox::animStep_goodFade)) { - setMouseTracking(true); - - _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); - - _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); - setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); - - connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); - connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); - _comments.hide(); - - connect(&_link, SIGNAL(changed()), this, SLOT(onChange())); - - _checkTimer.setSingleShot(true); - connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); - - connect(&_public, SIGNAL(changed()), this, SLOT(onPrivacyChange())); - connect(&_private, SIGNAL(changed()), this, SLOT(onPrivacyChange())); - - prepare(); -} - -void SetupChannelBox::hideAll() { - _public.hide(); - _private.hide(); - _comments.hide(); - _link.hide(); - _save.hide(); - _skip.hide(); -} - -void SetupChannelBox::showAll() { - _public.show(); - _private.show(); - //_comments.show(); - if (_public.checked()) { - _link.show(); - } else { - _link.hide(); - } - _save.show(); - _skip.show(); -} - -void SetupChannelBox::showDone() { - _link.setFocus(); -} - -void SetupChannelBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - if (_link.hasFocus()) { - if (_link.text().trimmed().isEmpty()) { - _link.setFocus(); - _link.showError(); - } else { - onSave(); - } - } - } else { - AbstractBox::keyPressEvent(e); - } -} - -void SetupChannelBox::paintEvent(QPaintEvent *e) { - Painter p(this); - if (paint(p)) return; - - p.setPen(st::newGroupAboutFg); - - QRect aboutPublic = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _public.y() + _public.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); - _aboutPublic.draw(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width()); - - QRect aboutPrivate = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _private.y() + _private.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); - _aboutPrivate.draw(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width()); - - //QRect aboutComments = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _comments.y() + _comments.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); - //_aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); - - p.setPen(st::black); - p.setFont(st::newGroupLinkFont); - p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::newGroupLink.textMargins.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link)); - - if (_link.isHidden()) { - QTextOption option(style::al_left); - option.setWrapMode(QTextOption::WrapAnywhere); - p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); - p.setPen(st::btnDefLink.color); - p.drawText(_invitationLink, _channel->invitationUrl, option); - if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { - p.setOpacity(a_goodOpacity.current()); - p.setPen(st::setGoodColor); - p.setFont(st::boxTextFont); - p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); - p.setOpacity(1); - } - } else { - if (!_errorText.isEmpty()) { - p.setPen(st::setErrColor); - p.setFont(st::boxTextFont); - p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText); - } else if (!_goodText.isEmpty()) { - p.setPen(st::setGoodColor); - p.setFont(st::boxTextFont); - p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText); - } - } -} - -void SetupChannelBox::resizeEvent(QResizeEvent *e) { - _public.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); - _private.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip); - //_comments.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip); - - _link.resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _link.height()); - //_link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); - _link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); - _invitationLink = QRect(_link.x(), _link.y() + (_link.height() / 2) - st::boxTextFont->height, _link.width(), 2 * st::boxTextFont->height); - - _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); - _skip.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); -} - -void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) { - updateSelected(e->globalPos()); -} - -void SetupChannelBox::mousePressEvent(QMouseEvent *e) { - mouseMoveEvent(e); - if (_linkOver) { - App::app()->clipboard()->setText(_channel->invitationUrl); - _goodTextLink = lang(lng_create_channel_link_copied); - a_goodOpacity = anim::fvalue(1, 0); - _a_goodFade.start(); - } -} - -void SetupChannelBox::leaveEvent(QEvent *e) { - updateSelected(QCursor::pos()); -} - -void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) { - QPoint p(mapFromGlobal(cursorGlobalPosition)); - - bool linkOver = _invitationLink.contains(p); - if (linkOver != _linkOver) { - _linkOver = linkOver; - update(); - setCursor(_linkOver ? style::cur_pointer : style::cur_default); - } -} - -bool SetupChannelBox::animStep_goodFade(float64 ms) { - float dt = ms / st::newGroupLinkFadeDuration; - bool res = true; - if (dt >= 1) { - res = false; - a_goodOpacity.finish(); - } else { - a_goodOpacity.update(dt, anim::linear); - } - update(); - return res; -} - -void SetupChannelBox::closePressed() { - if (!_existing) { - App::wnd()->showLayer(new ContactsBox(_channel)); - } -} - -void SetupChannelBox::onSave() { - if (!_public.checked()) { - if (!_existing && !_comments.isHidden() && _comments.checked()) { - MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true))); - } - if (_existing) { - _sentUsername = QString(); - _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); - } else { - onClose(); - } - } - - if (_saveRequestId) return; - - QString link = _link.text().trimmed(); - if (link.isEmpty()) { - _link.setFocus(); - _link.showError(); - return; - } - - if (!_existing && !_comments.isHidden() && _comments.checked()) { - MTP::send(MTPchannels_ToggleComments(_channel->inputChannel, MTP_bool(true)), RPCResponseHandler(), 0, 5); - } - _sentUsername = link; - _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); -} - -void SetupChannelBox::onChange() { - QString name = _link.text().trimmed(); - if (name.isEmpty()) { - if (!_errorText.isEmpty() || !_goodText.isEmpty()) { - _errorText = _goodText = QString(); - update(); - } - _checkTimer.stop(); - } else { - int32 i, len = name.size(); - for (int32 i = 0; i < len; ++i) { - QChar ch = name.at(i); - if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') { - if (_errorText != lang(lng_create_channel_link_bad_symbols)) { - _errorText = lang(lng_create_channel_link_bad_symbols); - update(); - } - _checkTimer.stop(); - return; - } - } - if (name.size() < MinUsernameLength) { - if (_errorText != lang(lng_create_channel_link_too_short)) { - _errorText = lang(lng_create_channel_link_too_short); - update(); - } - _checkTimer.stop(); - } else { - if (!_errorText.isEmpty() || !_goodText.isEmpty()) { - _errorText = _goodText = QString(); - update(); - } - _checkTimer.start(UsernameCheckTimeout); - } - } -} - -void SetupChannelBox::onCheck() { - if (_checkRequestId) { - MTP::cancel(_checkRequestId); - } - QString link = _link.text().trimmed(); - if (link.size() >= MinUsernameLength) { - _checkUsername = link; - _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string(link)), rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail)); - } -} - -void SetupChannelBox::onPrivacyChange() { - if (_public.checked()) { - if (_tooMuchUsernames) { - _private.setChecked(true); - App::wnd()->replaceLayer(new InformBox(lang(lng_channels_too_much_public))); - return; - } - _link.show(); - _link.setFocus(); - } else { - _link.hide(); - setFocus(); - } - update(); -} - -void SetupChannelBox::onUpdateDone(const MTPBool &result) { - _channel->setName(textOneLine(_channel->name), _sentUsername); - onClose(); -} - -bool SetupChannelBox::onUpdateFail(const RPCError &error) { - if (mtpIsFlood(error)) return false; - - _saveRequestId = 0; - QString err(error.type()); - if (err == "USERNAME_NOT_MODIFIED" || _sentUsername == _channel->username) { - _channel->setName(textOneLine(_channel->name), textOneLine(_sentUsername)); - onClose(); - return true; - } else if (err == "USERNAME_INVALID") { - _link.setFocus(); - _link.showError(); - _errorText = lang(lng_create_channel_link_invalid); - update(); - return true; - } else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") { - _link.setFocus(); - _link.showError(); - _errorText = lang(lng_create_channel_link_occupied); - update(); - return true; - } - _link.setFocus(); - return true; -} - -void SetupChannelBox::onCheckDone(const MTPBool &result) { - _checkRequestId = 0; - QString newError = (result.v || _checkUsername == _channel->username) ? QString() : lang(lng_create_channel_link_occupied); - QString newGood = newError.isEmpty() ? lang(lng_create_channel_link_available) : QString(); - if (_errorText != newError || _goodText != newGood) { - _errorText = newError; - _goodText = newGood; - update(); - } -} - -bool SetupChannelBox::onCheckFail(const RPCError &error) { - if (mtpIsFlood(error)) return false; - - _checkRequestId = 0; - QString err(error.type()); - if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") { - if (_existing) { - App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); - } else { - _tooMuchUsernames = true; - _private.setChecked(true); - onPrivacyChange(); - } - return true; - } else if (err == "USERNAME_INVALID") { - _errorText = lang(lng_create_channel_link_invalid); - update(); - return true; - } else if (err == "USERNAME_OCCUPIED" && _checkUsername != _channel->username) { - _errorText = lang(lng_create_channel_link_occupied); - update(); - return true; - } - _goodText = QString(); - _link.setFocus(); - return true; -} - -bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { - if (mtpIsFlood(error)) return false; - - _checkRequestId = 0; - QString err(error.type()); - if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") { - if (_existing) { - App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing))); - } else { - _tooMuchUsernames = true; - _private.setChecked(true); - onPrivacyChange(); - } - return true; - } - _goodText = QString(); - _link.setFocus(); - return true; -} diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index b198e956f..6d2a63fd9 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -22,12 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "abstractbox.h" -enum CreatingGroupType { - CreatingGroupNone, - CreatingGroupGroup, - CreatingGroupChannel, -}; - enum MembersFilter { MembersFilterRecent, MembersFilterAdmins, @@ -96,6 +90,7 @@ signals: void searchByUsername(); void chosenChanged(); void adminAdded(); + void addRequested(); public slots: @@ -115,6 +110,9 @@ private: void addAdminDone(const MTPBool &result, mtpRequestId req); bool addAdminFail(const RPCError &error, mtpRequestId req); + int32 _rowHeight, _newItemHeight; + bool _newItemSel; + ChatData *_chat; ChannelData *_channel; MembersFilter _channelFilter; @@ -194,9 +192,10 @@ signals: public slots: void onFilterUpdate(); + void onFilterCancel(); + void onChosenChanged(); void onScroll(); - void onAdd(); void onInvite(); void onCreate(); @@ -214,12 +213,14 @@ private: void init(); ContactsInner _inner; - FlatButton _addContact; - FlatInput _filter; + InputField _filter; + IconedButton _filterCancel; - FlatButton _next, _cancel; + BoxButton _next, _cancel; MembersFilter _membersFilter; + ScrollableBoxShadow _topShadow, *_bottomShadow; + void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req); bool peopleFailed(const RPCError &error, mtpRequestId req); @@ -286,7 +287,7 @@ public: signals: void mustScrollTo(int ymin, int ymax); - + void addRequested(); void loaded(); public slots: @@ -314,6 +315,9 @@ private: void clear(); + int32 _rowHeight, _newItemHeight; + bool _newItemSel; + ChannelData *_channel; MembersFilter _filter; @@ -374,7 +378,6 @@ public: public slots: - void onLoaded(); void onScroll(); void onAdd(); @@ -382,179 +385,13 @@ public slots: protected: - void hideAll(); - void showAll(); void showDone(); private: MembersInner _inner; - FlatButton _add, _done; ContactsBox *_addBox; SingleTimer _loadTimer; }; - -class NewGroupBox : public AbstractBox { - Q_OBJECT - -public: - - NewGroupBox(); - void keyPressEvent(QKeyEvent *e); - void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); - -public slots: - - void onNext(); - -protected: - - void hideAll(); - void showAll(); - void showDone(); - -private: - - Radiobutton _group, _channel; - int32 _aboutGroupWidth, _aboutGroupHeight; - Text _aboutGroup, _aboutChannel; - BoxButton _next, _cancel; - -}; - -class GroupInfoBox : public AbstractBox, public RPCSender { - Q_OBJECT - -public: - - GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose); - void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void mousePressEvent(QMouseEvent *e); - void leaveEvent(QEvent *e); - - bool animStep_photoOver(float64 ms); - - void setInnerFocus() { - _title.setFocus(); - } - -public slots: - - void onPhoto(); - void onPhotoReady(const QImage &img); - - void onNext(); - void onNameSubmit(); - void onDescriptionResized(); - -protected: - - void hideAll(); - void showAll(); - void showDone(); - -private: - - QRect photoRect() const; - - void updateMaxHeight(); - void updateSelected(const QPoint &cursorGlobalPosition); - CreatingGroupType _creating; - - anim::fvalue a_photoOver; - Animation _a_photoOver; - bool _photoOver; - - InputField _title; - InputArea _description; - - QImage _photoBig; - QPixmap _photoSmall; - BoxButton _next, _cancel; - - // channel creation - int32 _creationRequestId; - ChannelData *_createdChannel; - - void creationDone(const MTPUpdates &updates); - bool creationFail(const RPCError &e); - void exportDone(const MTPExportedChatInvite &result); -}; - -class SetupChannelBox : public AbstractBox, public RPCSender { - Q_OBJECT - -public: - - SetupChannelBox(ChannelData *channel, bool existing = false); - void keyPressEvent(QKeyEvent *e); - void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void mousePressEvent(QMouseEvent *e); - void leaveEvent(QEvent *e); - - void closePressed(); - - void setInnerFocus() { - if (_link.isHidden()) { - setFocus(); - } else { - _link.setFocus(); - } - } - -public slots: - - void onSave(); - void onChange(); - void onCheck(); - - void onPrivacyChange(); - -protected: - - void hideAll(); - void showAll(); - void showDone(); - -private: - - void updateSelected(const QPoint &cursorGlobalPosition); - bool animStep_goodFade(float64 ms); - - void onUpdateDone(const MTPBool &result); - bool onUpdateFail(const RPCError &error); - - void onCheckDone(const MTPBool &result); - bool onCheckFail(const RPCError &error); - bool onFirstCheckFail(const RPCError &error); - - ChannelData *_channel; - bool _existing; - - Radiobutton _public, _private; - Checkbox _comments; - int32 _aboutPublicWidth, _aboutPublicHeight; - Text _aboutPublic, _aboutPrivate, _aboutComments; - UsernameInput _link; - QRect _invitationLink; - bool _linkOver; - BoxButton _save, _skip; - - bool _tooMuchUsernames; - - mtpRequestId _saveRequestId, _checkRequestId; - QString _sentUsername, _checkUsername, _errorText, _goodText; - - QString _goodTextLink; - anim::fvalue a_goodOpacity; - Animation _a_goodFade; - - QTimer _checkTimer; -}; diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.cpp b/Telegram/SourceFiles/boxes/downloadpathbox.cpp index 3dc30241e..f9a53d54c 100644 --- a/Telegram/SourceFiles/boxes/downloadpathbox.cpp +++ b/Telegram/SourceFiles/boxes/downloadpathbox.cpp @@ -33,7 +33,7 @@ DownloadPathBox::DownloadPathBox() : _dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp")), _pathLink(this, QString(), st::defaultBoxLinkButton), _save(this, lang(lng_connection_save), st::defaultBoxButton), - _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { + _cancel(this, lang(lng_cancel), st::cancelBoxButton) { connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); @@ -143,6 +143,6 @@ void DownloadPathBox::onSave() { } void DownloadPathBox::setPathText(const QString &text) { - int32 availw = st::boxWideWidth - st::boxPadding.left() - st::defaultRadiobutton.textPosition.x() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)); + int32 availw = st::boxWideWidth - st::boxPadding.left() - st::defaultRadiobutton.textPosition.x() - st::boxPadding.right(); _pathLink.setText(st::boxTextFont->elided(text, availw)); } diff --git a/Telegram/SourceFiles/boxes/emojibox.cpp b/Telegram/SourceFiles/boxes/emojibox.cpp index 106d38944..a5b483747 100644 --- a/Telegram/SourceFiles/boxes/emojibox.cpp +++ b/Telegram/SourceFiles/boxes/emojibox.cpp @@ -71,14 +71,14 @@ namespace { const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 7; } -EmojiBox::EmojiBox() : _esize(EmojiSizes[EIndex + 1]), _done(this, lang(lng_about_done), st::aboutCloseButton) { +EmojiBox::EmojiBox() : _esize(EmojiSizes[EIndex + 1]) { + setBlueTitle(true); + fillBlocks(); _blockHeight = st::emojiReplaceInnerHeight; - resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + (st::emojiReplaceWidth - _esize), st::boxPadding.top() + st::boxFont->height + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + _done.height()); - - connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); + resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + 2 * st::emojiReplacePadding, st::boxTitleHeight + st::emojiReplacePadding + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + st::emojiReplacePadding); prepare(); } @@ -113,14 +113,6 @@ void EmojiBox::fillBlocks() { } } -void EmojiBox::hideAll() { - _done.hide(); -} - -void EmojiBox::showAll() { - _done.show(); -} - void EmojiBox::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { onClose(); @@ -130,14 +122,14 @@ void EmojiBox::keyPressEvent(QKeyEvent *e) { } void EmojiBox::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); if (paint(p)) return; - paintGrayTitle(p, lang(lng_settings_emoji_list)); + paintTitle(p, lang(lng_settings_emoji_list)); p.setFont(st::emojiTextFont->f); p.setPen(st::black->p); - int32 top = st::boxPadding.top() + st::boxFont->height + (st::emojiReplaceHeight - _blockHeight) / 2; + int32 top = st::boxTitleHeight + st::emojiReplacePadding + (st::emojiReplaceHeight - _blockHeight) / 2; for (Blocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { int32 rowSize = i->size(), left = (width() - rowSize * st::emojiReplaceWidth) / 2; for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) { @@ -151,7 +143,3 @@ void EmojiBox::paintEvent(QPaintEvent *e) { top += st::emojiReplaceHeight; } } - -void EmojiBox::resizeEvent(QResizeEvent *e) { - _done.setGeometry(0, height() - _done.height(), width(), _done.height()); -} diff --git a/Telegram/SourceFiles/boxes/emojibox.h b/Telegram/SourceFiles/boxes/emojibox.h index 8e613576c..405fd127b 100644 --- a/Telegram/SourceFiles/boxes/emojibox.h +++ b/Telegram/SourceFiles/boxes/emojibox.h @@ -30,19 +30,12 @@ public: EmojiBox(); void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); - -protected: - - void hideAll(); - void showAll(); private: void fillBlocks(); int32 _esize; - BottomButton _done; int32 _blockHeight; struct Block { diff --git a/Telegram/SourceFiles/boxes/languagebox.cpp b/Telegram/SourceFiles/boxes/languagebox.cpp index a9918515f..c1aae95e6 100644 --- a/Telegram/SourceFiles/boxes/languagebox.cpp +++ b/Telegram/SourceFiles/boxes/languagebox.cpp @@ -112,15 +112,15 @@ void LanguageBox::onChange() { if (_langs[i]->checked() && langId != cLang()) { LangLoaderResult result; if (langId > 0) { - LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[langId] + qsl(".strings"), LangLoaderRequest(lng_sure_save_language, lng_box_cancel, lng_box_ok)); + LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[langId] + qsl(".strings"), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok)); result = loader.found(); } else if (langId == languageTest) { - LangLoaderPlain loader(cLangFile(), LangLoaderRequest(lng_sure_save_language, lng_box_cancel, lng_box_ok)); + LangLoaderPlain loader(cLangFile(), LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok)); result = loader.found(); } QString text = result.value(lng_sure_save_language, langOriginal(lng_sure_save_language)), save = result.value(lng_box_ok, langOriginal(lng_box_ok)), - cancel = result.value(lng_box_cancel, langOriginal(lng_box_cancel)); + cancel = result.value(lng_cancel, langOriginal(lng_cancel)); ConfirmBox *box = new ConfirmBox(text, save, st::defaultBoxButton, cancel); connect(box, SIGNAL(confirmed()), this, SLOT(onSave())); connect(box, SIGNAL(closed()), this, SLOT(onRestore())); diff --git a/Telegram/SourceFiles/boxes/passcodebox.cpp b/Telegram/SourceFiles/boxes/passcodebox.cpp index 6bba1adb8..ca01abfb3 100644 --- a/Telegram/SourceFiles/boxes/passcodebox.cpp +++ b/Telegram/SourceFiles/boxes/passcodebox.cpp @@ -29,14 +29,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org PasscodeBox::PasscodeBox(bool turningOff) : _replacedBy(0), _turningOff(turningOff), _cloudPwd(false), _setRequest(0), _hasRecovery(false), _skipEmailWarning(false), _aboutHeight(0), -_about(st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right()), -_saveButton(this, lang(_turningOff ? lng_passcode_remove_button : lng_settings_save), st::btnSelectDone), -_cancelButton(this, lang(lng_cancel), st::btnSelectCancel), -_oldPasscode(this, st::inpAddContact, lang(lng_passcode_enter_old)), -_newPasscode(this, st::inpAddContact, lang(cHasPasscode() ? lng_passcode_enter_new : lng_passcode_enter_first)), -_reenterPasscode(this, st::inpAddContact, lang(lng_passcode_confirm_new)), -_passwordHint(this, st::inpAddContact, lang(lng_cloud_password_hint)), -_recoverEmail(this, st::inpAddContact, lang(lng_cloud_password_email)), +_about(st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right()), +_saveButton(this, lang(_turningOff ? lng_passcode_remove_button : lng_settings_save), st::defaultBoxButton), +_cancelButton(this, lang(lng_cancel), st::cancelBoxButton), +_oldPasscode(this, st::defaultInputField, lang(lng_passcode_enter_old)), +_newPasscode(this, st::defaultInputField, lang(cHasPasscode() ? lng_passcode_enter_new : lng_passcode_enter_first)), +_reenterPasscode(this, st::defaultInputField, lang(lng_passcode_confirm_new)), +_passwordHint(this, st::defaultInputField, lang(lng_cloud_password_hint)), +_recoverEmail(this, st::defaultInputField, lang(lng_cloud_password_email)), _recover(this, lang(lng_signin_recover)) { init(); prepare(); @@ -44,14 +44,14 @@ _recover(this, lang(lng_signin_recover)) { PasscodeBox::PasscodeBox(const QByteArray &newSalt, const QByteArray &curSalt, bool hasRecovery, const QString &hint, bool turningOff) : _replacedBy(0), _turningOff(turningOff), _cloudPwd(true), _setRequest(0), _newSalt(newSalt), _curSalt(curSalt), _hasRecovery(hasRecovery), _skipEmailWarning(false), _hint(hint), _aboutHeight(0), -_about(st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right()), -_saveButton(this, lang(_turningOff ? lng_passcode_remove_button : lng_settings_save), st::btnSelectDone), -_cancelButton(this, lang(lng_cancel), st::btnSelectCancel), -_oldPasscode(this, st::inpAddContact, lang(lng_cloud_password_enter_old)), -_newPasscode(this, st::inpAddContact, lang(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new)), -_reenterPasscode(this, st::inpAddContact, lang(lng_cloud_password_confirm_new)), -_passwordHint(this, st::inpAddContact, lang(lng_cloud_password_hint)), -_recoverEmail(this, st::inpAddContact, lang(lng_cloud_password_email)), +_about(st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right()), +_saveButton(this, lang(_turningOff ? lng_passcode_remove_button : lng_settings_save), st::defaultBoxButton), +_cancelButton(this, lang(lng_cancel), st::cancelBoxButton), +_oldPasscode(this, st::defaultInputField, lang(lng_cloud_password_enter_old)), +_newPasscode(this, st::defaultInputField, lang(curSalt.isEmpty() ? lng_cloud_password_enter_first : lng_cloud_password_enter_new)), +_reenterPasscode(this, st::defaultInputField, lang(lng_cloud_password_confirm_new)), +_passwordHint(this, st::defaultInputField, lang(lng_cloud_password_hint)), +_recoverEmail(this, st::defaultInputField, lang(lng_cloud_password_email)), _recover(this, lang(lng_signin_recover)) { init(); prepare(); @@ -60,24 +60,24 @@ _recover(this, lang(lng_signin_recover)) { void PasscodeBox::init() { _about.setRichText(st::normalFont, lang(_cloudPwd ? lng_cloud_password_about : lng_passcode_about)); if (!_hint.isEmpty()) _hintText.setText(st::normalFont, lng_signin_hint(lt_password_hint, _hint)); - _aboutHeight = _about.countHeight(st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right()); + _aboutHeight = _about.countHeight(st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right()); _oldPasscode.setEchoMode(QLineEdit::Password); _newPasscode.setEchoMode(QLineEdit::Password); _reenterPasscode.setEchoMode(QLineEdit::Password); if (_turningOff) { _oldPasscode.show(); _boxTitle = lang(_cloudPwd ? lng_cloud_password_remove : lng_passcode_remove); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 1 * _oldPasscode.height() + st::usernameSkip + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::addContactPadding.bottom() + _saveButton.height()); + setMaxHeight(st::boxTitleHeight + st::contactPadding.top() + 1 * _oldPasscode.height() + st::usernameSkip + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::contactPadding.bottom() + _saveButton.height()); } else { bool has = _cloudPwd ? (!_curSalt.isEmpty()) : cHasPasscode(); if (has) { _oldPasscode.show(); _boxTitle = lang(_cloudPwd ? lng_cloud_password_change : lng_passcode_change); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _oldPasscode.height() + st::usernameSkip * 2 + 1 * st::addContactSkip + (_cloudPwd ? _passwordHint.height() + st::addContactSkip : 0) + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::addContactPadding.bottom() + _saveButton.height()); + setMaxHeight(st::boxTitleHeight + st::contactPadding.top() + 3 * _oldPasscode.height() + st::usernameSkip * 2 + 1 * st::contactSkip + (_cloudPwd ? _passwordHint.height() + st::contactSkip : 0) + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::contactPadding.bottom() + _saveButton.height()); } else { _oldPasscode.hide(); _boxTitle = lang(_cloudPwd ? lng_cloud_password_create : lng_passcode_create); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _oldPasscode.height() + st::usernameSkip + 1 * st::addContactSkip + (_cloudPwd ? _passwordHint.height() + st::addContactSkip : 0) + _aboutHeight + (_cloudPwd ? st::addContactSkip + _recoverEmail.height() + st::usernameSkip : st::addContactPadding.bottom()) + _saveButton.height()); + setMaxHeight(st::boxTitleHeight + st::contactPadding.top() + 2 * _oldPasscode.height() + st::usernameSkip + 1 * st::contactSkip + (_cloudPwd ? _passwordHint.height() + st::contactSkip : 0) + _aboutHeight + (_cloudPwd ? st::contactSkip + _recoverEmail.height() + st::usernameSkip : st::contactPadding.bottom()) + _saveButton.height()); } } @@ -158,12 +158,12 @@ void PasscodeBox::keyPressEvent(QKeyEvent *e) { } else if (_reenterPasscode.hasFocus()) { if (has && _oldPasscode.text().isEmpty()) { _oldPasscode.setFocus(); - _oldPasscode.notaBene(); + _oldPasscode.showError(); } else if (_newPasscode.text().isEmpty()) { _newPasscode.setFocus(); - _newPasscode.notaBene(); + _newPasscode.showError(); } else if (_reenterPasscode.text().isEmpty()) { - _reenterPasscode.notaBene(); + _reenterPasscode.showError(); } else if (!_passwordHint.isHidden()) { _passwordHint.setFocus(); } else { @@ -187,19 +187,16 @@ void PasscodeBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintOldTitle(p, _boxTitle, true); + paintTitle(p, _boxTitle); - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - int32 w = width() - st::addContactPadding.left() - st::addContactPadding.right(); - int32 abouty = (_passwordHint.isHidden() ? (_reenterPasscode.isHidden() ? _oldPasscode : _reenterPasscode).y() + st::usernameSkip : _passwordHint.y() + st::addContactSkip) + _oldPasscode.height(); + int32 w = width() - st::boxPadding.left() - st::boxPadding.right(); + int32 abouty = (_passwordHint.isHidden() ? (_reenterPasscode.isHidden() ? _oldPasscode : _reenterPasscode).y() + st::usernameSkip : _passwordHint.y() + st::contactSkip) + _oldPasscode.height(); p.setPen(st::black); - _about.draw(p, st::addContactPadding.left(), abouty, w); + _about.draw(p, st::boxPadding.left(), abouty, w); if (!_hint.isEmpty() && _oldError.isEmpty()) { p.setPen(st::black->p); - _hintText.drawElided(p, st::addContactPadding.left(), _oldPasscode.y() + _oldPasscode.height() + ((st::usernameSkip - st::normalFont->height) / 2), w, 1, style::al_top); + _hintText.drawElided(p, st::boxPadding.left(), _oldPasscode.y() + _oldPasscode.height() + ((st::usernameSkip - st::normalFont->height) / 2), w, 1, style::al_top); } if (!_oldError.isEmpty()) { @@ -216,25 +213,22 @@ void PasscodeBox::paintEvent(QPaintEvent *e) { p.setPen(st::setErrColor->p); p.drawText(QRect(0, _recoverEmail.y() + _recoverEmail.height(), width(), st::usernameSkip), _emailError, style::al_center); } - - // paint button sep - p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void PasscodeBox::resizeEvent(QResizeEvent *e) { bool has = _cloudPwd ? (!_curSalt.isEmpty()) : cHasPasscode(); - _oldPasscode.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _oldPasscode.height()); - _newPasscode.setGeometry(st::addContactPadding.left(), _oldPasscode.y() + ((_turningOff || has) ? (_oldPasscode.height() + st::usernameSkip) : 0), _oldPasscode.width(), _oldPasscode.height()); - _reenterPasscode.setGeometry(st::addContactPadding.left(), _newPasscode.y() + _newPasscode.height() + st::addContactSkip, _newPasscode.width(), _newPasscode.height()); - _passwordHint.setGeometry(st::addContactPadding.left(), _reenterPasscode.y() + _reenterPasscode.height() + st::usernameSkip, _reenterPasscode.width(), _reenterPasscode.height()); + _oldPasscode.setGeometry(st::boxPadding.left(), st::boxTitleHeight + st::contactPadding.top(), width() - st::boxPadding.left() - st::boxPadding.right(), _oldPasscode.height()); + _newPasscode.setGeometry(st::boxPadding.left(), _oldPasscode.y() + ((_turningOff || has) ? (_oldPasscode.height() + st::usernameSkip) : 0), _oldPasscode.width(), _oldPasscode.height()); + _reenterPasscode.setGeometry(st::boxPadding.left(), _newPasscode.y() + _newPasscode.height() + st::contactSkip, _newPasscode.width(), _newPasscode.height()); + _passwordHint.setGeometry(st::boxPadding.left(), _reenterPasscode.y() + _reenterPasscode.height() + st::usernameSkip, _reenterPasscode.width(), _reenterPasscode.height()); - _recoverEmail.setGeometry(st::addContactPadding.left(), _passwordHint.y() + _passwordHint.height() + st::addContactSkip + _aboutHeight + st::addContactSkip, _passwordHint.width(), _passwordHint.height()); + _recoverEmail.setGeometry(st::boxPadding.left(), _passwordHint.y() + _passwordHint.height() + st::contactSkip + _aboutHeight + st::contactSkip, _passwordHint.width(), _passwordHint.height()); if (!_recover.isHidden()) { if (_turningOff) { _recover.move((width() - _recover.width()) / 2, _oldPasscode.y() + _oldPasscode.height() + st::usernameSkip + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); } else { - _recover.move((width() - _recover.width()) / 2, _passwordHint.y() + _passwordHint.height() + st::addContactSkip + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); + _recover.move((width() - _recover.width()) / 2, _passwordHint.y() + _passwordHint.height() + st::contactSkip + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); } } @@ -274,7 +268,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) { } } else if (err == "NEW_PASSWORD_BAD") { _newPasscode.setFocus(); - _newPasscode.notaBene(); + _newPasscode.showError(); _newError = lang(lng_cloud_password_bad); update(); } else if (err == "NEW_SALT_INVALID") { @@ -283,7 +277,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) { } else if (err == "EMAIL_INVALID") { _emailError = lang(lng_cloud_password_bad_email); _recoverEmail.setFocus(); - _recoverEmail.notaBene(); + _recoverEmail.showError(); update(); } else if (err == "EMAIL_UNCONFIRMED") { App::wnd()->showLayer(new InformBox(lang(lng_cloud_password_almost))); @@ -293,7 +287,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) { _oldPasscode.selectAll(); _oldPasscode.setFocus(); - _oldPasscode.notaBene(); + _oldPasscode.showError(); _oldError = lang(lng_flood_error); } return true; @@ -308,7 +302,7 @@ void PasscodeBox::onSave(bool force) { if (!passcodeCanTry()) { _oldError = lang(lng_flood_error); _oldPasscode.setFocus(); - _oldPasscode.notaBene(); + _oldPasscode.showError(); update(); return; } @@ -325,13 +319,13 @@ void PasscodeBox::onSave(bool force) { } if (!_turningOff && pwd.isEmpty()) { _newPasscode.setFocus(); - _newPasscode.notaBene(); + _newPasscode.showError(); if (isHidden() && _replacedBy && !_replacedBy->isHidden()) _replacedBy->onClose(); return; } if (pwd != conf) { _reenterPasscode.setFocus(); - _reenterPasscode.notaBene(); + _reenterPasscode.showError(); if (!conf.isEmpty()) { _newError = lang(_cloudPwd ? lng_cloud_password_differ : lng_passcode_differ); update(); @@ -339,15 +333,15 @@ void PasscodeBox::onSave(bool force) { if (isHidden() && _replacedBy && !_replacedBy->isHidden()) _replacedBy->onClose(); } else if (!_turningOff && has && old == pwd) { _newPasscode.setFocus(); - _newPasscode.notaBene(); + _newPasscode.showError(); _newError = lang(_cloudPwd ? lng_cloud_password_is_same : lng_passcode_is_same); update(); if (isHidden() && _replacedBy && !_replacedBy->isHidden()) _replacedBy->onClose(); } else if (_cloudPwd) { - QString hint = _passwordHint.text(), email = _recoverEmail.text().trimmed(); + QString hint = _passwordHint.getLastText(), email = _recoverEmail.getLastText().trimmed(); if (_cloudPwd && pwd == hint && !_passwordHint.isHidden() && !_newPasscode.isHidden()) { _newPasscode.setFocus(); - _newPasscode.notaBene(); + _newPasscode.showError(); _newError = lang(lng_cloud_password_bad); update(); if (isHidden() && _replacedBy && !_replacedBy->isHidden()) _replacedBy->onClose(); @@ -392,7 +386,7 @@ void PasscodeBox::onSave(bool force) { void PasscodeBox::onBadOldPasscode() { _oldPasscode.selectAll(); _oldPasscode.setFocus(); - _oldPasscode.notaBene(); + _oldPasscode.showError(); _oldError = lang(_cloudPwd ? lng_cloud_password_wrong : lng_passcode_wrong); update(); } @@ -465,11 +459,11 @@ bool PasscodeBox::recoverStartFail(const RPCError &error) { } RecoverBox::RecoverBox(const QString &pattern) : -_submitRequest(0), _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right())), -_saveButton(this, lang(lng_passcode_submit), st::btnSelectDone), -_cancelButton(this, lang(lng_cancel), st::btnSelectCancel), -_recoverCode(this, st::inpAddContact, lang(lng_signin_code)) { - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + st::usernameSkip + _recoverCode.height() + st::usernameSkip + st::addContactPadding.bottom() + _saveButton.height()); +_submitRequest(0), _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right())), +_saveButton(this, lang(lng_passcode_submit), st::defaultBoxButton), +_cancelButton(this, lang(lng_cancel), st::cancelBoxButton), +_recoverCode(this, st::defaultInputField, lang(lng_signin_code)) { + setMaxHeight(st::boxTitleHeight + st::contactPadding.top() + st::usernameSkip + _recoverCode.height() + st::usernameSkip + st::contactPadding.bottom() + _saveButton.height()); connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSubmit())); connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); @@ -493,9 +487,9 @@ void RecoverBox::showAll() { void RecoverBox::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - if (_recoverCode.text().isEmpty()) { + if (_recoverCode.getLastText().isEmpty()) { _recoverCode.setFocus(); - _recoverCode.notaBene(); + _recoverCode.showError(); } else { onSubmit(); } @@ -508,26 +502,20 @@ void RecoverBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintOldTitle(p, lang(lng_signin_recover), true); - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + paintTitle(p, lang(lng_signin_recover)); p.setFont(st::normalFont->f); - int32 w = width() - st::addContactPadding.left() - st::addContactPadding.right(); - p.drawText(QRect(st::addContactPadding.left(), _recoverCode.y() - st::usernameSkip - st::addContactPadding.top(), w, st::addContactPadding.top() + st::usernameSkip), _pattern, style::al_center); + int32 w = width() - st::boxPadding.left() - st::boxPadding.right(); + p.drawText(QRect(st::boxPadding.left(), _recoverCode.y() - st::usernameSkip - st::contactPadding.top(), w, st::contactPadding.top() + st::usernameSkip), _pattern, style::al_center); if (!_error.isEmpty()) { p.setPen(st::setErrColor->p); p.drawText(QRect(0, _recoverCode.y() + _recoverCode.height(), width(), st::usernameSkip), _error, style::al_center); } - - // paint button sep - p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void RecoverBox::resizeEvent(QResizeEvent *e) { - _recoverCode.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top() + st::usernameSkip, width() - st::addContactPadding.left() - st::addContactPadding.right(), _recoverCode.height()); + _recoverCode.setGeometry(st::boxPadding.left(), st::boxTitleHeight + st::contactPadding.top() + st::usernameSkip, width() - st::boxPadding.left() - st::boxPadding.right(), _recoverCode.height()); int32 buttonTop = height() - _cancelButton.height(); _cancelButton.move(0, buttonTop); @@ -541,9 +529,9 @@ void RecoverBox::showDone() { void RecoverBox::onSubmit() { if (_submitRequest) return; - QString code = _recoverCode.text().trimmed(); + QString code = _recoverCode.getLastText().trimmed(); if (code.isEmpty()) { - _recoverCode.notaBene(); + _recoverCode.showError(); return; } @@ -580,12 +568,12 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) { } else if (err == "CODE_INVALID") { _error = lang(lng_signin_wrong_code); update(); - _recoverCode.notaBene(); + _recoverCode.showError(); return true; } else if (mtpIsFlood(error)) { _error = lang(lng_flood_error); update(); - _recoverCode.notaBene(); + _recoverCode.showError(); return true; } if (cDebug()) { // internal server error diff --git a/Telegram/SourceFiles/boxes/passcodebox.h b/Telegram/SourceFiles/boxes/passcodebox.h index 246d99c9a..2ac2c74bf 100644 --- a/Telegram/SourceFiles/boxes/passcodebox.h +++ b/Telegram/SourceFiles/boxes/passcodebox.h @@ -80,8 +80,9 @@ private: QString _boxTitle; Text _about, _hintText; - FlatButton _saveButton, _cancelButton; - FlatInput _oldPasscode, _newPasscode, _reenterPasscode, _passwordHint, _recoverEmail; + BoxButton _saveButton, _cancelButton; + PasswordField _oldPasscode, _newPasscode, _reenterPasscode; + InputField _passwordHint, _recoverEmail; LinkButton _recover; QString _oldError, _newError, _emailError; @@ -122,8 +123,8 @@ private: QString _pattern; - FlatButton _saveButton, _cancelButton; - FlatInput _recoverCode; + BoxButton _saveButton, _cancelButton; + InputField _recoverCode; QString _error; }; diff --git a/Telegram/SourceFiles/boxes/photocropbox.cpp b/Telegram/SourceFiles/boxes/photocropbox.cpp index c47da34c7..9153ed9fd 100644 --- a/Telegram/SourceFiles/boxes/photocropbox.cpp +++ b/Telegram/SourceFiles/boxes/photocropbox.cpp @@ -27,11 +27,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "photocropbox.h" #include "fileuploader.h" -PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer, bool upload) : _downState(0), - _sendButton(this, lang(lng_settings_save), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), - _img(img), _peerId(peer) { - +PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer, bool upload) : AbstractBox() +, _downState(0) +, _done(this, lang(lng_settings_save), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _img(img) +, _peerId(peer) { if (peerIsChannel(_peerId)) { _title = lang(lng_create_channel_crop); } else if (peerIsChat(_peerId)) { @@ -40,13 +41,13 @@ PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer, bool upload) : _title = lang(lng_settings_crop_profile); } - connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_done, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); if (_peerId && upload) { - connect(this, SIGNAL(ready(const QImage &)), this, SLOT(onReady(const QImage &))); + connect(this, SIGNAL(ready(const QImage&)), this, SLOT(onReady(const QImage&))); } - int32 s = st::boxWideWidth - st::boxPadding.left() - st::boxPadding.right(); + int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); _thumb = QPixmap::fromImage(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); _thumbw = _thumb.width(); _thumbh = _thumb.height(); @@ -59,10 +60,10 @@ PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer, bool upload) : _cropy = (_thumbh - _cropw) / 2; _thumbx = (st::boxWideWidth - _thumbw) / 2; - _thumby = st::boxPadding.top() * 2 + st::boxFont->height; + _thumby = st::boxPhotoPadding.top(); setMouseTracking(true); - resizeMaxHeight(st::boxWideWidth, _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.top() + st::boxPadding.bottom() + _sendButton.height()); + resizeMaxHeight(st::boxWideWidth, st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxTextFont->height + st::cropSkip + st::boxButtonPadding.top() + _done.height() + st::boxButtonPadding.bottom()); } void PhotoCropBox::mousePressEvent(QMouseEvent *e) { @@ -211,16 +212,12 @@ void PhotoCropBox::keyPressEvent(QKeyEvent *e) { } void PhotoCropBox::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); if (paint(p)) return; - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); - - paintGrayTitle(p, _title); + p.setFont(st::boxTextFont); + p.setPen(st::boxPhotoTextFg); + p.drawText(QRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom(), width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), st::boxTextFont->height), _title, style::al_top); p.translate(_thumbx, _thumby); p.drawPixmap(0, 0, _thumb); @@ -246,8 +243,8 @@ void PhotoCropBox::paintEvent(QPaintEvent *e) { } void PhotoCropBox::resizeEvent(QResizeEvent *e) { - _sendButton.move(width() - _sendButton.width(), height() - _sendButton.height()); - _cancelButton.move(0, height() - _cancelButton.height()); + _done.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _done.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _done.width() + st::boxButtonPadding.left(), _done.y()); } void PhotoCropBox::onSend() { @@ -288,11 +285,11 @@ void PhotoCropBox::onReady(const QImage &tosend) { } void PhotoCropBox::hideAll() { - _sendButton.hide(); - _cancelButton.hide(); + _done.hide(); + _cancel.hide(); } void PhotoCropBox::showAll() { - _sendButton.show(); - _cancelButton.show(); + _done.show(); + _cancel.show(); } diff --git a/Telegram/SourceFiles/boxes/photocropbox.h b/Telegram/SourceFiles/boxes/photocropbox.h index 7fdb74fbf..c9262a284 100644 --- a/Telegram/SourceFiles/boxes/photocropbox.h +++ b/Telegram/SourceFiles/boxes/photocropbox.h @@ -58,7 +58,7 @@ private: int32 _thumbx, _thumby, _thumbw, _thumbh; int32 _cropx, _cropy, _cropw; int32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw; - FlatButton _sendButton, _cancelButton; + BoxButton _done, _cancel; QImage _img; QPixmap _thumb; PeerId _peerId; diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp index e7e5af9be..6b0b713bb 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.cpp +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -27,14 +27,21 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "photosendbox.h" -PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(new ReadyLocalMedia(img)), - _thumbx(0), _thumby(0), _thumbw(0), _thumbh(0), _namew(0), _textw(0), - _compressed(this, lang(lng_send_image_compressed), cCompressPastedImage()), - _sendButton(this, lang(lng_send_button), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), - _replyTo(img.replyTo) { - connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); +PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : AbstractBox(st::boxWideWidth) +, _img(new ReadyLocalMedia(img)) +, _thumbx(0) +, _thumby(0) +, _thumbw(0) +, _thumbh(0) +, _namew(0) +, _textw(0) +, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption)) +, _compressed(this, lang(lng_send_image_compressed), cCompressPastedImage()) +, _send(this, lang(lng_send_button), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _replyTo(img.replyTo) { + connect(&_send, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); if (_img->type == ToPreparePhoto) { int32 maxW = 0, maxH = 0; @@ -49,7 +56,7 @@ PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(new ReadyLocalMedi if (!tw || !th) { tw = th = 1; } - _thumbw = width() - st::boxPadding.left() - st::boxPadding.right(); + _thumbw = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); if (_thumb.width() < _thumbw) { _thumbw = (_thumb.width() > 20) ? _thumb.width() : 20; } @@ -62,7 +69,7 @@ PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(new ReadyLocalMedi _thumbw = 10; } } - resizeMaxHeight(st::boxWideWidth, _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.bottom() + st::boxPadding.bottom() + _compressed.height() + _sendButton.height()); + _thumbx = (width() - _thumbw) / 2; _thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); _thumb.setDevicePixelRatio(cRetinaFactor()); @@ -87,24 +94,37 @@ PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(new ReadyLocalMedi _thumb = QPixmap::fromImage(_thumb.toImage().scaledToWidth(_thumbw * cIntRetinaFactor(), Qt::SmoothTransformation), Qt::ColorOnly); _thumb.setDevicePixelRatio(cRetinaFactor()); } - resizeMaxHeight(st::boxWideWidth, st::boxPadding.top() + st::boxFont->height + st::boxPadding.bottom() + st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom() + st::boxPadding.bottom() + _sendButton.height()); _name = _img->filename; _namew = st::mediaFont->width(_name); _size = formatSizeText(_img->filesize); _textw = qMax(_namew, st::mediaFont->width(_size)); } + updateBoxSize(); + _caption.setMaxLength(MaxPhotoCaption); + _caption.setCtrlEnterSubmit(false); + connect(&_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange())); + connect(&_caption, SIGNAL(resized()), this, SLOT(onCaptionResized())); + connect(&_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool))); + connect(&_caption, SIGNAL(cancelled()), this, SLOT(onClose())); prepare(); } -PhotoSendBox::PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo) : _img(0), -_thumbx(0), _thumby(0), _thumbw(0), _thumbh(0), _namew(0), _textw(0), -_compressed(this, lang(lng_send_image_compressed), true), -_sendButton(this, lang(lng_send_button), st::btnSelectDone), -_cancelButton(this, lang(lng_cancel), st::btnSelectCancel), -_phone(phone), _fname(fname), _lname(lname), _replyTo(replyTo) { - connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); +PhotoSendBox::PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo) : AbstractBox(st::boxWideWidth) +, _img(0) +, _thumbx(0) +, _thumby(0) +, _thumbw(0) +, _thumbh(0) +, _namew(0) +, _textw(0) +, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption)) +, _compressed(this, lang(lng_send_image_compressed), true) +, _send(this, lang(lng_send_button), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) +, _phone(phone), _fname(fname), _lname(lname), _replyTo(replyTo) { + connect(&_send, SIGNAL(clicked()), this, SLOT(onSend())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); _compressed.hide(); @@ -113,10 +133,35 @@ _phone(phone), _fname(fname), _lname(lname), _replyTo(replyTo) { _size = _phone; _textw = qMax(_namew, st::mediaFont->width(_size)); - resizeMaxHeight(st::boxWideWidth, st::boxPadding.top() + st::boxFont->height + st::boxPadding.bottom() + st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom() + st::boxPadding.bottom() + _sendButton.height()); + updateBoxSize(); prepare(); } +void PhotoSendBox::onCompressedChange() { + showAll(); + if (_caption.isHidden()) { + setFocus(); + } else { + _caption.setFocus(); + } + updateBoxSize(); + resizeEvent(0); + update(); +} + +void PhotoSendBox::onCaptionResized() { + updateBoxSize(); + resizeEvent(0); + update(); +} + +void PhotoSendBox::updateBoxSize() { + if (_img && _img->type == ToPreparePhoto) { + setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.top() + _compressed.height() + (_compressed.checked() ? (st::boxPhotoCompressedPadding.bottom() + _caption.height()) : 0) + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom()); + } else { + setMaxHeight(st::boxPhotoPadding.top() + st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom() + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom()); + } +} void PhotoSendBox::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { @@ -130,26 +175,23 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); - if (_img && _img->type == ToPreparePhoto) { - paintGrayTitle(p, lang(lng_really_send_image)); - p.drawPixmap((width() - _thumbw) / 2, st::boxPadding.top() * 2 + st::boxFont->height, _thumb); + if (_thumbx > st::boxPhotoPadding.left()) { + p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg->b); + } + if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) { + p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg->b); + } + p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb); } else { - paintGrayTitle(p, lang(_img ? lng_really_send_file : lng_really_share_contact)); - - int32 w = width() - st::boxPadding.left() - st::boxPadding.right(), h = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); + int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), h = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom(); int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right(); int32 twidth = w - tleft - st::mediaPadding.right(); if (twidth > _textw) { w -= (twidth - _textw); twidth = _textw; } - int32 x = (width() - w) / 2, y = st::boxPadding.top() * 2 + st::boxFont->height; + int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top(); App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow); if (_thumbw) { @@ -175,9 +217,11 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) { } void PhotoSendBox::resizeEvent(QResizeEvent *e) { - _sendButton.move(width() - _sendButton.width(), height() - _sendButton.height()); - _cancelButton.move(0, height() - _cancelButton.height()); - _compressed.move((width() - _compressed.width()) / 2, height() - _cancelButton.height() - _compressed.height() - st::confirmCompressedSkip); + _send.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _send.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y()); + _caption.resize(st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), _caption.height()); + _caption.moveToLeft(st::boxPhotoPadding.left(), _send.y() - st::boxButtonPadding.top() - _caption.height()); + _compressed.moveToLeft(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.top()); } void PhotoSendBox::closePressed() { @@ -185,21 +229,32 @@ void PhotoSendBox::closePressed() { } void PhotoSendBox::hideAll() { - _sendButton.hide(); - _cancelButton.hide(); + _send.hide(); + _cancel.hide(); + _caption.hide(); _compressed.hide(); } void PhotoSendBox::showAll() { - _sendButton.show(); - _cancelButton.show(); + _send.show(); + _cancel.show(); if (_img && _img->type == ToPreparePhoto) { _compressed.show(); + if (_compressed.checked()) { + _caption.show(); + } else { + _caption.hide(); + } } else { + _caption.hide(); _compressed.hide(); } } +void PhotoSendBox::showDone() { + setInnerFocus(); +} + void PhotoSendBox::onSend(bool ctrlShiftEnter) { if (!_img) { if (App::main()) App::main()->confirmShareContact(ctrlShiftEnter, _phone, _fname, _lname, _replyTo); @@ -212,6 +267,7 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) { } if (_compressed.isHidden() || _compressed.checked()) { _img->ctrlShiftEnter = ctrlShiftEnter; + _img->caption = _caption.isHidden() ? QString() : _caption.getLastText(); if (App::main()) App::main()->confirmSendImage(*_img); } else { if (App::main()) App::main()->confirmSendImageUncompressed(ctrlShiftEnter, _replyTo); diff --git a/Telegram/SourceFiles/boxes/photosendbox.h b/Telegram/SourceFiles/boxes/photosendbox.h index 935faefe9..4d2964eb3 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.h +++ b/Telegram/SourceFiles/boxes/photosendbox.h @@ -33,6 +33,15 @@ public: void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); + + void setInnerFocus() { + if (_caption.isHidden()) { + setFocus(); + } else { + _caption.setFocus(); + } + } + ~PhotoSendBox(); signals: @@ -41,6 +50,8 @@ signals: public slots: + void onCompressedChange(); + void onCaptionResized(); void onSend(bool ctrlShiftEnter = false); protected: @@ -48,15 +59,19 @@ protected: void closePressed(); void hideAll(); void showAll(); + void showDone(); private: + void updateBoxSize(); + ReadyLocalMedia *_img; int32 _thumbx, _thumby, _thumbw, _thumbh; QString _name, _size; int32 _namew, _textw; - FlatCheckbox _compressed; - FlatButton _sendButton, _cancelButton; + InputArea _caption; + Checkbox _compressed; + BoxButton _send, _cancel; QPixmap _thumb; QString _phone, _fname, _lname; diff --git a/Telegram/SourceFiles/boxes/sessionsbox.cpp b/Telegram/SourceFiles/boxes/sessionsbox.cpp index ed7a9c3c8..a76d13b3f 100644 --- a/Telegram/SourceFiles/boxes/sessionsbox.cpp +++ b/Telegram/SourceFiles/boxes/sessionsbox.cpp @@ -164,7 +164,7 @@ _terminateAll(this, lang(lng_sessions_terminate_all)), _terminateBox(0), _shortP connect(App::wnd(), SIGNAL(newAuthorization()), this, SLOT(onNewAuthorization())); connect(&_shortPollTimer, SIGNAL(timeout()), this, SLOT(onShortPollAuthorizations())); - init(&_inner, _done.height(), st::old_boxTitleHeight + st::sessionHeight + st::old_boxTitleHeight); + init(&_inner, _done.height(), st::boxTitleHeight + st::sessionHeight + st::boxTitleHeight); _inner.resize(width(), st::noContactsHeight); prepare(); @@ -176,7 +176,7 @@ _terminateAll(this, lang(lng_sessions_terminate_all)), _terminateBox(0), _shortP void SessionsBox::resizeEvent(QResizeEvent *e) { ScrollableBox::resizeEvent(e); _done.move(0, height() - _done.height()); - _terminateAll.moveToRight(st::sessionPadding.left(), st::old_boxTitleHeight + st::sessionHeight + st::old_boxTitlePos.y() + st::old_boxTitleFont->ascent - st::linkFont->ascent); + _terminateAll.moveToRight(st::sessionPadding.left(), st::boxTitleHeight + st::sessionHeight + st::boxTitlePosition.y() + st::boxTitleFont->ascent - st::linkFont->ascent); } void SessionsBox::hideAll() { @@ -204,8 +204,8 @@ void SessionsBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintOldTitle(p, lang(lng_sessions_header), true); - p.translate(0, st::old_boxTitleHeight); + paintTitle(p, lang(lng_sessions_header)); + p.translate(0, st::boxTitleHeight); if (_loading) { p.setFont(st::noContactsFont->f); @@ -230,16 +230,16 @@ void SessionsBox::paintEvent(QPaintEvent *e) { p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, _current.ip, _current.ipWidth); p.translate(0, st::sessionHeight); if (_list.isEmpty()) { - paintOldTitle(p, lang(lng_sessions_no_other), true); + paintTitle(p, lang(lng_sessions_no_other)); p.setFont(st::sessionInfoFont->f); p.setPen(st::sessionInfoColor->p); - p.drawText(QRect(st::sessionPadding.left(), st::old_boxTitleHeight + st::old_boxTitlePos.y(), width() - st::sessionPadding.left() - st::sessionPadding.right(), _scroll.height()), lang(lng_sessions_other_desc), style::al_topleft); + p.drawText(QRect(st::sessionPadding.left(), st::boxTitleHeight + st::boxTitlePosition.y(), width() - st::sessionPadding.left() - st::sessionPadding.right(), _scroll.height()), lang(lng_sessions_other_desc), style::al_topleft); // paint shadow - p.fillRect(0, height() - st::sessionsCloseButton.height - st::scrollDef.bottomsh - st::sessionHeight - st::old_boxTitleHeight, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + p.fillRect(0, height() - st::sessionsCloseButton.height - st::scrollDef.bottomsh - st::sessionHeight - st::boxTitleHeight, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); } else { - paintOldTitle(p, lang(lng_sessions_other_header), false); + paintTitle(p, lang(lng_sessions_other_header)); } } } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 4fecc0143..8a0119691 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -29,14 +29,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "localstorage.h" -void StickerSetPanel::paintEvent(QPaintEvent *e) { - Painter p(this); - p.fillRect(e->rect(), st::emojiPanHeaderBg->b); -} - StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : _loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0), -_input(set), _installRequest(0), _panel(0) { +_input(set), _installRequest(0) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); switch (set.type()) { case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break; @@ -61,7 +57,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { if (d.vset.type() == mtpc_stickerSet) { const MTPDstickerSet &s(d.vset.c_stickerSet()); _setTitle = qs(s.vtitle); - _title = st::old_boxTitleFont->elided(_setTitle, width() - st::btnStickersClose.width - st::old_boxTitlePos.x()); + _title = st::boxTitleFont->elided(_setTitle, width() - st::boxTitlePosition.x() - st::boxTitleHeight); _setShortName = qs(s.vshort_name); _setId = s.vid.v; _setAccess = s.vaccess_hash.v; @@ -75,10 +71,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { App::wnd()->showLayer(new InformBox(lang(lng_stickers_not_found))); } else { int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0); - resize(st::stickersPadding + StickerPanPerRow * st::stickersSize.width(), rows * st::stickersSize.height() + st::stickersAddOrShare); - _panel = new StickerSetPanel(parentWidget()); - _panel->setGeometry(0, parentWidget()->height() - st::stickersAddOrShare, width(), st::stickersAddOrShare); - _panel->show(); + resize(st::stickersPadding.left() + StickerPanPerRow * st::stickersSize.width(), st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom()); } _loaded = true; @@ -157,7 +150,7 @@ void StickerSetInner::paintEvent(QPaintEvent *e) { if (index >= _pack.size()) break; DocumentData *doc = _pack.at(index); - QPoint pos(st::stickerPanPadding + j * st::stickersSize.width(), i * st::stickersSize.height()); + QPoint pos(st::stickersPadding.left() + j * st::stickersSize.width(), st::stickersPadding.top() + i * st::stickersSize.height()); bool goodThumb = !doc->thumb->isNull() && ((doc->thumb->width() >= 128) || (doc->thumb->height() >= 128)); if (goodThumb) { @@ -225,21 +218,20 @@ void StickerSetInner::install() { StickerSetInner::~StickerSetInner() { } -StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::stickersScroll), _inner(set), -_close(this, st::btnStickersClose), -_addStickers(this, lng_stickers_add_pack(lt_count, 0), st::btnStickersAdd), -_shareStickers(this, lang(lng_stickers_share_pack), st::btnStickersAdd), -_closeStickers(this, lang(lng_close), st::btnStickersAdd) { - resize(st::stickersWidth, height()); +StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::stickersScroll) +, _inner(set) +, _shadow(this) +, _add(this, lang(lng_stickers_add_pack), st::defaultBoxButton) +, _share(this, lang(lng_stickers_share_pack), st::defaultBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) { setMaxHeight(st::stickersMaxHeight); connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated())); - init(&_inner, 0, st::boxFont->height + st::old_newGroupNamePadding.top() + st::old_newGroupNamePadding.bottom()); + init(&_inner, st::boxButtonPadding.bottom() + _cancel.height() + st::boxButtonPadding.top()); - connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); - connect(&_addStickers, SIGNAL(clicked()), this, SLOT(onAddStickers())); - connect(&_shareStickers, SIGNAL(clicked()), this, SLOT(onShareStickers())); - connect(&_closeStickers, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_add, SIGNAL(clicked()), this, SLOT(onAddStickers())); + connect(&_share, SIGNAL(clicked()), this, SLOT(onShareStickers())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); @@ -268,7 +260,9 @@ void StickerSetBox::onShareStickers() { } void StickerSetBox::onUpdateButtons() { - if (!_close.isHidden()) showAll(); + if (!_cancel.isHidden()) { + showAll(); + } } void StickerSetBox::onScroll() { @@ -277,37 +271,35 @@ void StickerSetBox::onScroll() { void StickerSetBox::hideAll() { ScrollableBox::hideAll(); - _close.hide(); - _addStickers.hide(); - _shareStickers.hide(); + _shadow.hide(); + _cancel.hide(); + _add.hide(); + _share.hide(); } void StickerSetBox::showAll() { ScrollableBox::showAll(); - _close.show(); + _shadow.show(); + _cancel.show(); int32 cnt = _inner.notInstalled(); if (_inner.loaded()) { if (_inner.official()) { - _addStickers.hide(); - _shareStickers.hide(); - _closeStickers.show(); + _add.hide(); + _share.hide(); } else if (_inner.notInstalled()) { - _addStickers.setText(lng_stickers_add_pack(lt_count, cnt)); - _addStickers.show(); - _addStickers.raise(); - _shareStickers.hide(); - _closeStickers.hide(); + _add.show(); + _add.raise(); + _share.hide(); } else { - _shareStickers.show(); - _shareStickers.raise(); - _addStickers.hide(); - _closeStickers.hide(); + _share.show(); + _share.raise(); + _add.hide(); } } else { - _addStickers.hide(); - _shareStickers.hide(); - _closeStickers.hide(); + _add.hide(); + _share.hide(); } + resizeEvent(0); update(); } @@ -315,14 +307,20 @@ void StickerSetBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintOldTitle(p, _inner.title(), false); + paintTitle(p, _inner.title()); } void StickerSetBox::resizeEvent(QResizeEvent *e) { ScrollableBox::resizeEvent(e); _inner.resize(width(), _inner.height()); - _close.moveToRight(0, 0); - _addStickers.move((width() - _addStickers.width()) / 2, height() - (st::stickersAddOrShare + _addStickers.height()) / 2); - _shareStickers.move((width() - _shareStickers.width()) / 2, height() - (st::stickersAddOrShare + _shareStickers.height()) / 2); - _closeStickers.move((width() - _closeStickers.width()) / 2, height() - (st::stickersAddOrShare + _closeStickers.height()) / 2); + _shadow.setGeometry(0, height() - st::boxButtonPadding.bottom() - _cancel.height() - st::boxButtonPadding.top() - st::lineWidth, width(), st::lineWidth); + _add.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _add.height()); + _share.moveToRight(st::boxButtonPadding.right(), _add.y()); + if (_add.isHidden() && _share.isHidden()) { + _cancel.moveToRight(st::boxButtonPadding.right(), _add.y()); + } else if (_add.isHidden()) { + _cancel.moveToRight(st::boxButtonPadding.right() + _share.width() + st::boxButtonPadding.left(), _add.y()); + } else { + _cancel.moveToRight(st::boxButtonPadding.right() + _add.width() + st::boxButtonPadding.left(), _add.y()); + } } diff --git a/Telegram/SourceFiles/boxes/stickersetbox.h b/Telegram/SourceFiles/boxes/stickersetbox.h index 65171e09d..7789e6d33 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.h +++ b/Telegram/SourceFiles/boxes/stickersetbox.h @@ -22,15 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "abstractbox.h" -class StickerSetPanel : public TWidget { -public: - - StickerSetPanel(QWidget *parent) : TWidget(parent) { - } - void paintEvent(QPaintEvent *e); - -}; - class StickerSetInner : public TWidget, public RPCSender { Q_OBJECT @@ -51,6 +42,8 @@ public: void setScrollBottom(int32 bottom); void install(); + QString getTitle() const; + ~StickerSetInner(); signals: @@ -76,8 +69,6 @@ private: MTPInputStickerSet _input; mtpRequestId _installRequest; - - StickerSetPanel *_panel; }; class StickerSetBox : public ScrollableBox, public RPCSender { @@ -111,6 +102,7 @@ protected: private: StickerSetInner _inner; - IconedButton _close; - FlatButton _addStickers, _shareStickers, _closeStickers; + ScrollableBoxShadow _shadow; + BoxButton _add, _share, _cancel; + QString _title; }; diff --git a/Telegram/SourceFiles/boxes/usernamebox.cpp b/Telegram/SourceFiles/boxes/usernamebox.cpp index cc9eb064f..635ff21b7 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.cpp +++ b/Telegram/SourceFiles/boxes/usernamebox.cpp @@ -28,16 +28,18 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org UsernameBox::UsernameBox() : AbstractBox(st::boxWidth), _save(this, lang(lng_settings_save), st::defaultBoxButton), -_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_cancel(this, lang(lng_cancel), st::cancelBoxButton), _username(this, st::usernameField, qsl("@username"), App::self()->username, false), _link(this, QString(), st::defaultBoxLinkButton), _saveRequestId(0), _checkRequestId(0), _about(st::boxWidth - st::usernamePadding.left()) { + setBlueTitle(true); + _goodText = App::self()->username.isEmpty() ? QString() : lang(lng_username_available); textstyleSet(&st::usernameTextStyle); _about.setRichText(st::boxTextFont, lang(lng_username_about)); - resizeMaxHeight(st::boxWidth, st::boxBlueTitleHeight + st::usernamePadding.top() + _username.height() + st::usernameSkip + _about.countHeight(st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right()) + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + resizeMaxHeight(st::boxWidth, st::boxTitleHeight + st::usernamePadding.top() + _username.height() + st::usernameSkip + _about.countHeight(st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right()) + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); textstyleRestore(); connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); @@ -58,6 +60,8 @@ void UsernameBox::hideAll() { _save.hide(); _cancel.hide(); _link.hide(); + + AbstractBox::hideAll(); } void UsernameBox::showAll() { @@ -65,6 +69,8 @@ void UsernameBox::showAll() { _save.show(); _cancel.show(); updateLinkText(); + + AbstractBox::showAll(); } void UsernameBox::showDone() { @@ -75,7 +81,7 @@ void UsernameBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintBlueTitle(p, lang(lng_username_title)); + paintTitle(p, lang(lng_username_title)); if (!_copiedTextLink.isEmpty()) { p.setPen(st::usernameDefaultFg); @@ -112,7 +118,7 @@ void UsernameBox::paintEvent(QPaintEvent *e) { void UsernameBox::resizeEvent(QResizeEvent *e) { _username.resize(width() - st::usernamePadding.left() - st::usernamePadding.right(), _username.height()); - _username.moveToLeft(st::usernamePadding.left(), st::boxBlueTitleHeight + st::usernamePadding.top()); + _username.moveToLeft(st::usernamePadding.left(), st::boxTitleHeight + st::usernamePadding.top()); textstyleSet(&st::usernameTextStyle); int32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); @@ -122,6 +128,8 @@ void UsernameBox::resizeEvent(QResizeEvent *e) { _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); + + AbstractBox::resizeEvent(e); } void UsernameBox::onSave() { diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 894e4ec7e..b9953da4b 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -66,6 +66,7 @@ enum { MaxSelectedItems = 100, + MaxPhoneCodeLength = 4, // max length of country phone code MaxPhoneTailLength = 18, // rest of the phone number, without country code (seen 12 at least) MaxScrollSpeed = 37, // 37px per 15ms while select-by-drag @@ -127,6 +128,8 @@ enum { UsernameCheckTimeout = 200, MaxChannelDescription = 120, + MaxGroupChannelTitle = 255, + MaxPhotoCaption = 140, MaxMessageSize = 4096, MaxHttpRedirects = 5, // when getting external data/images diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 2903caa0b..1d736b6bc 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -48,7 +48,8 @@ _addContactLnk(this, lang(lng_add_contact_button)), _cancelSearchInPeer(this, st::btnCancelSearch), _overDelete(false), _searchInPeer(0) { - connect(main, SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&))); + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + connect(main, SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&))); connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*))); connect(main, SIGNAL(dialogRowReplaced(DialogRow*,DialogRow*)), this, SLOT(onDialogRowReplaced(DialogRow*,DialogRow*))); connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); @@ -1525,7 +1526,6 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent) connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); connect(&_newGroup, SIGNAL(clicked()), this, SLOT(onNewGroup())); connect(&_cancelSearch, SIGNAL(clicked()), this, SLOT(onCancelSearch())); - connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); _chooseByDragTimer.setSingleShot(true); connect(&_chooseByDragTimer, SIGNAL(timeout()), this, SLOT(onChooseByDrag())); diff --git a/Telegram/SourceFiles/gui/countryinput.cpp b/Telegram/SourceFiles/gui/countryinput.cpp index d3ea80ee0..53719fa5c 100644 --- a/Telegram/SourceFiles/gui/countryinput.cpp +++ b/Telegram/SourceFiles/gui/countryinput.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "application.h" #include "gui/countryinput.h" #include "gui/scrollarea.h" +#include "boxes/contactsbox.h" #include "countries.h" @@ -42,7 +43,7 @@ namespace { CountriesByLetter countriesByLetter; CountriesNames countriesNames; - QString lastFilter, lastValidISO; + QString lastValidISO; int countriesCount = sizeof(countries) / sizeof(countries[0]); void initCountries() { @@ -87,7 +88,7 @@ QString findValidCode(QString fullCode) { return ""; } -CountryInput::CountryInput(QWidget *parent, const style::countryInput &st) : QWidget(parent), _st(st), _active(false), _text(lang(lng_country_code)), _select(0) { +CountryInput::CountryInput(QWidget *parent, const style::countryInput &st) : QWidget(parent), _st(st), _active(false), _text(lang(lng_country_code)) { initCountries(); resize(_st.width, _st.height + _st.ptrSize.height()); @@ -134,15 +135,9 @@ void CountryInput::mouseMoveEvent(QMouseEvent *e) { void CountryInput::mousePressEvent(QMouseEvent *e) { mouseMoveEvent(e); if (_active) { - Window *w = App::wnd(); - if (w->focusWidget()) w->focusWidget()->clearFocus(); - if (_select) { - _select->hide(); - _select->deleteLater(); - } - _select = new CountrySelect(); - connect(_select, SIGNAL(countryChosen(const QString &)), this, SLOT(onChooseCountry(const QString &))); - connect(_select, SIGNAL(countryFinished()), this, SLOT(onFinishCountry())); + CountrySelectBox *box = new CountrySelectBox(); + connect(box, SIGNAL(countryChosen(const QString&)), this, SLOT(onChooseCountry(const QString&))); + App::wnd()->showLayer(box); } } @@ -157,12 +152,7 @@ void CountryInput::leaveEvent(QEvent *e) { } void CountryInput::onChooseCode(const QString &code) { - if (_select) { - _select->hide(); - _select->deleteLater(); - _select = 0; - emit selectClosed(); - } + App::wnd()->hideLayer(); if (code.length()) { CountriesByCode::const_iterator i = _countriesByCode.constFind(code); if (i != _countriesByCode.cend()) { @@ -179,6 +169,8 @@ void CountryInput::onChooseCode(const QString &code) { } bool CountryInput::onChooseCountry(const QString &iso) { + App::wnd()->hideLayer(); + CountriesByISO2::const_iterator i = _countriesByISO2.constFind(iso); const CountryInfo *info = (i == _countriesByISO2.cend()) ? 0 : (*i); @@ -192,25 +184,19 @@ bool CountryInput::onChooseCountry(const QString &iso) { return false; } -void CountryInput::onFinishCountry() { - if (_select) { - _select->hide(); - _select->deleteLater(); - _select = 0; - emit selectClosed(); - } -} - void CountryInput::setText(const QString &newText) { _text = _st.font->elided(newText, width() - _st.textMrg.left() - _st.textMrg.right()); } CountryInput::~CountryInput() { - delete _select; } -CountryList::CountryList(QWidget *parent, const style::countryList &st) : QWidget(parent), _sel(0), - _st(st), _mouseSel(false) { +CountrySelectInner::CountrySelectInner() : TWidget() +, _rowHeight(st::countryRowHeight) +, _sel(0) +, _mouseSel(false) { + setAttribute(Qt::WA_OpaquePaintEvent); + CountriesByISO2::const_iterator l = _countriesByISO2.constFind(lastValidISO); bool seenLastValid = false; int already = countriesAll.size(); @@ -228,7 +214,7 @@ CountryList::CountryList(QWidget *parent, const style::countryList &st) : QWidge } else { countriesAll.push_back(ins); } - + QStringList namesList = QString::fromUtf8(ins->name).toLower().split(QRegularExpression("[\\s\\-]"), QString::SkipEmptyParts); CountryNames &names(countriesNames[i]); int l = namesList.size(); @@ -248,368 +234,284 @@ CountryList::CountryList(QWidget *parent, const style::countryList &st) : QWidge } } - lastFilter = ""; - resetList(); + _filter = qsl("a"); + updateFilter(); } -void CountryList::resetList() { - countriesNow = &countriesAll; - if (lastFilter.length()) { - QChar first = lastFilter[0].toLower(); - CountriesIds &ids(countriesByLetter[first]); - - QStringList filterList = lastFilter.split(QRegularExpression("[\\s\\-]"), QString::SkipEmptyParts); - int l = filterList.size(); - - CountryNames filter; - filter.reserve(l); - for (int i = 0; i < l; ++i) { - QString filterName = filterList[i].trimmed(); - if (!filterName.length()) continue; - filter.push_back(filterName); - } - CountryNames::const_iterator fb = filter.cbegin(), fe = filter.cend(), fi; - - countriesFiltered.clear(); - for (CountriesIds::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) { - int index = *i; - CountryNames &names(countriesNames[index]); - CountryNames::const_iterator nb = names.cbegin(), ne = names.cend(), ni; - for (fi = fb; fi != fe; ++fi) { - QString filterName(*fi); - for (ni = nb; ni != ne; ++ni) { - if (ni->startsWith(*fi)) { - break; - } - } - if (ni == ne) { - break; - } - } - if (fi == fe) { - countriesFiltered.push_back(countriesAll[index]); - } - } - countriesNow = &countriesFiltered; - } - resize(width(), countriesNow->length() ? (countriesNow->length() * _st.rowHeight + 2 * _st.verticalMargin) : parentWidget()->height()); - setSelected(0); -} - -void CountryList::paintEvent(QPaintEvent *e) { +void CountrySelectInner::paintEvent(QPaintEvent *e) { + Painter p(this); QRect r(e->rect()); - bool trivial = (rect() == r); - - QPainter p(this); - if (!trivial) { - p.setClipRect(r); - } + p.setClipRect(r); int l = countriesNow->size(); if (l) { - int32 from = floorclamp(r.y() - _st.verticalMargin, _st.rowHeight, 0, l); - int32 to = ceilclamp(r.y() + r.height() - _st.verticalMargin, _st.rowHeight, 0, l); - p.setFont(_st.font->f); - QRectF textRect(_st.margin + _st.borderMargin, _st.verticalMargin + from * _st.rowHeight, width() - 2 * _st.margin - 2 * _st.borderMargin, _st.rowHeight - _st.borderWidth); - for (int i = from; i < to; ++i) { + if (r.intersects(QRect(0, 0, width(), st::countriesSkip))) { + p.fillRect(r.intersected(QRect(0, 0, width(), st::countriesSkip)), st::white->b); + } + int32 from = floorclamp(r.y() - st::countriesSkip, _rowHeight, 0, l); + int32 to = ceilclamp(r.y() + r.height() - st::countriesSkip, _rowHeight, 0, l); + for (int32 i = from; i < to; ++i) { bool sel = (i == _sel); - if (sel) { - p.fillRect(_st.borderMargin, _st.verticalMargin + i * _st.rowHeight, width() - 2 * _st.borderMargin, _st.rowHeight, _st.bgHovered->b); + int32 y = st::countriesSkip + i * _rowHeight; + + p.fillRect(0, y, width(), _rowHeight, (sel ? st::countryRowBgOver : st::white)->b); + + QString code = QString("+") + (*countriesNow)[i]->code; + int32 codeWidth = st::countryRowCodeFont->width(code); + + QString name = QString::fromUtf8((*countriesNow)[i]->name); + int32 nameWidth = st::countryRowNameFont->width(name); + int32 availWidth = width() - st::countryRowPadding.left() - st::countryRowPadding.right() - codeWidth - st::contactsScroll.width; + if (nameWidth > availWidth) { + name = st::countryRowNameFont->elided(name, availWidth); + nameWidth = st::countryRowNameFont->width(name); } - p.setFont(_st.font->f); - p.setPen(_st.color->p); - p.drawText(textRect, _st.font->elided(QString::fromUtf8((*countriesNow)[i]->name), width() - 2 * _st.margin - _st.codeWidth), QTextOption(style::al_left)); - p.setFont(_st.codeFont->f); - p.setPen(_st.codeColor->p); - p.drawText(textRect, QString("+") + (*countriesNow)[i]->code, QTextOption(style::al_right)); - textRect.setBottom(textRect.bottom() + _st.rowHeight); - textRect.setTop(textRect.top() + _st.rowHeight); + + p.setFont(st::countryRowNameFont); + p.setPen(st::black); + p.drawTextLeft(st::countryRowPadding.left(), y + st::countryRowPadding.top(), width(), name); + p.setFont(st::countryRowCodeFont); + p.setPen(sel ? st::countryRowCodeFgOver : st::countryRowCodeFg); + p.drawTextLeft(st::countryRowPadding.left() + nameWidth + st::countryRowPadding.right(), y + st::countryRowPadding.top(), width(), code); } } else { - p.setFont(_st.notFoundFont->f); - p.setPen(_st.notFoundColor->p); - p.drawText(r, lang(lng_country_none), QTextOption(style::al_center)); + p.fillRect(r, st::white->b); + p.setFont(st::noContactsFont->f); + p.setPen(st::noContactsColor->p); + p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_country_none), style::al_center); } } -void CountryList::mouseMoveEvent(QMouseEvent *e) { - _mouseSel = true; - _mousePos = mapToGlobal(e->pos()); - onUpdateSelected(true); +void CountrySelectInner::enterEvent(QEvent *e) { + setMouseTracking(true); } -void CountryList::onUpdateSelected(bool force) { - QPoint p(mapFromGlobal(_mousePos)); - if ((!force && !rect().contains(p)) || !_mouseSel) return; +void CountrySelectInner::leaveEvent(QEvent *e) { + _mouseSel = false; + setMouseTracking(false); + if (_sel >= 0) { + updateSelectedRow(); + _sel = -1; + } +} - int newSelected = p.y(); - newSelected = (newSelected > _st.verticalMargin) ? (newSelected - _st.verticalMargin) / _st.rowHeight : 0; - int l = countriesNow->size(); +void CountrySelectInner::mouseMoveEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); +} - if (newSelected >= l) newSelected = l - 1; - if (newSelected < 0) newSelected = 0; - if (newSelected != _sel) { - _sel = newSelected; +void CountrySelectInner::mousePressEvent(QMouseEvent *e) { + _mouseSel = true; + _lastMousePos = e->globalPos(); + updateSel(); + if (e->button() == Qt::LeftButton) { + chooseCountry(); + } +} + +void CountrySelectInner::updateFilter(QString filter) { + filter = textSearchKey(filter); + + QStringList f; + if (!filter.isEmpty()) { + QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts); + int l = filterList.size(); + + f.reserve(l); + for (int i = 0; i < l; ++i) { + QString filterName = filterList[i].trimmed(); + if (filterName.isEmpty()) continue; + f.push_back(filterName); + } + filter = f.join(' '); + } + if (_filter != filter) { + _filter = filter; + + if (_filter.isEmpty()) { + countriesNow = &countriesAll; + } else { + QChar first = _filter[0].toLower(); + CountriesIds &ids(countriesByLetter[first]); + + QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi; + + countriesFiltered.clear(); + for (CountriesIds::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) { + int index = *i; + CountryNames &names(countriesNames[index]); + CountryNames::const_iterator nb = names.cbegin(), ne = names.cend(), ni; + for (fi = fb; fi != fe; ++fi) { + QString filterName(*fi); + for (ni = nb; ni != ne; ++ni) { + if (ni->startsWith(*fi)) { + break; + } + } + if (ni == ne) { + break; + } + } + if (fi == fe) { + countriesFiltered.push_back(countriesAll[index]); + } + } + countriesNow = &countriesFiltered; + } + refresh(); + _sel = countriesNow->isEmpty() ? -1 : 0; update(); } } -void CountryList::mousePressEvent(QMouseEvent *e) { - _mouseSel = true; - _mousePos = mapToGlobal(e->pos()); - onUpdateSelected(true); - - emit countrySelected(); -} - -void CountryList::enterEvent(QEvent *e) { - setMouseTracking(true); -} - -void CountryList::leaveEvent(QEvent *e) { - setMouseTracking(false); -} - -void CountryList::updateFiltered() { - resetList(); -} - -void CountryList::onParentGeometryChanged() { - _mousePos = QCursor::pos(); - if (rect().contains(mapFromGlobal(_mousePos))) { - setMouseTracking(true); - onUpdateSelected(true); - } -} - -void CountryList::selectSkip(int delta) { - setSelected(_sel + delta); -} - -void CountryList::selectSkipPage(int h, int delta) { - setSelected(_sel + delta * (h / int(_st.rowHeight) - 1)); -} - -void CountryList::setSelected(int newSelected) { +void CountrySelectInner::selectSkip(int32 dir) { _mouseSel = false; - if (newSelected >= countriesNow->size()) { - newSelected = countriesNow->size() - 1; + + int cur = (_sel >= 0) ? _sel : -1; + cur += dir; + if (cur <= 0) { + _sel = countriesNow->isEmpty() ? -1 : 0; + } else if (cur >= countriesNow->size()) { + _sel = -1; + } else { + _sel = cur; } - if (newSelected < 0) { - newSelected = 0; + if (_sel >= 0) { + emit mustScrollTo(st::countriesSkip + _sel * _rowHeight, st::countriesSkip + (_sel + 1) * _rowHeight); } - _sel = newSelected; - emit mustScrollTo(_sel * _st.rowHeight, (_sel + 1) * _st.rowHeight); update(); } -QString CountryList::getSelectedCountry() const { - if (lastFilter.length()) { - if (_sel < countriesFiltered.size()) { - return countriesFiltered[_sel]->iso2; - } else { - return ""; - } - } - return countriesAll[_sel]->iso2; +void CountrySelectInner::selectSkipPage(int32 h, int32 dir) { + int32 points = h / _rowHeight; + if (!points) return; + selectSkip(points * dir); } -CountrySelect::CountrySelect() : QWidget(App::wnd()), - _result("none"), - _filter(this, st::inpCountry, lang(lng_country_ph)), _scroll(this, st::scrollCountries), _list(&_scroll), - _doneButton(this, lang(lng_country_done), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), - _innerLeft(0), _innerTop(0), _innerWidth(0), _innerHeight(0), - a_alpha(0), a_bgAlpha(0), a_coord(st::countriesSlideShift), _shadow(st::boxShadow) { - setGeometry(App::wnd()->rect()); - - App::wnd()->topWidget(this); +void CountrySelectInner::chooseCountry() { + QString result; + if (_filter.isEmpty()) { + if (_sel >= 0 && _sel < countriesAll.size()) { + result = countriesAll[_sel]->iso2; + } + } else { + if (_sel >= 0 && _sel < countriesFiltered.size()) { + result = countriesFiltered[_sel]->iso2; + } + } + emit countryChosen(result); +} - connect(App::wnd(), SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); - connect(&_doneButton, SIGNAL(clicked()), this, SLOT(onCountryChoose())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCountryCancel())); - connect(&_scroll, SIGNAL(scrollFinished()), this, SLOT(onScrollFinished())); - connect(&_scroll, SIGNAL(geometryChanged()), &_list, SLOT(onParentGeometryChanged())); - connect(&_scroll, SIGNAL(scrolled()), &_list, SLOT(onUpdateSelected())); - connect(&_list, SIGNAL(countrySelected()), this, SLOT(onCountryChoose())); +void CountrySelectInner::refresh() { + resize(width(), countriesNow->length() ? (countriesNow->length() * _rowHeight + st::countriesSkip) : st::noContactsHeight); +} + +void CountrySelectInner::updateSel() { + if (!_mouseSel) return; + + QPoint p(mapFromGlobal(_lastMousePos)); + bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos)); + + int32 newSel = (in && p.y() >= st::countriesSkip && p.y() < st::countriesSkip + countriesNow->size() * _rowHeight) ? ((p.y() - st::countriesSkip) / _rowHeight) : -1; + if (newSel != _sel) { + updateSelectedRow(); + _sel = newSel; + updateSelectedRow(); + } +} + +void CountrySelectInner::updateSelectedRow() { + if (_sel >= 0) { + update(0, st::countriesSkip + _sel * _rowHeight, width(), _rowHeight); + } +} + +CountrySelectBox::CountrySelectBox() : ItemListBox(st::countriesScroll, st::boxWidth) +, _inner() +, _filter(this, st::boxSearchField, lang(lng_country_ph)) +, _filterCancel(this, st::boxSearchCancel) +, _topShadow(this) { + ItemListBox::init(&_inner, st::boxScrollSkip, st::boxTitleHeight + _filter.height()); + + connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); - connect(&_list, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); + connect(&_filter, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_filterCancel, SIGNAL(clicked()), this, SLOT(onFilterCancel())); + connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); + connect(&_inner, SIGNAL(countryChosen(const QString&)), this, SIGNAL(countryChosen(const QString&))); - show(); - setFocus(); - _scroll.setWidget(&_list); - _scroll.setFocusPolicy(Qt::NoFocus); + _filterCancel.setAttribute(Qt::WA_OpaquePaintEvent); - prepareAnimation(0); + prepare(); } -void CountrySelect::prepareAnimation(int to) { - if (to) { - if (_result == "none") _result = ""; - a_alpha.start(0); - af_alpha = st::countriesAlphaHideFunc; - a_bgAlpha.start(0); - af_bgAlpha = st::countriesBackHideFunc; - a_coord.start(to * st::countriesSlideShift); - af_coord = st::countriesHideFunc; - } else { - _result = "none"; - a_alpha.start(1); - af_alpha = st::countriesAlphaShowFunc; - a_bgAlpha.start(1); - af_bgAlpha = st::countriesBackShowFunc; - a_coord.start(0); - af_coord = st::countriesShowFunc; - } - _cache = myGrab(this, QRect(_innerLeft, _innerTop, _innerWidth, _innerHeight)); - _scroll.hide(); - _doneButton.hide(); - _cancelButton.hide(); - _filter.hide(); - anim::start(this); +void CountrySelectBox::onSubmit() { + _inner.chooseCountry(); } -void CountrySelect::paintEvent(QPaintEvent *e) { - bool trivial = (rect() == e->rect()); - - QPainter p(this); - if (!trivial) { - p.setClipRect(e->rect()); - } - p.setOpacity(st::layerAlpha * a_bgAlpha.current()); - p.fillRect(rect(), st::layerBG->b); - if (animating()) { - p.setOpacity(a_alpha.current()); - p.drawPixmap(a_coord.current() + _innerLeft, _innerTop, _cache); - } else { - p.setOpacity(1); - - QRect inner(_innerLeft, _innerTop, _innerWidth, _innerHeight); - _shadow.paint(p, inner, st::boxShadowShift); - if (trivial || e->rect().intersects(inner)) { - // fill bg - p.fillRect(inner, st::white->b); - - // paint shadows - p.fillRect(_innerLeft, _innerTop + st::participantFilter.height, _innerWidth, st::scrollDef.topsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(_innerLeft + st::btnSelectCancel.width, _innerTop + _innerHeight - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); - - // draw box title / text - p.setPen(st::black->p); - p.setFont(st::old_boxTitleFont->f); - p.drawText(_innerLeft + st::old_boxTitlePos.x(), _innerTop + st::old_boxTitlePos.y() + st::old_boxTitleFont->ascent, lang(lng_country_select)); - } - } -} - -void CountrySelect::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Escape) { - onCountryCancel(); - } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { - onCountryChoose(); - } else if (e->key() == Qt::Key_Down) { - _list.selectSkip(1); +void CountrySelectBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Down) { + _inner.selectSkip(1); } else if (e->key() == Qt::Key_Up) { - _list.selectSkip(-1); + _inner.selectSkip(-1); } else if (e->key() == Qt::Key_PageDown) { - _list.selectSkipPage(_scroll.height(), 1); + _inner.selectSkipPage(_scroll.height(), 1); } else if (e->key() == Qt::Key_PageUp) { - _list.selectSkipPage(_scroll.height(), -1); - } -} - -void CountrySelect::mousePressEvent(QMouseEvent *e) { - if (!QRect(_innerLeft, _innerTop, _innerWidth, _innerHeight).contains(e->pos())) { - onCountryCancel(); - } -} - -void CountrySelect::onFilterUpdate() { - QString newFilter(_filter.text().trimmed().toLower()); - if (newFilter != lastFilter) { - lastFilter = newFilter; - _list.updateFiltered(); - } -} - -void CountrySelect::resizeEvent(QResizeEvent *e) { - if (width() != e->oldSize().width()) { - _innerWidth = st::old_newGroupNamePadding.left() + _filter.width() + st::old_newGroupNamePadding.right(); - _innerLeft = (width() - _innerWidth) / 2; - - _list.resize(_innerWidth, _list.height()); - } - if (height() != e->oldSize().height()) { - _innerTop = st::introSelectDelta; - _innerHeight = height() - _innerTop - st::introSelectDelta; - if (_innerHeight > st::boxMaxListHeight) { - _innerHeight = st::boxMaxListHeight; - _innerTop = (height() - _innerHeight) / 2; - } - } - - _filter.move(_innerLeft + st::old_newGroupNamePadding.left(), _innerTop + st::contactsAdd.height + st::old_newGroupNamePadding.top()); - int32 scrollTop = _filter.y() + _filter.height() + st::old_newGroupNamePadding.bottom(); - int32 scrollHeight = _innerHeight - st::contactsAdd.height - st::old_newGroupNamePadding.top() - _filter.height() - st::old_newGroupNamePadding.bottom() - _cancelButton.height(); - _scroll.setGeometry(_innerLeft, scrollTop, _innerWidth, scrollHeight); - - int btnTop = scrollTop + scrollHeight; - _cancelButton.move(_innerLeft, btnTop); - _doneButton.move(_innerLeft + _innerWidth - _doneButton.width(), btnTop); -} - -bool CountrySelect::animStep(float64 ms) { - float64 dt = ms / st::countriesSlideDuration; - bool res = true; - if (dt >= 1) { - a_alpha.finish(); - a_bgAlpha.finish(); - a_coord.finish(); - _cache = QPixmap(); - _scroll.show(); - _doneButton.show(); - _cancelButton.show(); - _filter.show(); - _filter.setFocus(); - if (_result != "none") { - QTimer::singleShot(0, this, SIGNAL(countryFinished())); - } - res = false; + _inner.selectSkipPage(_scroll.height(), -1); } else { - a_alpha.update(dt, af_alpha); - a_bgAlpha.update(dt, af_bgAlpha); - a_coord.update(dt, af_coord); + ItemListBox::keyPressEvent(e); } - update(); - return res; } -void CountrySelect::onParentResize(const QSize &newSize) { - resize(App::wnd()->size()); +void CountrySelectBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + paintTitle(p, lang(lng_country_select)); } -void CountrySelect::onCountryCancel() { - finish(""); +void CountrySelectBox::resizeEvent(QResizeEvent *e) { + ItemListBox::resizeEvent(e); + _filter.resize(width(), _filter.height()); + _filter.moveToLeft(0, st::boxTitleHeight); + _filterCancel.moveToRight(0, st::boxTitleHeight); + _inner.resize(width(), _inner.height()); + _topShadow.setGeometry(0, st::boxTitleHeight + _filter.height(), width(), st::lineWidth); } -void CountrySelect::onCountryChoose() { - finish(_list.getSelectedCountry()); +void CountrySelectBox::hideAll() { + _filter.hide(); + _filterCancel.hide(); + _topShadow.hide(); + ItemListBox::hideAll(); } -void CountrySelect::finish(const QString &res) { - _result = res; - prepareAnimation(_result.length() ? -1 : 1); - emit countryChosen(_result); +void CountrySelectBox::showAll() { + _filter.show(); + if (_filter.getLastText().isEmpty()) { + _filterCancel.hide(); + } else { + _filterCancel.show(); + } + _topShadow.show(); + ItemListBox::showAll(); } -void CountrySelect::onScrollFinished() { +void CountrySelectBox::onFilterCancel() { + _filter.setText(QString()); +} + +void CountrySelectBox::onFilterUpdate() { + _scroll.scrollToY(0); + if (_filter.getLastText().isEmpty()) { + _filterCancel.hide(); + } else { + _filterCancel.show(); + } + _inner.updateFilter(_filter.getLastText()); +} + +void CountrySelectBox::showDone() { _filter.setFocus(); } - -CountrySelect::~CountrySelect() { - if (App::wnd()) { - App::wnd()->noTopWidget(this); - } -} diff --git a/Telegram/SourceFiles/gui/countryinput.h b/Telegram/SourceFiles/gui/countryinput.h index 4f356edc0..ff6c7e234 100644 --- a/Telegram/SourceFiles/gui/countryinput.h +++ b/Telegram/SourceFiles/gui/countryinput.h @@ -20,13 +20,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org */ #pragma once -#include #include "style.h" #include "gui/flatinput.h" #include "gui/scrollarea.h" #include "gui/flatbutton.h" #include "gui/boxshadow.h" +#include "boxes/abstractbox.h" QString findValidCode(QString fullCode); @@ -51,12 +51,10 @@ public slots: void onChooseCode(const QString &code); bool onChooseCountry(const QString &country); - void onFinishCountry(); signals: void codeChanged(const QString &code); - void selectClosed(); private: @@ -72,6 +70,89 @@ private: }; +class CountrySelectInner : public TWidget { + Q_OBJECT + +public: + + CountrySelectInner(); + void paintEvent(QPaintEvent *e); + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + + void updateFilter(QString filter = QString()); + + void selectSkip(int32 dir); + void selectSkipPage(int32 h, int32 dir); + + void chooseCountry(); + + void refresh(); + +signals: + + void countryChosen(const QString &iso); + void mustScrollTo(int ymin, int ymax); + +public slots: + + void updateSel(); + +private: + + void updateSelectedRow(); + + int32 _rowHeight; + + int32 _sel; + QString _filter; + bool _mouseSel; + + QPoint _lastMousePos; +}; + +class CountrySelectBox : public ItemListBox { + Q_OBJECT + +public: + + CountrySelectBox(); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + void setInnerFocus() { + _filter.setFocus(); + } + +signals: + + void countryChosen(const QString &iso); + +public slots: + + void onFilterUpdate(); + void onFilterCancel(); + void onSubmit(); + +protected: + + void showDone(); + void hideAll(); + void showAll(); + +private: + + CountrySelectInner _inner; + InputField _filter; + IconedButton _filterCancel; + + ScrollableBoxShadow _topShadow; +}; + +/** / class CountryList : public QWidget { Q_OBJECT @@ -153,7 +234,7 @@ private: FlatInput _filter; ScrollArea _scroll; CountryList _list; - FlatButton _doneButton, _cancelButton; + BoxButton _doneButton, _cancelButton; int32 _innerLeft, _innerTop, _innerWidth, _innerHeight; anim::fvalue a_alpha, a_bgAlpha; @@ -164,3 +245,4 @@ private: BoxShadow _shadow; }; +*/ \ No newline at end of file diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp index a5e039da7..75db4c86b 100644 --- a/Telegram/SourceFiles/gui/flatbutton.cpp +++ b/Telegram/SourceFiles/gui/flatbutton.cpp @@ -296,7 +296,7 @@ void MaskedButton::paintEvent(QPaintEvent *e) { } BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent), -_text(text), _fullText(text), _textWidth(st.font->width(text)), +_text(text.toUpper()), _fullText(text.toUpper()), _textWidth(st.font->width(_text)), _st(st), a_textBgOverOpacity(0), a_textFg(st.textFg->c), _a_over(animFunc(this, &BoxButton::animStep_over)) { if (_st.width <= 0) { diff --git a/Telegram/SourceFiles/gui/flatinput.cpp b/Telegram/SourceFiles/gui/flatinput.cpp index 1e5cfb7e4..f3a19c9ac 100644 --- a/Telegram/SourceFiles/gui/flatinput.cpp +++ b/Telegram/SourceFiles/gui/flatinput.cpp @@ -400,10 +400,10 @@ void CountryCodeInput::correctValue(const QString &was, QString &now) { } } -PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) { +PhonePartInput::PhonePartInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) { } -void PhoneInput::paintEvent(QPaintEvent *e) { +void PhonePartInput::paintEvent(QPaintEvent *e) { FlatInput::paintEvent(e); Painter p(this); @@ -423,7 +423,7 @@ void PhoneInput::paintEvent(QPaintEvent *e) { } } -void PhoneInput::keyPressEvent(QKeyEvent *e) { +void PhonePartInput::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Backspace && text().isEmpty()) { emit voidBackspace(e); } else { @@ -431,7 +431,7 @@ void PhoneInput::keyPressEvent(QKeyEvent *e) { } } -void PhoneInput::correctValue(const QString &was, QString &now) { +void PhonePartInput::correctValue(const QString &was, QString &now) { QString newText; int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), digitCount = 0; for (int i = 0; i < oldLen; ++i) { @@ -497,7 +497,7 @@ void PhoneInput::correctValue(const QString &was, QString &now) { } } -void PhoneInput::addedToNumber(const QString &added) { +void PhonePartInput::addedToNumber(const QString &added) { setFocus(); QString wasText(getLastText()), newText = added + wasText; setText(newText); @@ -506,7 +506,7 @@ void PhoneInput::addedToNumber(const QString &added) { updatePlaceholder(); } -void PhoneInput::onChooseCode(const QString &code) { +void PhonePartInput::onChooseCode(const QString &code) { pattern = phoneNumberParse(code); if (!pattern.isEmpty() && pattern.at(0) == code.size()) { pattern.pop_front(); @@ -1119,6 +1119,10 @@ void InputArea::customUpDown(bool custom) { _customUpDown = custom; } +void InputArea::setCtrlEnterSubmit(bool ctrlEnterSubmit) { + _ctrlEnterSubmit = ctrlEnterSubmit; +} + void InputArea::InputAreaInner::keyPressEvent(QKeyEvent *e) { bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier); bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier); @@ -1201,7 +1205,7 @@ _oldtext(val), _undoAvailable(false), _redoAvailable(false), -_customUpDown(false), +_customUpDown(true), _placeholderFull(ph), _placeholderVisible(val.isEmpty()), @@ -1717,6 +1721,13 @@ void InputField::onRedoAvailable(bool avail) { if (App::wnd()) App::wnd()->updateGlobalMenu(); } +void InputField::selectAll() { + QTextCursor c(_inner.textCursor()); + c.setPosition(0); + c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + _inner.setTextCursor(c); +} + bool InputField::animStep_placeholderFg(float64 ms) { float dt = ms / _st.duration; bool res = true; @@ -2102,10 +2113,14 @@ bool MaskedInputField::animStep_border(float64 ms) { return res; } -void MaskedInputField::setPlaceholder(const QString &placeholder) { - _placeholderFull = placeholder; - resizeEvent(0); - update(); +bool MaskedInputField::setPlaceholder(const QString &placeholder) { + if (_placeholderFull != placeholder) { + _placeholderFull = placeholder; + resizeEvent(0); + update(); + return true; + } + return false; } void MaskedInputField::setPlaceholderFast(bool fast) { @@ -2213,7 +2228,7 @@ void MaskedInputField::onTextEdited() { } void MaskedInputField::onTextChange(const QString &text) { - _oldtext = text; + _oldtext = QLineEdit::text(); if (_error) { _error = false; startBorderAnimation(); @@ -2225,6 +2240,10 @@ void MaskedInputField::onCursorPositionChanged(int oldPosition, int position) { _oldcursor = position; } +PasswordField::PasswordField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) { + setEchoMode(QLineEdit::Password); +} + PortInput::PortInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) { if (!val.toInt() || val.toInt() > 65535) { setText(QString()); @@ -2307,3 +2326,143 @@ void UsernameInput::correctValue(const QString &was, int32 wasCursor, QString &n setCursorPosition(newCursor); } } + +PhoneInput::PhoneInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) +, _defaultPlaceholder(ph) { + QString phone(val); + if (phone.isEmpty()) { + clearText(); + } else { + int32 pos = phone.size(); + correctValue(QString(), 0, phone, pos); + } +} + +void PhoneInput::focusInEvent(QFocusEvent *e) { + MaskedInputField::focusInEvent(e); + setSelection(cursorPosition(), cursorPosition()); +} + +void PhoneInput::clearText() { + QString phone; + if (App::self()) { + QVector newPattern = phoneNumberParse(App::self()->phone); + if (!newPattern.isEmpty()) { + phone = App::self()->phone.mid(0, newPattern.at(0)); + } + } + setText(phone); + int32 pos = phone.size(); + correctValue(QString(), 0, phone, pos); +} + +void PhoneInput::paintPlaceholder(Painter &p) { + QString t(getLastText()); + if (!pattern.isEmpty() && !t.isEmpty()) { + QString ph = placeholder().mid(t.size()); + if (!ph.isEmpty()) { + p.setClipRect(rect()); + QRect phRect(placeholderRect()); + int tw = phFont()->width(t); + if (tw < phRect.width()) { + phRect.setLeft(phRect.left() + tw); + placeholderPreparePaint(p); + p.drawText(phRect, ph, style::al_topleft); + } + } + } else { + MaskedInputField::paintPlaceholder(p); + } +} + +void PhoneInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) { + QString digits(now); + digits.replace(QRegularExpression(qsl("[^\\d]")), QString()); + pattern = phoneNumberParse(digits); + + QString newPlaceholder; + if (pattern.isEmpty()) { + newPlaceholder = lang(lng_contact_phone); + } else if (pattern.size() == 1 && pattern.at(0) == digits.size()) { + newPlaceholder = QString(pattern.at(0) + 2, ' ') + lang(lng_contact_phone); + } else { + newPlaceholder.reserve(20); + for (int i = 0, l = pattern.size(); i < l; ++i) { + if (i) { + newPlaceholder.append(' '); + } else { + newPlaceholder.append('+'); + } + newPlaceholder.append(i ? QString(pattern.at(i), QChar(0x2212)) : digits.mid(0, pattern.at(i))); + } + } + if (setPlaceholder(newPlaceholder)) { + setPlaceholderFast(!pattern.isEmpty()); + updatePlaceholder(); + } + + QString newText; + int oldPos(nowCursor), newPos(-1), oldLen(now.length()), digitCount = qMin(digits.size(), MaxPhoneCodeLength + MaxPhoneTailLength); + + bool inPart = !pattern.isEmpty(), plusFound = false; + int curPart = 0, leftInPart = inPart ? pattern.at(curPart) : 0; + newText.reserve(oldLen + 1); + newText.append('+'); + for (int i = 0; i < oldLen; ++i) { + if (i == oldPos && newPos < 0) { + newPos = newText.length(); + } + + QChar ch(now[i]); + if (ch.isDigit()) { + if (!digitCount--) { + break; + } + if (inPart) { + if (leftInPart) { + --leftInPart; + } else { + newText += ' '; + ++curPart; + inPart = curPart < pattern.size(); + leftInPart = inPart ? (pattern.at(curPart) - 1) : 0; + + ++oldPos; + } + } + newText += ch; + } else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') { + if (inPart) { + if (leftInPart) { + } else { + newText += ch; + ++curPart; + inPart = curPart < pattern.size(); + leftInPart = inPart ? pattern.at(curPart) : 0; + } + } else { + newText += ch; + } + } else if (ch == '+') { + plusFound = true; + } + } + if (!plusFound && newText == qstr("+")) { + newText = QString(); + newPos = 0; + } + int32 newlen = newText.size(); + while (newlen > 0 && newText.at(newlen - 1).isSpace()) { + --newlen; + } + if (newlen < newText.size()) newText = newText.mid(0, newlen); + if (newPos < 0) { + newPos = newText.length(); + } + if (newText != now) { + now = newText; + setText(newText); + updatePlaceholder(); + setCursorPosition(newPos); + } +} diff --git a/Telegram/SourceFiles/gui/flatinput.h b/Telegram/SourceFiles/gui/flatinput.h index 3f506c52a..6c48c3169 100644 --- a/Telegram/SourceFiles/gui/flatinput.h +++ b/Telegram/SourceFiles/gui/flatinput.h @@ -135,12 +135,12 @@ private: }; -class PhoneInput : public FlatInput { +class PhonePartInput : public FlatInput { Q_OBJECT public: - PhoneInput(QWidget *parent, const style::flatInput &st); + PhonePartInput(QWidget *parent, const style::flatInput &st); void paintEvent(QPaintEvent *e); void keyPressEvent(QKeyEvent *e); @@ -203,6 +203,7 @@ public: bool isRedoAvailable() const; void customUpDown(bool isCustom); + void setCtrlEnterSubmit(bool ctrlEnterSubmit); void setTextCursor(const QTextCursor &cursor) { return _inner.setTextCursor(cursor); @@ -333,6 +334,10 @@ public: void contextMenuEvent(QContextMenuEvent *e); void resizeEvent(QResizeEvent *e); + void setMaxLength(int32 maxLength) { + _maxLength = maxLength; + } + void showError(); const QString &getLastText() const { @@ -397,6 +402,8 @@ public slots: void onUndoAvailable(bool avail); void onRedoAvailable(bool avail); + void selectAll(); + signals: void changed(); @@ -499,7 +506,7 @@ public: void showError(); - void setPlaceholder(const QString &ph); + bool setPlaceholder(const QString &ph); void setPlaceholderFast(bool fast); void updatePlaceholder(); @@ -591,9 +598,14 @@ private: QPoint _touchStart; }; -class PortInput : public MaskedInputField { - Q_OBJECT +class PasswordField : public MaskedInputField { +public: + PasswordField(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString()); + +}; + +class PortInput : public MaskedInputField { public: PortInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val); @@ -619,3 +631,23 @@ private: QString _linkPlaceholder; }; + +class PhoneInput : public MaskedInputField { +public: + + PhoneInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val); + + void focusInEvent(QFocusEvent *e); + void clearText(); + +protected: + + void paintPlaceholder(Painter &p); + void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor); + +private: + + QString _defaultPlaceholder; + QVector pattern; + +}; diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 811d88171..b990f358a 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -1100,6 +1100,9 @@ public: virtual ImagePtr replyPreview() { return ImagePtr(); } + virtual QString getCaption() const { + return QString(); + } int32 currentWidth() const { return qMin(w, _maxw); @@ -1152,6 +1155,10 @@ public: } ImagePtr replyPreview(); + QString getCaption() const { + return _caption.original(0, 0xFFFFU, true); + } + private: int16 pixw, pixh; PhotoData *data; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 34a2a2956..db24f7f37 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -67,6 +67,7 @@ HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, His , _touchAccelerationTime(0) , _touchTime(0) , _menu(0) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); linkTipTimer.setSingleShot(true); connect(&linkTipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip())); @@ -2037,7 +2038,7 @@ HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : QWidget(p , _forwardSelected(forwardSelected) , _sendPath(false) , _send(this, lang(lng_forward_send), st::defaultBoxButton) -, _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , offered(0) , a_opacity(0, 1) , hiding(false) @@ -2053,7 +2054,7 @@ HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : QWidge , _forwardSelected(false) , _sendPath(false) , _send(this, lang(lng_forward_send), st::defaultBoxButton) -, _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , offered(0) , a_opacity(0, 1) , hiding(false) @@ -2069,7 +2070,7 @@ HistoryHider::HistoryHider(MainWidget *parent) : QWidget(parent) , _forwardSelected(false) , _sendPath(true) , _send(this, lang(lng_forward_send), st::defaultBoxButton) -, _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) +, _cancel(this, lang(lng_cancel), st::cancelBoxButton) , offered(0) , a_opacity(0, 1) , hiding(false) @@ -2116,7 +2117,7 @@ void HistoryHider::paintEvent(QPaintEvent *e) { Painter p(this); if (!hiding || !cacheForAnim.isNull() || !offered) { p.setOpacity(a_opacity.current() * st::layerAlpha); - p.fillRect(rect(), st::layerBG->b); + p.fillRect(rect(), st::layerBg->b); p.setOpacity(a_opacity.current()); } if (cacheForAnim.isNull() || !offered) { @@ -2125,7 +2126,7 @@ void HistoryHider::paintEvent(QPaintEvent *e) { shadow.paint(p, box, st::boxShadowShift); // fill bg - p.fillRect(box, st::boxBG->b); + p.fillRect(box, st::boxBg->b); p.setPen(st::black->p); toText.drawElided(p, box.left() + st::boxPadding.left(), box.top() + st::boxPadding.top(), toTextWidth + 2); @@ -2255,8 +2256,8 @@ bool HistoryHider::offerPeer(PeerId peer) { toText.setText(st::boxTextFont, phrase, _textNameOptions); toTextWidth = toText.maxWidth(); - if (toTextWidth > box.width() - st::boxPadding.left() - st::boxPadding.right()) { - toTextWidth = box.width() - st::boxPadding.left() - st::boxPadding.right(); + if (toTextWidth > box.width() - st::boxPadding.left() - st::boxButtonPadding.right()) { + toTextWidth = box.width() - st::boxPadding.left() - st::boxButtonPadding.right(); } resizeEvent(0); @@ -4878,7 +4879,7 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) { flags |= MTPDmessage::flag_from_id; } if (img.type == ToPreparePhoto) { - h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string("")), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); + h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo, MTP_string(img.caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); } else if (img.type == ToPrepareDocument) { h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(img.peer), MTPPeer(), MTPint(), MTP_int(img.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread); } else if (img.type == ToPrepareAudio) { @@ -4919,7 +4920,8 @@ void HistoryWidget::onPhotoUploaded(const FullMsgId &newId, const MTPInputFile & if (fromChannelName) { sendFlags |= MTPmessages_SendMessage_flag_broadcast; } - hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedPhoto(file, MTP_string("")), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendPhotoFail, randomId), 0, 0, hist->sendRequestId); + QString caption = item->getMedia() ? item->getMedia()->getCaption() : QString(); + hist->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), item->history()->peer->input, MTP_int(replyTo), MTP_inputMediaUploadedPhoto(file, MTP_string(caption)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendPhotoFail, randomId), 0, 0, hist->sendRequestId); } } diff --git a/Telegram/SourceFiles/intro/introphone.cpp b/Telegram/SourceFiles/intro/introphone.cpp index 46e016689..cc98c7b73 100644 --- a/Telegram/SourceFiles/intro/introphone.cpp +++ b/Telegram/SourceFiles/intro/introphone.cpp @@ -63,7 +63,6 @@ IntroPhone::IntroPhone(IntroWidget *parent) : IntroStage(parent), connect(&code, SIGNAL(codeChanged(const QString &)), &phone, SLOT(onChooseCode(const QString &))); connect(&country, SIGNAL(codeChanged(const QString &)), &phone, SLOT(onChooseCode(const QString &))); connect(&code, SIGNAL(addedToNumber(const QString &)), &phone, SLOT(addedToNumber(const QString &))); - connect(&country, SIGNAL(selectClosed()), this, SLOT(onSelectClose())); connect(&phone, SIGNAL(changed()), this, SLOT(onInputChange())); connect(&code, SIGNAL(changed()), this, SLOT(onInputChange())); connect(intro(), SIGNAL(countryChanged()), this, SLOT(countryChanged())); @@ -162,10 +161,6 @@ void IntroPhone::countryChanged() { } } -void IntroPhone::onSelectClose() { - phone.setFocus(); -} - void IntroPhone::onInputChange() { changed = true; showError(""); diff --git a/Telegram/SourceFiles/intro/introphone.h b/Telegram/SourceFiles/intro/introphone.h index 7e559e207..22a5b963b 100644 --- a/Telegram/SourceFiles/intro/introphone.h +++ b/Telegram/SourceFiles/intro/introphone.h @@ -53,7 +53,6 @@ public: public slots: void countryChanged(); - void onSelectClose(); void onInputChange(); void onSubmitPhone(bool force = false); void onCheckRequest(); @@ -76,7 +75,7 @@ private: QRect textRect; CountryInput country; - PhoneInput phone; + PhonePartInput phone; CountryCodeInput code; FlatLabel _signup; diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index abddad43d..2e4352567 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -54,7 +54,7 @@ void BackgroundWidget::paintEvent(QPaintEvent *e) { p.setClipRect(e->rect()); } p.setOpacity(st::layerAlpha * aBackground.current()); - p.fillRect(rect(), st::layerBG->b); + p.fillRect(rect(), st::layerBg->b); p.setOpacity(aBackground.current()); shadow.paint(p, w->geometry(), st::boxShadowShift); diff --git a/Telegram/SourceFiles/localimageloader.h b/Telegram/SourceFiles/localimageloader.h index d741274ec..e21d2c707 100644 --- a/Telegram/SourceFiles/localimageloader.h +++ b/Telegram/SourceFiles/localimageloader.h @@ -81,6 +81,7 @@ struct ReadyLocalMedia { bool broadcast; bool ctrlShiftEnter; + QString caption; }; typedef QList ReadyLocalMedias; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 18f5b4e34..19fa8fb8b 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -91,8 +91,8 @@ void TopBarWidget::onEdit() { App::wnd()->showLayer(new EditChannelBox(p->asChannel())); } else if (p->isChat()) { App::wnd()->showLayer(new EditNameTitleBox(p)); - } else { - App::wnd()->showLayer(new AddContactBox(p)); + } else if (p->isUser()) { + App::wnd()->showLayer(new AddContactBox(p->asUser())); } } } diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index e32e26581..77f95b134 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -137,57 +137,58 @@ int32 OverviewInner::CachedLink::countHeight(int32 w) { // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const PeerData *peer, MediaOverviewType type) : QWidget(0) - , _overview(overview) - , _scroll(scroll) - , _resizeIndex(-1) - , _resizeSkip(0) - , _peer(App::peer(peer->id)) - , _type(type) - , _hist(App::history(peer->id)) - , _channel(peerToChannel(peer->id)) - , _photosInRow(1) - , _photosToAdd(0) - , _selMode(false) - , _audioLeft(st::msgMargin.left()) - , _audioWidth(st::msgMinWidth) - , _audioHeight(st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom()) - , _linksLeft(st::linksSearchMargin.left()) - , _linksWidth(st::msgMinWidth) - , _search(this, st::dlgFilter, lang(lng_dlg_filter)) - , _cancelSearch(this, st::btnCancelSearch) - , _itemsToBeLoaded(LinksOverviewPerPage * 2) - , _inSearch(false) - , _searchFull(false) - , _searchRequest(0) - , _lastSearchId(0) - , _searchedCount(0) - , _width(st::wndMinWidth) - , _height(0) - , _minHeight(0) - , _addToY(0) - , _cursor(style::cur_default) - , _cursorState(HistoryDefaultCursorState) - , _dragAction(NoDrag) - , _dragItem(0), _selectedMsgId(0) - , _dragItemIndex(-1) - , _mousedItem(0) - , _mousedItemIndex(-1) - , _lnkOverIndex(0) - , _lnkDownIndex(0) - , _dragWasInactive(false) - , _dragSelFrom(0) - , _dragSelTo(0) - , _dragSelecting(false) - , _touchScroll(false) - , _touchSelect(false) - , _touchInProgress(false) - , _touchScrollState(TouchScrollManual) - , _touchPrevPosValid(false) - , _touchWaitingAcceleration(false) - , _touchSpeedTime(0) - , _touchAccelerationTime(0) - , _touchTime(0) - , _menu(0) { +, _overview(overview) +, _scroll(scroll) +, _resizeIndex(-1) +, _resizeSkip(0) +, _peer(App::peer(peer->id)) +, _type(type) +, _hist(App::history(peer->id)) +, _channel(peerToChannel(peer->id)) +, _photosInRow(1) +, _photosToAdd(0) +, _selMode(false) +, _audioLeft(st::msgMargin.left()) +, _audioWidth(st::msgMinWidth) +, _audioHeight(st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom()) +, _linksLeft(st::linksSearchMargin.left()) +, _linksWidth(st::msgMinWidth) +, _search(this, st::dlgFilter, lang(lng_dlg_filter)) +, _cancelSearch(this, st::btnCancelSearch) +, _itemsToBeLoaded(LinksOverviewPerPage * 2) +, _inSearch(false) +, _searchFull(false) +, _searchRequest(0) +, _lastSearchId(0) +, _searchedCount(0) +, _width(st::wndMinWidth) +, _height(0) +, _minHeight(0) +, _addToY(0) +, _cursor(style::cur_default) +, _cursorState(HistoryDefaultCursorState) +, _dragAction(NoDrag) +, _dragItem(0), _selectedMsgId(0) +, _dragItemIndex(-1) +, _mousedItem(0) +, _mousedItemIndex(-1) +, _lnkOverIndex(0) +, _lnkDownIndex(0) +, _dragWasInactive(false) +, _dragSelFrom(0) +, _dragSelTo(0) +, _dragSelecting(false) +, _touchScroll(false) +, _touchSelect(false) +, _touchInProgress(false) +, _touchScrollState(TouchScrollManual) +, _touchPrevPosValid(false) +, _touchWaitingAcceleration(false) +, _touchSpeedTime(0) +, _touchAccelerationTime(0) +, _touchTime(0) +, _menu(0) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); resize(_width, height()); diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index 4b77af01e..5532274a3 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -186,7 +186,7 @@ void PasscodeWidget::paintEvent(QPaintEvent *e) { p.drawText(QRect(0, _passcode.y() - st::passcodeHeaderHeight, width(), st::passcodeHeaderHeight), lang(lng_passcode_enter), style::al_center); if (!_error.isEmpty()) { - p.setFont(st::boxFont->f); + p.setFont(st::boxTextFont->f); p.setPen(st::setErrColor->p); p.drawText(QRect(0, _passcode.y() + _passcode.height(), width(), st::usernameSkip), _error, style::al_center); } diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index ef4b4bdd1..42c40b773 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -83,6 +83,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee _kickOver(0), _kickDown(0), _kickConfirm(0), _menu(0) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index 85a0e5df1..9679783e6 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -199,6 +199,8 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent), _supportGetRequest(0) { if (self()) { + connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); + _nameText.setText(st::setNameFont, _nameCache, _textNameOptions); PhotoData *selfPhoto = (self()->photoId && self()->photoId != UnknownPeerPhotoId) ? App::photo(self()->photoId) : 0; if (selfPhoto && selfPhoto->date) _photoLink = TextLinkPtr(new PhotoLink(selfPhoto, self())); @@ -1207,12 +1209,12 @@ void SettingsInner::chooseCustomLang() { QByteArray arr; if (filedialogGetOpenFile(file, arr, qsl("Choose language .strings file"), qsl("Language files (*.strings)"))) { _testlang = QFileInfo(file).absoluteFilePath(); - LangLoaderPlain loader(_testlang, LangLoaderRequest(lng_sure_save_language, lng_box_cancel, lng_box_ok)); + LangLoaderPlain loader(_testlang, LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok)); if (loader.errors().isEmpty()) { LangLoaderResult result = loader.found(); QString text = result.value(lng_sure_save_language, langOriginal(lng_sure_save_language)), save = result.value(lng_box_ok, langOriginal(lng_box_ok)), - cancel = result.value(lng_box_cancel, langOriginal(lng_box_cancel)); + cancel = result.value(lng_cancel, langOriginal(lng_cancel)); ConfirmBox *box = new ConfirmBox(text, save, st::defaultBoxButton, cancel); connect(box, SIGNAL(confirmed()), this, SLOT(onSaveTestLang())); App::wnd()->showLayer(box); diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp index c65425fa1..7c81d746d 100644 --- a/Telegram/SourceFiles/title.cpp +++ b/Telegram/SourceFiles/title.cpp @@ -35,7 +35,7 @@ TitleHider::TitleHider(QWidget *parent) : QWidget(parent), _level(0) { void TitleHider::paintEvent(QPaintEvent *e) { QPainter p(this); p.setOpacity(_level * st::layerAlpha); - p.fillRect(App::main()->dlgsWidth() - st::dlgShadow, 0, width() + st::dlgShadow - App::main()->dlgsWidth(), height(), st::layerBG->b); + p.fillRect(App::main()->dlgsWidth() - st::dlgShadow, 0, width() + st::dlgShadow - App::main()->dlgsWidth(), height(), st::layerBg->b); } void TitleHider::mousePressEvent(QMouseEvent *e) { diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index e76739576..7e291c721 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -34,6 +34,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "settingswidget.h" #include "boxes/confirmbox.h" #include "boxes/contactsbox.h" +#include "boxes/addcontactbox.h" #include "mediaview.h" #include "localstorage.h" @@ -357,7 +358,7 @@ NotifyWindow::~NotifyWindow() { } Window::Window(QWidget *parent) : PsMainWindow(parent), _serviceHistoryRequest(0), title(0), -_passcode(0), intro(0), main(0), settings(0), layerBG(0), _isActive(false), _topWidget(0), +_passcode(0), intro(0), main(0), settings(0), layerBg(0), _isActive(false), _connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _shouldLockAt(0), _mediaView(0) { icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); @@ -389,7 +390,6 @@ _connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _shoul connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); - connect(this, SIGNAL(imageLoaded()), this, SLOT(update())); connect(this, SIGNAL(imageLoaded()), this, SLOT(notifyUpdateAllPhotos())); setAttribute(Qt::WA_NoSystemBackground); @@ -776,17 +776,17 @@ void Window::showDocument(DocumentData *doc, HistoryItem *item) { void Window::showLayer(LayeredWidget *w, bool forceFast) { bool fast = forceFast || layerShown(); hideLayer(true); - layerBG = new BackgroundWidget(this, w); + layerBg = new BackgroundWidget(this, w); if (fast) { - layerBG->showFast(); + layerBg->showFast(); } } void Window::replaceLayer(LayeredWidget *w) { - if (layerBG) { - layerBG->replaceInner(w); + if (layerBg) { + layerBg->replaceInner(w); } else { - layerBG = new BackgroundWidget(this, w); + layerBg = new BackgroundWidget(this, w); } } @@ -815,26 +815,26 @@ void Window::hideConnecting() { } void Window::hideLayer(bool fast) { - if (layerBG) { - layerBG->onClose(); + if (layerBg) { + layerBg->onClose(); if (fast) { - layerBG->hide(); - layerBG->deleteLater(); - layerBG = 0; + layerBg->hide(); + layerBg->deleteLater(); + layerBg = 0; } } hideMediaview(); } bool Window::hideInnerLayer() { - if (layerBG) { - return layerBG->onInnerClose(); + if (layerBg) { + return layerBg->onInnerClose(); } return true; } bool Window::layerShown() { - return !!layerBG || !!_topWidget; + return !!layerBg; } bool Window::historyIsActive() const { @@ -849,11 +849,11 @@ void Window::checkHistoryActivation() { } void Window::layerHidden() { - if (layerBG) { - layerBG->hide(); - layerBG->deleteLater(); + if (layerBg) { + layerBg->hide(); + layerBg->deleteLater(); } - layerBG = 0; + layerBg = 0; hideMediaview(); setInnerFocus(); } @@ -871,13 +871,13 @@ void Window::hideMediaview() { bool Window::contentOverlapped(const QRect &globalRect) { if (main && main->contentOverlapped(globalRect)) return true; - if (layerBG && layerBG->contentOverlapped(globalRect)) return true; + if (layerBg && layerBg->contentOverlapped(globalRect)) return true; return false; } void Window::setInnerFocus() { - if (layerBG && layerBG->canSetFocus()) { - layerBG->setInnerFocus(); + if (layerBg && layerBg->canSetFocus()) { + layerBg->setInnerFocus(); } else if (_passcode) { _passcode->setInnerFocus(); } else if (settings) { @@ -1063,7 +1063,7 @@ void Window::onShowNewChannel() { void Window::onLogout() { if (isHidden()) showFromTray(); - ConfirmBox *box = new ConfirmBox(lang(lng_sure_logout), lang(lng_box_logout), st::attentionBoxButton); + ConfirmBox *box = new ConfirmBox(lang(lng_sure_logout), lang(lng_settings_logout), st::attentionBoxButton); connect(box, SIGNAL(confirmed()), this, SLOT(onLogoutSure())); App::wnd()->showLayer(box); } @@ -1116,34 +1116,23 @@ void Window::noMain(MainWidget *was) { } void Window::noBox(BackgroundWidget *was) { - if (was == layerBG) { - layerBG = 0; + if (was == layerBg) { + layerBg = 0; } } void Window::layerFinishedHide(BackgroundWidget *was) { - if (was == layerBG) { + if (was == layerBg) { QTimer::singleShot(0, this, SLOT(layerHidden())); } } void Window::fixOrder() { title->raise(); - if (layerBG) layerBG->raise(); - if (_topWidget) _topWidget->raise(); + if (layerBg) layerBg->raise(); if (_connecting) _connecting->raise(); } -void Window::topWidget(QWidget *w) { - _topWidget = w; -} - -void Window::noTopWidget(QWidget *w) { - if (_topWidget == w) { - _topWidget = 0; - } -} - void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) { if (reason != QSystemTrayIcon::Context) { QTimer::singleShot(1, this, SLOT(updateTrayMenu())); @@ -1168,7 +1157,7 @@ void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) { } void Window::closeEvent(QCloseEvent *e) { - if (MTP::authedId() && minimizeToTray()) { + if (MTP::authedId() && !App::app()->isSavingSession() && minimizeToTray()) { e->ignore(); } else { App::quit(); @@ -1188,7 +1177,7 @@ void Window::resizeEvent(QResizeEvent *e) { updateWideMode(); } title->setGeometry(0, 0, width(), st::titleHeight); - if (layerBG) layerBG->resize(width(), height()); + if (layerBg) layerBg->resize(width(), height()); if (_connecting) _connecting->setGeometry(0, height() - _connecting->height(), _connecting->width(), _connecting->height()); emit resized(QSize(width(), height() - st::titleHeight)); } @@ -1198,7 +1187,7 @@ void Window::updateWideMode() { if (main) main->updateWideMode(); if (settings) settings->updateWideMode(); if (intro) intro->updateWideMode(); - if (layerBG) layerBG->updateWideMode(); + if (layerBg) layerBg->updateWideMode(); } bool Window::needBackButton() { diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index 0d9195947..aa6a9380c 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -198,9 +198,6 @@ public: void noBox(BackgroundWidget *was); void layerFinishedHide(BackgroundWidget *was); - void topWidget(QWidget *w); - void noTopWidget(QWidget *w); - void fixOrder(); enum TempDirState { @@ -309,12 +306,11 @@ private: IntroWidget *intro; MainWidget *main; SettingsWidget *settings; - BackgroundWidget *layerBG; + BackgroundWidget *layerBg; QTimer _isActiveTimer; bool _isActive; - QWidget *_topWidget; // temp hack for CountrySelect ConnectingWidget *_connecting; Local::ClearManager *_clearManager;