From ed3cd4be24544d3843a6af0af4581d2c8cbb0d47 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Fri, 30 Aug 2024 15:27:11 +1000 Subject: [PATCH 01/48] Removing the non translatable tags --- libsession/src/main/res/values/strings.xml | 1558 ++++++++++---------- 1 file changed, 779 insertions(+), 779 deletions(-) diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index 656a481ff9..9db042567c 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -1,448 +1,448 @@ - Session - About - Accept - Copy Account ID - Account ID Copied - Copy your Account ID then share it with your friends so they can message you. - Enter Account ID - This Account ID is invalid. Please check and try again. - Enter Account ID or ONS - Invite Account ID or ONS - Hey, I\'ve been using {app_name} to chat with complete privacy and security. Come join me! My Account ID is\n\n{account_id}\n\nDownload it at {session_download_url} - Your Account ID - This is your Account ID. Other users can scan it to start a conversation with you. - Actual Size - Add - Admins cannot be removed. - {name} and {count} others were promoted to Admin. - Promote Admins - Are you sure you want to promote {name} to admin? Admins cannot be removed. - Are you sure you want to promote {name} and {count} others to admin? Admins cannot be removed. - Promote to Admin - Are you sure you want to promote {name} and {other_name} to admin? Admins cannot be removed. - {name} was promoted to Admin. - Admin promotion failed - Failed to promote {name} in {group_name} - Failed to promote {name} and {count} others in {group_name} - Failed to promote {name} and {other_name} in {group_name} - Admin promotion sent - Remove Admins - Remove as Admin - There are no Admins in this Community. - Failed to remove {name} as Admin. - Failed to remove {name} and {count} others as Admin. - Failed to remove {name} and {other_name} as Admin. - {name} was removed as Admin. - {name} and {count} others were removed as Admin. - {name} and {other_name} were removed as Admin. - Sending admin promotion - Admin Settings - {name} and {other_name} were promoted to Admin. - +{count} - Anonymous - Auto dark-mode - Hide Menu Bar - Language - Choose your language setting for {app_name}. {app_name} will restart when you change your language setting. - How are you? - I\'m good thanks, you? - I\'m doing great, thanks. - Primary Color - Themes - Classic Dark - Classic Light - Ocean Dark - Ocean Light - Zoom - Zoom In - Zoom Out - Attachment - Add attachment - Unnamed Album - Auto-download Attachments - Automatically download media and files from this chat. - Would you like to automatically download all files from {conversation_name}? - Auto Download - Clear All Attachments - Are you sure you want to clear all attachments? Messages with attachments will also be deleted. - Click to download {file_type} - Collapse attachment options - Collecting attachments... - Download Attachment - Duration: - Error attaching file - Failed to select attachment - Can\'t find an app to select media. - This file type is not supported. - Unable to send more than 32 image and video files at once. - Unable to open file. - Error sending file - Please send files as separate messages. - Files must be less than 10MB - Cannot attach images and video with other file types. Try sending other files in a separate message. - Attachment expired - File ID: - File Size: - File Type: - You don\'t have any files in this conversation. - Unable to remove metadata from file. - Loading Newer Media... - Loading Newer Files... - Loading Older Media... - Loading Older Files... - {name} on {date_time} - You don\'t have any media in this conversation. - Media saved by {name} - Move and Scale - N/A - {emoji} Attachment - {author}: {emoji} Attachment - Resolution: - Unable to save file. - Send to {name} - Tap to download {file_type} - This Month - This Week - Attachments you save can be accessed by other apps on your device. - Audio - No audio input found - No audio output found - Unable to play audio file. - Unable to record audio. - Authentication Failed - Too many failed authentication attempts. Please try again later. - Authentication could not be accessed. - Authenticate to open {app_name}. - Back - Ban and Delete All - Ban failed - Unban failed - Unban User - User unbanned - Ban User - User banned - Block - Unblock this contact to send a message. - No blocked contacts - Blocked {name} - Are you sure you want to block {name}? Blocked users cannot send you message requests, group invites or call you. - Unblock - Are you sure you want to unblock {name}? - Are you sure you want to unblock {name} and {count} others? - Are you sure you want to unblock {name} and 1 other? - Unblocked {name} - Call - {name} called you - You cannot start a new call. Finish your current call first. - Connecting... - End call - Call Ended - Failed to answer call - Failed to start call - Call in progress - Incoming call from {name} - Incoming call - Missed Call - Missed call from {name} - Voice and Video Calls require notifications to be enabled in your device system settings. - Call Permissions Required - You can enable the \"Voice and Video Calls\" permission in Privacy Settings. - Reconnecting… - Ringing... - {app_name} Call - Calls (Beta) - Voice and Video Calls - Voice and Video Calls (Beta) - Your IP is visible to your call partner and an Oxen Foundation server while using beta calls. - Enables voice and video calls to and from other users - You called {name} - You missed a call from {name} because you haven\'t enabled Voice and Video Calls in Privacy Settings. - No camera found - Camera unavailable. - Grant Camera Access - {app_name} needs camera access to take photos and videos, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Camera\". - {app_name} needs camera access to take photos and videos, or scan QR codes. - {app_name} needs camera access to scan QR codes - Cancel - Failed to change password - Clear - Clear All - Clear All Data - This will permanently delete your messages and contacts. Would you like to clear this device only, or delete your data from the network as well? - Data Not Deleted + Session + About + Accept + Copy Account ID + Account ID Copied + Copy your Account ID then share it with your friends so they can message you. + Enter Account ID + This Account ID is invalid. Please check and try again. + Enter Account ID or ONS + Invite Account ID or ONS + Hey, I\'ve been using {app_name} to chat with complete privacy and security. Come join me! My Account ID is\n\n{account_id}\n\nDownload it at {session_download_url} + Your Account ID + This is your Account ID. Other users can scan it to start a conversation with you. + Actual Size + Add + Admins cannot be removed. + {name} and {count} others were promoted to Admin. + Promote Admins + Are you sure you want to promote {name} to admin? Admins cannot be removed. + Are you sure you want to promote {name} and {count} others to admin? Admins cannot be removed. + Promote to Admin + Are you sure you want to promote {name} and {other_name} to admin? Admins cannot be removed. + {name} was promoted to Admin. + Admin promotion failed + Failed to promote {name} in {group_name} + Failed to promote {name} and {count} others in {group_name} + Failed to promote {name} and {other_name} in {group_name} + Admin promotion sent + Remove Admins + Remove as Admin + There are no Admins in this Community. + Failed to remove {name} as Admin. + Failed to remove {name} and {count} others as Admin. + Failed to remove {name} and {other_name} as Admin. + {name} was removed as Admin. + {name} and {count} others were removed as Admin. + {name} and {other_name} were removed as Admin. + Sending admin promotion + Admin Settings + {name} and {other_name} were promoted to Admin. + +{count} + Anonymous + Auto dark-mode + Hide Menu Bar + Language + Choose your language setting for {app_name}. {app_name} will restart when you change your language setting. + How are you? + I\'m good thanks, you? + I\'m doing great, thanks. + Primary Color + Themes + Classic Dark + Classic Light + Ocean Dark + Ocean Light + Zoom + Zoom In + Zoom Out + Attachment + Add attachment + Unnamed Album + Auto-download Attachments + Automatically download media and files from this chat. + Would you like to automatically download all files from {conversation_name}? + Auto Download + Clear All Attachments + Are you sure you want to clear all attachments? Messages with attachments will also be deleted. + Click to download {file_type} + Collapse attachment options + Collecting attachments... + Download Attachment + Duration: + Error attaching file + Failed to select attachment + Can\'t find an app to select media. + This file type is not supported. + Unable to send more than 32 image and video files at once. + Unable to open file. + Error sending file + Please send files as separate messages. + Files must be less than 10MB + Cannot attach images and video with other file types. Try sending other files in a separate message. + Attachment expired + File ID: + File Size: + File Type: + You don\'t have any files in this conversation. + Unable to remove metadata from file. + Loading Newer Media... + Loading Newer Files... + Loading Older Media... + Loading Older Files... + {name} on {date_time} + You don\'t have any media in this conversation. + Media saved by {name} + Move and Scale + N/A + {emoji} Attachment + {author}: {emoji} Attachment + Resolution: + Unable to save file. + Send to {name} + Tap to download {file_type} + This Month + This Week + Attachments you save can be accessed by other apps on your device. + Audio + No audio input found + No audio output found + Unable to play audio file. + Unable to record audio. + Authentication Failed + Too many failed authentication attempts. Please try again later. + Authentication could not be accessed. + Authenticate to open {app_name}. + Back + Ban and Delete All + Ban failed + Unban failed + Unban User + User unbanned + Ban User + User banned + Block + Unblock this contact to send a message. + No blocked contacts + Blocked {name} + Are you sure you want to block {name}? Blocked users cannot send you message requests, group invites or call you. + Unblock + Are you sure you want to unblock {name}? + Are you sure you want to unblock {name} and {count} others? + Are you sure you want to unblock {name} and 1 other? + Unblocked {name} + Call + {name} called you + You cannot start a new call. Finish your current call first. + Connecting... + End call + Call Ended + Failed to answer call + Failed to start call + Call in progress + Incoming call from {name} + Incoming call + Missed Call + Missed call from {name} + Voice and Video Calls require notifications to be enabled in your device system settings. + Call Permissions Required + You can enable the \"Voice and Video Calls\" permission in Privacy Settings. + Reconnecting… + Ringing... + {app_name} Call + Calls (Beta) + Voice and Video Calls + Voice and Video Calls (Beta) + Your IP is visible to your call partner and an Oxen Foundation server while using beta calls. + Enables voice and video calls to and from other users + You called {name} + You missed a call from {name} because you haven\'t enabled Voice and Video Calls in Privacy Settings. + No camera found + Camera unavailable. + Grant Camera Access + {app_name} needs camera access to take photos and videos, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Camera\". + {app_name} needs camera access to take photos and videos, or scan QR codes. + {app_name} needs camera access to scan QR codes + Cancel + Failed to change password + Clear + Clear All + Clear All Data + This will permanently delete your messages and contacts. Would you like to clear this device only, or delete your data from the network as well? + Data Not Deleted Data not deleted by %1$d Service Node. Service Node ID: %2$s. Data not deleted by %1$d Service Nodes. Service Node IDs: %2$s. - An unknown error occurred and your data was not deleted. Do you want to delete your data from just this device instead? - Clear Device - Clear device and network - Are you sure you want to delete your data from the network? If you continue, you will not be able to restore your messages or contacts. - Are you sure you want to clear your device? - Clear device only - Clear All Messages - Are you sure you want to clear all messages from your conversation with {name} from your device? - Are you sure you want to clear all {community_name} messages from your device? - Clear for everyone - Clear for me - Are you sure you want to clear all {group_name} messages? - Are you sure you want to clear all {group_name} messages from your device? - Are you sure you want to clear all Note to Self messages from your device? - Close - Close Window - This will ban the selected user from this Community. Are you sure you want to continue? - This will ban the selected user from this Community and delete all their messages. Are you sure you want to continue? - Enter Community URL - Invalid URL - Please check the Community URL and try again. - Community Error - Oops, an error occurred. Please try again later. - Community Invitation - Join Community - Are you sure you want to join {community_name}? - Failed to join community - Or join one of these... - Joined Community - You are already a member of this community. - Leave Community - Failed to leave {community_name} - Unknown Community - Community URL - Copy Community URL - Confirm - Contacts - Delete Contact - Are you sure you want to delete {name} from your contacts? New messages from {name} will arrive as a message request. - You don\'t have any contacts yet - Select Contacts - User Details - Camera - Choose an action to start a conversation - Media message - Message composition - Thumbnail of image from quoted message - Create a conversation with a new contact - Add to home screen - Added to home screen - Audio Messages - Autoplay Audio Messages - Autoplay consecutively sent audio messages - Blocked Contacts - Communities - Delete Conversation - Are you sure you want to delete your conversation with {name}? New messages from {name} will start a new conversation. - Conversation deleted - There are no messages in {conversation_name}. - Enter Key - Function of the enter key when typing in a conversation. - SHIFT + ENTER sends a message, ENTER starts a new line - ENTER sends a message, SHIFT + ENTER starts a new line - Groups - Message Trimming - Trim Communities - Delete messages from Community conversations older than 6 months, and where there are over 2,000 messages. - New Conversation - You don\'t have any conversations yet - Send with Enter Key - Tapping the Enter Key will send message instead of starting a new line. - All Media - Spell Check - Enable spell check when typing messages - Start Conversation - Copied - Copy - Create - Cut - A database error occurred.\n\nExport your application logs to share for troubleshooting. If this is unsuccessful, reinstall {app_name} and restore your account.\n\nWarning: This will result in loss of all messages, attachments, and account data older than two weeks. - We\'ve noticed {app_name} is taking a long time to start.\n\nYou can continue to wait, export your device logs to share for troubleshooting, or try restarting {app_name}. - Your app database is incompatible with this version of {app_name}. Reinstall the app and restore your account to generate a new database and continue using {app_name}.\n\nWarning: This will result in the loss of all messages and attachments older than two weeks. - Optimizing Database - Debug Log - Decline - Delete - Some of your devices are using outdated versions. Syncing may be unreliable until they are updated. - Block This User - Block User - Group Settings - Notify for Mentions Only - When enabled, you\'ll only be notified for messages mentioning you. - Message Sound - Permanently delete the messages in this conversation? - Can\'t leave while adding or removing other members. - Legacy - Original version of disappearing messages. - {name} set the disappearing message timer to {time} - Please wait while the group is created... - Failed to Update Group - You don’t have permission to delete others’ messages - + An unknown error occurred and your data was not deleted. Do you want to delete your data from just this device instead? + Clear Device + Clear device and network + Are you sure you want to delete your data from the network? If you continue, you will not be able to restore your messages or contacts. + Are you sure you want to clear your device? + Clear device only + Clear All Messages + Are you sure you want to clear all messages from your conversation with {name} from your device? + Are you sure you want to clear all {community_name} messages from your device? + Clear for everyone + Clear for me + Are you sure you want to clear all {group_name} messages? + Are you sure you want to clear all {group_name} messages from your device? + Are you sure you want to clear all Note to Self messages from your device? + Close + Close Window + This will ban the selected user from this Community. Are you sure you want to continue? + This will ban the selected user from this Community and delete all their messages. Are you sure you want to continue? + Enter Community URL + Invalid URL + Please check the Community URL and try again. + Community Error + Oops, an error occurred. Please try again later. + Community Invitation + Join Community + Are you sure you want to join {community_name}? + Failed to join community + Or join one of these... + Joined Community + You are already a member of this community. + Leave Community + Failed to leave {community_name} + Unknown Community + Community URL + Copy Community URL + Confirm + Contacts + Delete Contact + Are you sure you want to delete {name} from your contacts? New messages from {name} will arrive as a message request. + You don\'t have any contacts yet + Select Contacts + User Details + Camera + Choose an action to start a conversation + Media message + Message composition + Thumbnail of image from quoted message + Create a conversation with a new contact + Add to home screen + Added to home screen + Audio Messages + Autoplay Audio Messages + Autoplay consecutively sent audio messages + Blocked Contacts + Communities + Delete Conversation + Are you sure you want to delete your conversation with {name}? New messages from {name} will start a new conversation. + Conversation deleted + There are no messages in {conversation_name}. + Enter Key + Function of the enter key when typing in a conversation. + SHIFT + ENTER sends a message, ENTER starts a new line + ENTER sends a message, SHIFT + ENTER starts a new line + Groups + Message Trimming + Trim Communities + Delete messages from Community conversations older than 6 months, and where there are over 2,000 messages. + New Conversation + You don\'t have any conversations yet + Send with Enter Key + Tapping the Enter Key will send message instead of starting a new line. + All Media + Spell Check + Enable spell check when typing messages + Start Conversation + Copied + Copy + Create + Cut + A database error occurred.\n\nExport your application logs to share for troubleshooting. If this is unsuccessful, reinstall {app_name} and restore your account.\n\nWarning: This will result in loss of all messages, attachments, and account data older than two weeks. + We\'ve noticed {app_name} is taking a long time to start.\n\nYou can continue to wait, export your device logs to share for troubleshooting, or try restarting {app_name}. + Your app database is incompatible with this version of {app_name}. Reinstall the app and restore your account to generate a new database and continue using {app_name}.\n\nWarning: This will result in the loss of all messages and attachments older than two weeks. + Optimizing Database + Debug Log + Decline + Delete + Some of your devices are using outdated versions. Syncing may be unreliable until they are updated. + Block This User + Block User + Group Settings + Notify for Mentions Only + When enabled, you\'ll only be notified for messages mentioning you. + Message Sound + Permanently delete the messages in this conversation? + Can\'t leave while adding or removing other members. + Legacy + Original version of disappearing messages. + {name} set the disappearing message timer to {time} + Please wait while the group is created... + Failed to Update Group + You don’t have permission to delete others’ messages + Delete Message Delete Messages - Are you sure you want to delete this message? - + Are you sure you want to delete this message? + Message deleted Messages deleted - This message was deleted - This message was deleted on this device - Are you sure you want to delete this message from this device only? - Are you sure you want to delete this message for everyone? - Delete on this device only - Delete on all my devices - Delete for everyone + This message was deleted + This message was deleted on this device + Are you sure you want to delete this message from this device only? + Are you sure you want to delete this message for everyone? + Delete on this device only + Delete on all my devices + Delete for everyone Failed to delete message Failed to delete messages - Are you sure you want to delete these messages? - Are you sure you want to delete these messages from this device only? - Are you sure you want to delete these messages for everyone? - Deleting - Toggle Developer Tools - Start Dictation... - Disappearing Messages - Message will delete in {time_large} - Auto-deletes in {time_large} - Message will delete in {time_large} {time_small} - Auto-deletes in {time_large} {time_small} - Delete Type - This setting applies to everyone in this conversation. - This setting applies to messages you send in this conversation. - Disappear After {disappearing_messages_type} - {time} - Disappear After Read - Messages delete after they have been read. - Disappear After Send - Messages delete after they have been sent. - Follow Setting - Messages you send will no longer disappear. Are you sure you want to turn off disappearing messages? - Set your messages to disappear {time} after they have been {disappearing_messages_type}? - {name} is using an outdated client. Disappearing messages may not work as expected. - Only group admins can change this setting. - Sent - {name} has set messages to disappear {time} after they have been {disappearing_messages_type}. - You set messages to disappear {time} after they have been {disappearing_messages_type}. - Timer - {name} has turned disappearing messages off. Messages they send will no longer disappear. - {name} has turned disappearing messages off. - You turned off disappearing messages. Messages you send will no longer disappear. - read - sent - {admin_name} updated disappearing message settings. - You updated disappearing message settings. - Dismiss - It can be your real name, an alias, or anything else you like — and you can change it at any time. - Enter your display name - Please enter a display name - Please enter a shorter display name - We were unable to load your display name. Please enter a new display name to continue. - Pick a new display name - Pick your display name - Set Display Name - Document - Done - Download - Downloading... - Draft - Edit - Emoji and Symbols - Activities - Animals and Nature - Flags - Food and Drink - Objects - Recently Used - Smileys and People - Symbols - Travel and Places - Are you sure you want to clear all {emoji}? - Slow down! You\'ve sent too many emoji reacts. Try again soon + Are you sure you want to delete these messages? + Are you sure you want to delete these messages from this device only? + Are you sure you want to delete these messages for everyone? + Deleting + Toggle Developer Tools + Start Dictation... + Disappearing Messages + Message will delete in {time_large} + Auto-deletes in {time_large} + Message will delete in {time_large} {time_small} + Auto-deletes in {time_large} {time_small} + Delete Type + This setting applies to everyone in this conversation. + This setting applies to messages you send in this conversation. + Disappear After {disappearing_messages_type} - {time} + Disappear After Read + Messages delete after they have been read. + Disappear After Send + Messages delete after they have been sent. + Follow Setting + Messages you send will no longer disappear. Are you sure you want to turn off disappearing messages? + Set your messages to disappear {time} after they have been {disappearing_messages_type}? + {name} is using an outdated client. Disappearing messages may not work as expected. + Only group admins can change this setting. + Sent + {name} has set messages to disappear {time} after they have been {disappearing_messages_type}. + You set messages to disappear {time} after they have been {disappearing_messages_type}. + Timer + {name} has turned disappearing messages off. Messages they send will no longer disappear. + {name} has turned disappearing messages off. + You turned off disappearing messages. Messages you send will no longer disappear. + read + sent + {admin_name} updated disappearing message settings. + You updated disappearing message settings. + Dismiss + It can be your real name, an alias, or anything else you like — and you can change it at any time. + Enter your display name + Please enter a display name + Please enter a shorter display name + We were unable to load your display name. Please enter a new display name to continue. + Pick a new display name + Pick your display name + Set Display Name + Document + Done + Download + Downloading... + Draft + Edit + Emoji and Symbols + Activities + Animals and Nature + Flags + Food and Drink + Objects + Recently Used + Smileys and People + Symbols + Travel and Places + Are you sure you want to clear all {emoji}? + Slow down! You\'ve sent too many emoji reacts. Try again soon And %1$d other has reacted %2$s to this message. And %1$d others have reacted %2$s to this message. - Reacted to your message {emoji} - Enable - Please check your internet connection and try again. - Copy Error and Quit - Database Error - An unknown error occurred. - Failures - File - Files - Follow system settings - From: - Toggle Full Screen - Giphy - {app_name} will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs. - Groups have a maximum of 100 members - Create Group - Please pick at least one other group member. - Delete Group - Are you sure you want to delete {group_name}? This will remove all members and delete all group content. - Enter a group description - Group display picture updated. - Edit Group - Group Error - Failed to create group. Please check your internet connection and try again. - Failed to join {group_name} - Set Group Information - Are you sure you want to delete this group invite? - Invite failed - Failed to invite {name} and {count} others to {group_name} - Failed to invite {name} and {other_name} to {group_name} - Failed to invite {name} to {group_name} - Sending invite - Invite sent - Group invite successful - Users must have the latest release to receive invitations - You were invited to join the group. - You and {count} others were invited to join the group. - You and {other_name} were invited to join the group. - Leave Group - Are you sure you want to leave {group_name}? - Are you sure you want to leave {group_name}? This will deactivate the group for all members. - Failed to leave {group_name} - Groups have been upgraded, create a new group to upgrade. Old group functionality will be degraded from {date}. - {name} left the group. - {name} and {count} others left the group. - {name} and {other_name} left the group. - {name} and {count} others joined the group. - {name} joined the group. - {name} was invited to join the group. Chat history was shared. - {name} and {count} others were invited to join the group. Chat history was shared. - {name} and {other_name} were invited to join the group. Chat history was shared. - {name} and {count} others joined the group. - {name} and {other_name} were invited to join the group. - {name} was invited to join the group. Chat history was shared. - You and {count} others were invited to join the group. Chat history was shared. - You and {name} were invited to join the group. Chat history was shared. - You and {count} others were invited to join the group. - You and {name} were invited to join the group. - You and {count} others joined the group. - You and {other_name} joined the group. - {name} and {other_name} joined the group. - You left the group. - You joined the group. - Group Members - There are no other members in this group. - Group Name - Enter a group name - Please enter a group name. - Please enter a shorter group name. - Group name is now {group_name}. - Group name updated. - You have no messages from {group_name}. Send a message to start the conversation! - You are the only admin in {group_name}.\n\nGroup members and settings cannot be changed without an admin. - You were promoted to Admin. - You and {count} others were promoted to Admin. - You and {name} were promoted to Admin. - Would you like to remove {name} from {group_name}? - Would you like to remove {name} and {other_name} from {group_name}? - Remove user and their messages - Would you like to remove {name} and {count} others from {group_name}? + Reacted to your message {emoji} + Enable + Please check your internet connection and try again. + Copy Error and Quit + Database Error + An unknown error occurred. + Failures + File + Files + Follow system settings + From: + Toggle Full Screen + Giphy + {app_name} will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs. + Groups have a maximum of 100 members + Create Group + Please pick at least one other group member. + Delete Group + Are you sure you want to delete {group_name}? This will remove all members and delete all group content. + Enter a group description + Group display picture updated. + Edit Group + Group Error + Failed to create group. Please check your internet connection and try again. + Failed to join {group_name} + Set Group Information + Are you sure you want to delete this group invite? + Invite failed + Failed to invite {name} and {count} others to {group_name} + Failed to invite {name} and {other_name} to {group_name} + Failed to invite {name} to {group_name} + Sending invite + Invite sent + Group invite successful + Users must have the latest release to receive invitations + You were invited to join the group. + You and {count} others were invited to join the group. + You and {other_name} were invited to join the group. + Leave Group + Are you sure you want to leave {group_name}? + Are you sure you want to leave {group_name}? This will deactivate the group for all members. + Failed to leave {group_name} + Groups have been upgraded, create a new group to upgrade. Old group functionality will be degraded from {date}. + {name} left the group. + {name} and {count} others left the group. + {name} and {other_name} left the group. + {name} and {count} others joined the group. + {name} joined the group. + {name} was invited to join the group. Chat history was shared. + {name} and {count} others were invited to join the group. Chat history was shared. + {name} and {other_name} were invited to join the group. Chat history was shared. + {name} and {count} others joined the group. + {name} and {other_name} were invited to join the group. + {name} was invited to join the group. Chat history was shared. + You and {count} others were invited to join the group. Chat history was shared. + You and {name} were invited to join the group. Chat history was shared. + You and {count} others were invited to join the group. + You and {name} were invited to join the group. + You and {count} others joined the group. + You and {other_name} joined the group. + {name} and {other_name} joined the group. + You left the group. + You joined the group. + Group Members + There are no other members in this group. + Group Name + Enter a group name + Please enter a group name. + Please enter a shorter group name. + Group name is now {group_name}. + Group name updated. + You have no messages from {group_name}. Send a message to start the conversation! + You are the only admin in {group_name}.\n\nGroup members and settings cannot be changed without an admin. + You were promoted to Admin. + You and {count} others were promoted to Admin. + You and {name} were promoted to Admin. + Would you like to remove {name} from {group_name}? + Would you like to remove {name} and {other_name} from {group_name}? + Remove user and their messages + Would you like to remove {name} and {count} others from {group_name}? Remove user and their messages Remove users and their messages @@ -451,376 +451,376 @@ Remove user Remove users - {name} was removed from the group. - {name} and {count} others were removed from the group. - {name} and {other_name} were removed from the group. - You were removed from {group_name}. - You and {count} others were removed from the group. - You and {other_name} were removed from the group. - Set Group Display Picture - Unknown Group - Group updated - FAQ - Help us translate {app_name} - Report a bug - Share some details to help us resolve your issue. Export your logs, then upload the file through {app_name}\'s Help Desk. - Export Logs - Export your logs, then upload the file through {app_name}\'s Help Desk. - Save to desktop - Save this file to your desktop, then share it with {app_name} developers. - Support - We\'d love your feedback - Hide - Toggle system menu bar visibility - Hide Others - Image - Incognito Keyboard - Request incognito mode if available. Depending on the keyboard you are using, your keyboard may ignore this request. - Info - Invalid shortcut - Join - Later - Learn More - Leave - Leaving... - {name} joined the group. - {name} and {count} others joined the group. - You and {count} others joined the group. - You and {other_name} joined the group. - {name} and {other_name} joined the group. - You joined the group. - Link Previews - Show link previews for supported URLs. - Enable Link Previews - Unable to load link preview - Preview not loaded for unsecure link - Display previews for URLs you send and receive. This can be useful, however {app_name} must contact linked websites to generate previews. You can always turn off link previews in {app_name}\'s settings. - Send Link Previews - You will not have full metadata protection when sending link previews. - Link Previews Are Off - {app_name} must contact linked websites to generate previews of links you send and receive.\n\nYou can turn them on in {app_name}\'s settings. - Load Account - Loading your account - Loading... - Lock App - Require fingerprint, PIN, pattern or password to unlock {app_name}. - You must enable a passcode in your iOS Settings in order to use Screen Lock. - {app_name} is locked - Quick response unavailable when {app_name} is locked! - Lock status - Tap to unlock - {app_name} is unlocked - Max - Media - + {name} was removed from the group. + {name} and {count} others were removed from the group. + {name} and {other_name} were removed from the group. + You were removed from {group_name}. + You and {count} others were removed from the group. + You and {other_name} were removed from the group. + Set Group Display Picture + Unknown Group + Group updated + FAQ + Help us translate {app_name} + Report a bug + Share some details to help us resolve your issue. Export your logs, then upload the file through {app_name}\'s Help Desk. + Export Logs + Export your logs, then upload the file through {app_name}\'s Help Desk. + Save to desktop + Save this file to your desktop, then share it with {app_name} developers. + Support + We\'d love your feedback + Hide + Toggle system menu bar visibility + Hide Others + Image + Incognito Keyboard + Request incognito mode if available. Depending on the keyboard you are using, your keyboard may ignore this request. + Info + Invalid shortcut + Join + Later + Learn More + Leave + Leaving... + {name} joined the group. + {name} and {count} others joined the group. + You and {count} others joined the group. + You and {other_name} joined the group. + {name} and {other_name} joined the group. + You joined the group. + Link Previews + Show link previews for supported URLs. + Enable Link Previews + Unable to load link preview + Preview not loaded for unsecure link + Display previews for URLs you send and receive. This can be useful, however {app_name} must contact linked websites to generate previews. You can always turn off link previews in {app_name}\'s settings. + Send Link Previews + You will not have full metadata protection when sending link previews. + Link Previews Are Off + {app_name} must contact linked websites to generate previews of links you send and receive.\n\nYou can turn them on in {app_name}\'s settings. + Load Account + Loading your account + Loading... + Lock App + Require fingerprint, PIN, pattern or password to unlock {app_name}. + You must enable a passcode in your iOS Settings in order to use Screen Lock. + {app_name} is locked + Quick response unavailable when {app_name} is locked! + Lock status + Tap to unlock + {app_name} is unlocked + Max + Media + %1$d member %1$d members - + %1$d active member %1$d active members - Add Account ID or ONS - Invite Contacts - + Add Account ID or ONS + Invite Contacts + Send Invite Send Invites - Would you like to share group message history with {name}? - Would you like to share group message history with {name} and {count} others? - Would you like to share group message history with {name} and {other_name}? - Share message history - Share new messages only - Invite - Message - This message is empty. - Message delivery failed - Message limit reached - Received a message encrypted using an old version of {app_name} that is no longer supported. Please ask the sender to update to the most recent version and resend the message. - Original message not found - Message Info - Mark read - Mark unread - + Would you like to share group message history with {name}? + Would you like to share group message history with {name} and {count} others? + Would you like to share group message history with {name} and {other_name}? + Share message history + Share new messages only + Invite + Message + This message is empty. + Message delivery failed + Message limit reached + Received a message encrypted using an old version of {app_name} that is no longer supported. Please ask the sender to update to the most recent version and resend the message. + Original message not found + Message Info + Mark read + Mark unread + New Message New Messages - Start a new conversation by entering your friend\'s Account ID or ONS. - Start a new conversation by entering your friend\'s Account ID, ONS or scanning their QR code. - + Start a new conversation by entering your friend\'s Account ID or ONS. + Start a new conversation by entering your friend\'s Account ID, ONS or scanning their QR code. + You\'ve got a new message. You\'ve got %1$d new messages. - Replying to - {name} invited you to join {group_name}. - Sending a message to this group will automatically accept the group invite. - Your message request is currently pending. - You will be able to send voice messages and attachments once the recipient has approved this message request. - You have accepted the message request from {name}. - Sending a message to this user will automatically accept their message request and reveal your Account ID. - Your message request has been accepted. - Are you sure you want to clear all message and group invites? - Community Message Requests - Allow message requests from Community conversations. - Are you sure you want to delete this message request? - You have a new message request - No pending message requests - {name} has message requests from Community conversations turned off, so you cannot send them a message. - Select Message - {author}: {message_snippet} - Failed to send - Failed to sync - Syncing - Unread messages - Voice Message - Hold to record a voice message - Slide to Cancel - {emoji} Voice Message - {author}: {emoji} Voice Message - Messages - Minimize - Next - Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations. - Enter nickname - Remove nickname - Set Nickname - No - No Suggestions - None - Not now - Note to Self - You have no messages in Note to Self. - Hide Note to Self - Are you sure you want to hide Note to Self? - All Messages - Notification Content - The information shown in notifications. - Name and Content - Name Only - No Name or Content - Fast Mode - You\'ll be notified of new messages reliably and immediately using Google\'s notification Servers. - You\'ll be notified of new messages reliably and immediately using Apple\'s notification Servers. - Go to device notification settings - {name} to {conversation_name} - You may have received messages while your {device} was restarting. - LED color - Mentions Only - Message notifications - Most recent from {name} - Mute - Mute for {time_large} - Unmute - Muted - Slow Mode - {app_name} will occasionally check for new messages in the background. - Sound - Sound when App is open - Audio Notifications - Notification Strategy - Notification Style - {message_count} new messages in {conversation_count} conversations - Vibrate - Off - Okay - On - Create account - Account Created - I have an account - You cannot go back further. In order to cancel your account creation, {app_name} needs to quit. - You cannot go back further. In order to stop loading your account, {app_name} needs to quit. - Creating an account is instant, free, and anonymous {emoji} - You don\'t even need a phone number to sign up. - Privacy in your pocket. - {app_name} is engineered to protect your privacy. - Welcome to {app_name} {emoji} - Hit the plus button to start a chat, create a group, or join an official community! - There are two ways {app_name} can notify you of new messages. - Privacy Policy - Terms of Service - By using this service, you agree to our Terms of Service and Privacy Policy - Path - {app_name} hides your IP by routing your messages through multiple service nodes in {app_name}\'s decentralized network. This is your current path: - Destination - Entry Node - Service Node - Unknown Country - We couldn\'t recognize this ONS. Please check it and try again. - We were unable to search for this ONS. Please try again later. - Open - Other - Change Password - Change the password required to unlock {app_name}. - Your password has been changed. Please keep it safe. - Confirm password - Create your password - Your current password is incorrect. - Require password to unlock {app_name}. - Enter password - Please enter your current password. - Please enter your new password - Password must only contain letters, numbers and symbols - Password must be between 6 and 64 characters long - Passwords do not match - Failed to set password - Incorrect password - Remove Password - Remove the password required to unlock {app_name}. - Your password has been removed. - Set Password - Your password has been set. Please keep it safe. - Paste - {app_name} needs to use Apple Music to play media attachments. - Auto Update - Automatically check for updates on startup - The screen lock feature on {app_name} uses Face ID. - Keep in System Tray - {app_name} continues running in the background when you close the window - {app_name} needs photo library access to continue. You can enable access in the iOS settings. - Microphone - {app_name} needs microphone access to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". - Allow access to microphone - Permission required - {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Files and media\" on. - {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Storage\" on. - {app_name} needs storage access to save attachments and media. - {app_name} needs storage access to save photos and videos, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Storage\". - {app_name} needs storage access to send photos and videos. - Pin - Pin Conversation - Unpin - Unpin Conversation - Preview - Profile - Display Picture - Failed to remove display picture. - Set Display Picture - Please pick a smaller file. - Failed to update profile. - Promote - QR Code - This QR code does not contain an Account ID - This QR code does not contain a Recovery Password - Scan QR Code - View QR - Friends can message you by scanning your QR code. - Quit {app_name} - Quit - Read - Read Receipts - Show read receipts for all messages you send and receive. - Received: - Recommended - Save your recovery password to make sure you don\'t lose access to your account. - Save your recovery password - Use your recovery password to load your account on new devices.\n\nYour account cannot be recovered without your recovery password. Make sure it\'s stored somewhere safe and secure — and don\'t share it with anyone. - Enter your recovery password - An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session\'s Help Desk to help resolve this issue. - Please check your recovery password and try again. - Some of the words in your Recovery Password are incorrect. Please check and try again. - The Recovery Password you entered is not long enough. Please check and try again. - Incorrect Recovery Password - To load your account, enter your recovery password. - Hide Recovery Password Permanently - Without your recovery password, you cannot load your account on new devices.\n\nWe strongly recommend you save your recovery password in a safe and secure place before continuing. - Are you sure you want to permanently hide your recovery password on this device? This cannot be undone. - Hide Recovery Password - Permanently hide your recover password on this device. - Enter your recovery password to load your account. If you haven\'t saved it, you can find it in your app settings. - View Password - This is your recovery password. If you send it to someone they\'ll have full access to your account. - Redo - Remove - Failed to remove password - Reply - Resend - Loading country information... - Restart - Resync - Retry - Save - Saved - Saved messages - Saving... - Scan - Screen Security - Screenshot Notifications - Require a notification when a contact takes a screenshot of a one-to-one chat. - {name} took a screenshot. - Search - Search Contacts - Search Conversation - Please enter your search. - + Replying to + {name} invited you to join {group_name}. + Sending a message to this group will automatically accept the group invite. + Your message request is currently pending. + You will be able to send voice messages and attachments once the recipient has approved this message request. + You have accepted the message request from {name}. + Sending a message to this user will automatically accept their message request and reveal your Account ID. + Your message request has been accepted. + Are you sure you want to clear all message and group invites? + Community Message Requests + Allow message requests from Community conversations. + Are you sure you want to delete this message request? + You have a new message request + No pending message requests + {name} has message requests from Community conversations turned off, so you cannot send them a message. + Select Message + {author}: {message_snippet} + Failed to send + Failed to sync + Syncing + Unread messages + Voice Message + Hold to record a voice message + Slide to Cancel + {emoji} Voice Message + {author}: {emoji} Voice Message + Messages + Minimize + Next + Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations. + Enter nickname + Remove nickname + Set Nickname + No + No Suggestions + None + Not now + Note to Self + You have no messages in Note to Self. + Hide Note to Self + Are you sure you want to hide Note to Self? + All Messages + Notification Content + The information shown in notifications. + Name and Content + Name Only + No Name or Content + Fast Mode + You\'ll be notified of new messages reliably and immediately using Google\'s notification Servers. + You\'ll be notified of new messages reliably and immediately using Apple\'s notification Servers. + Go to device notification settings + {name} to {conversation_name} + You may have received messages while your {device} was restarting. + LED color + Mentions Only + Message notifications + Most recent from {name} + Mute + Mute for {time_large} + Unmute + Muted + Slow Mode + {app_name} will occasionally check for new messages in the background. + Sound + Sound when App is open + Audio Notifications + Notification Strategy + Notification Style + {message_count} new messages in {conversation_count} conversations + Vibrate + Off + Okay + On + Create account + Account Created + I have an account + You cannot go back further. In order to cancel your account creation, {app_name} needs to quit. + You cannot go back further. In order to stop loading your account, {app_name} needs to quit. + Creating an account is instant, free, and anonymous {emoji} + You don\'t even need a phone number to sign up. + Privacy in your pocket. + {app_name} is engineered to protect your privacy. + Welcome to {app_name} {emoji} + Hit the plus button to start a chat, create a group, or join an official community! + There are two ways {app_name} can notify you of new messages. + Privacy Policy + Terms of Service + By using this service, you agree to our Terms of Service and Privacy Policy + Path + {app_name} hides your IP by routing your messages through multiple service nodes in {app_name}\'s decentralized network. This is your current path: + Destination + Entry Node + Service Node + Unknown Country + We couldn\'t recognize this ONS. Please check it and try again. + We were unable to search for this ONS. Please try again later. + Open + Other + Change Password + Change the password required to unlock {app_name}. + Your password has been changed. Please keep it safe. + Confirm password + Create your password + Your current password is incorrect. + Require password to unlock {app_name}. + Enter password + Please enter your current password. + Please enter your new password + Password must only contain letters, numbers and symbols + Password must be between 6 and 64 characters long + Passwords do not match + Failed to set password + Incorrect password + Remove Password + Remove the password required to unlock {app_name}. + Your password has been removed. + Set Password + Your password has been set. Please keep it safe. + Paste + {app_name} needs to use Apple Music to play media attachments. + Auto Update + Automatically check for updates on startup + The screen lock feature on {app_name} uses Face ID. + Keep in System Tray + {app_name} continues running in the background when you close the window + {app_name} needs photo library access to continue. You can enable access in the iOS settings. + Microphone + {app_name} needs microphone access to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". + Allow access to microphone + Permission required + {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Files and media\" on. + {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Storage\" on. + {app_name} needs storage access to save attachments and media. + {app_name} needs storage access to save photos and videos, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Storage\". + {app_name} needs storage access to send photos and videos. + Pin + Pin Conversation + Unpin + Unpin Conversation + Preview + Profile + Display Picture + Failed to remove display picture. + Set Display Picture + Please pick a smaller file. + Failed to update profile. + Promote + QR Code + This QR code does not contain an Account ID + This QR code does not contain a Recovery Password + Scan QR Code + View QR + Friends can message you by scanning your QR code. + Quit {app_name} + Quit + Read + Read Receipts + Show read receipts for all messages you send and receive. + Received: + Recommended + Save your recovery password to make sure you don\'t lose access to your account. + Save your recovery password + Use your recovery password to load your account on new devices.\n\nYour account cannot be recovered without your recovery password. Make sure it\'s stored somewhere safe and secure — and don\'t share it with anyone. + Enter your recovery password + An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session\'s Help Desk to help resolve this issue. + Please check your recovery password and try again. + Some of the words in your Recovery Password are incorrect. Please check and try again. + The Recovery Password you entered is not long enough. Please check and try again. + Incorrect Recovery Password + To load your account, enter your recovery password. + Hide Recovery Password Permanently + Without your recovery password, you cannot load your account on new devices.\n\nWe strongly recommend you save your recovery password in a safe and secure place before continuing. + Are you sure you want to permanently hide your recovery password on this device? This cannot be undone. + Hide Recovery Password + Permanently hide your recover password on this device. + Enter your recovery password to load your account. If you haven\'t saved it, you can find it in your app settings. + View Password + This is your recovery password. If you send it to someone they\'ll have full access to your account. + Redo + Remove + Failed to remove password + Reply + Resend + Loading country information... + Restart + Resync + Retry + Save + Saved + Saved messages + Saving... + Scan + Screen Security + Screenshot Notifications + Require a notification when a contact takes a screenshot of a one-to-one chat. + {name} took a screenshot. + Search + Search Contacts + Search Conversation + Please enter your search. + %1$d of %2$d match %1$d of %2$d matches - No results found. - No results found for {query} - Search Members - Searching... - Select - Select All - Send - Sending - Sent: - Appearance - Clear Data - Conversations - Help - Invite a Friend - Message Requests - {token_name_long} ({{token_name_short}) - Notifications - Permissions - Privacy - Recovery Password - Settings - Set - You must restart {app_name} to apply your new settings. - Share - Invite your friend to chat with you on {app_name} by sharing your Account ID with them. - Share with your friends wherever you usually speak with them — then move the conversation here. - There is an issue opening the database. Please restart the app and try again. - Share to {app_Name} - Show - Show All - Show Less - Stickers - Go to Support Page - Continue - Default - Error - Try Again - Typing Indicators - See and share typing indicators - Undo - Unknown - App updates - Update installed, click to restart - Downloading update: {percent_loader}% - Cannot Update - {app_name} failed to update. Please go to {session_download_url} and install the new version manually, then contact our Help Center to let us know about this problem. - A new version of {app_name} is available, tap to update - A new version of {app_name} is available. - Go to Release Notes - {app_name} Update - Version {version} - Uploading - Copy URL - Open URL - This will open in your browser. - Are you sure you want to open this URL in your browser?\n\n{url} - Use Fast Mode - Video - Unable to play video. - View - This can take a few minutes. - One moment please... - Warning - Window - Yes - You + No results found. + No results found for {query} + Search Members + Searching... + Select + Select All + Send + Sending + Sent: + Appearance + Clear Data + Conversations + Help + Invite a Friend + Message Requests + {token_name_long} ({{token_name_short}) + Notifications + Permissions + Privacy + Recovery Password + Settings + Set + You must restart {app_name} to apply your new settings. + Share + Invite your friend to chat with you on {app_name} by sharing your Account ID with them. + Share with your friends wherever you usually speak with them — then move the conversation here. + There is an issue opening the database. Please restart the app and try again. + Share to {app_Name} + Show + Show All + Show Less + Stickers + Go to Support Page + Continue + Default + Error + Try Again + Typing Indicators + See and share typing indicators + Undo + Unknown + App updates + Update installed, click to restart + Downloading update: {percent_loader}% + Cannot Update + {app_name} failed to update. Please go to {session_download_url} and install the new version manually, then contact our Help Center to let us know about this problem. + A new version of {app_name} is available, tap to update + A new version of {app_name} is available. + Go to Release Notes + {app_name} Update + Version {version} + Uploading + Copy URL + Open URL + This will open in your browser. + Are you sure you want to open this URL in your browser?\n\n{url} + Use Fast Mode + Video + Unable to play video. + View + This can take a few minutes. + One moment please... + Warning + Window + Yes + You - Legacy + Legacy - Uploading + Uploading \ No newline at end of file From 8b10527125bf7f077491802fa4122ae6373b2f4b Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 2 Sep 2024 15:10:17 +1000 Subject: [PATCH 02/48] Adding text color tertiary to the sheet's theme --- app/src/main/res/layout/reactions_pill.xml | 2 +- app/src/main/res/layout/reactions_pill_large.xml | 2 +- app/src/main/res/values/themes.xml | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/reactions_pill.xml b/app/src/main/res/layout/reactions_pill.xml index 69546d092b..ea5aee108d 100644 --- a/app/src/main/res/layout/reactions_pill.xml +++ b/app/src/main/res/layout/reactions_pill.xml @@ -27,7 +27,7 @@ android:layout_height="wrap_content" android:textSize="11sp" android:fontFamily="sans-serif-medium" - android:textColor="?android:textColorTertiary" + android:textColor="?android:textColorPrimary" android:layout_gravity="center_vertical" tools:text="23" tools:ignore="SpUsage" /> diff --git a/app/src/main/res/layout/reactions_pill_large.xml b/app/src/main/res/layout/reactions_pill_large.xml index 44fbd5aa02..d216f2a6ea 100644 --- a/app/src/main/res/layout/reactions_pill_large.xml +++ b/app/src/main/res/layout/reactions_pill_large.xml @@ -27,7 +27,7 @@ android:layout_height="wrap_content" android:textSize="14sp" android:fontFamily="sans-serif-medium" - android:textColor="?android:textColorTertiary" + android:textColor="?android:textColorPrimary" android:layout_gravity="center_vertical" tools:text="23" tools:ignore="SpUsage" /> diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 6e358115cc..662d811064 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -248,29 +248,33 @@ @color/classic_dark_0 @style/Widget.Session.BottomSheetDialog @color/transparent_black_15 - @color/white + @color/classic_dark_6 ?android:textColorPrimary + @color/classic_dark_5 @@ -476,7 +475,6 @@ ?colorCellBackground @color/classic_light_4 @color/classic_light_2 - @color/classic_dark_4 @color/classic_light_4 @@ -562,7 +560,6 @@ @color/ocean_dark_2 @color/ocean_dark_4 ?colorPrimary - @color/ocean_dark_4 @color/ocean_dark_1 @@ -649,7 +646,6 @@ ?colorCellBackground ?input_bar_button_background_opaque ?input_bar_button_background_opaque_border - ?colorAccent ?colorCellBackground @color/ocean_light_5 ?android:textColorSecondary @@ -732,7 +728,6 @@ @color/classic_dark_2 @color/classic_dark_1 @color/classic_dark_3 - @color/classic_dark_4 @color/classic_dark_2 From 32acd6e029c974e16841b53b2a3ab528d9ac625f Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 2 Sep 2024 16:17:52 +1000 Subject: [PATCH 06/48] Fixing up styling of Prominent buttons and "view_user" to work better on different bg colors --- .../main/res/color/prominent_button_color.xml | 2 +- .../drawable/conversation_view_background.xml | 9 ------- ...inent_outline_button_medium_background.xml | 26 ++++++++++++++----- app/src/main/res/layout/view_user.xml | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) delete mode 100644 app/src/main/res/drawable/conversation_view_background.xml diff --git a/app/src/main/res/color/prominent_button_color.xml b/app/src/main/res/color/prominent_button_color.xml index 39985565d1..911a0c5429 100644 --- a/app/src/main/res/color/prominent_button_color.xml +++ b/app/src/main/res/color/prominent_button_color.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/conversation_view_background.xml b/app/src/main/res/drawable/conversation_view_background.xml deleted file mode 100644 index 50e38698b4..0000000000 --- a/app/src/main/res/drawable/conversation_view_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/prominent_outline_button_medium_background.xml b/app/src/main/res/drawable/prominent_outline_button_medium_background.xml index 4bde2f855c..503b30c158 100644 --- a/app/src/main/res/drawable/prominent_outline_button_medium_background.xml +++ b/app/src/main/res/drawable/prominent_outline_button_medium_background.xml @@ -1,13 +1,27 @@ - - + + - + - + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/view_user.xml b/app/src/main/res/layout/view_user.xml index 826b3fffc9..965efe7780 100644 --- a/app/src/main/res/layout/view_user.xml +++ b/app/src/main/res/layout/view_user.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="64dp" - android:background="@drawable/conversation_view_background" + android:background="?attr/selectableItemBackground" android:contentDescription="@string/AccessibilityId_contact" android:orientation="vertical"> From 28d59f9ec995bb063ef8e5f3d2f6b5c3e734cb3c Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Mon, 2 Sep 2024 17:00:59 +1000 Subject: [PATCH 07/48] Fixing strings --- .../onboarding/OnboardingBackPressAlertDialog.kt | 3 +-- .../main/res/drawable/conversation_view_background.xml | 9 +++++++++ app/src/main/res/layout/fragment_create_group.xml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/conversation_view_background.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/OnboardingBackPressAlertDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/OnboardingBackPressAlertDialog.kt index 2852743df0..017c720dde 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/OnboardingBackPressAlertDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/OnboardingBackPressAlertDialog.kt @@ -21,7 +21,6 @@ fun OnboardingBackPressAlertDialog( quit: () -> Unit ) { val c = LocalContext.current - val quitButtonText = c.getSubbedString(R.string.quit, APP_NAME_KEY to APP_NAME) AlertDialog( onDismissRequest = dismissDialog, @@ -31,7 +30,7 @@ fun OnboardingBackPressAlertDialog( }, buttons = listOf( DialogButtonModel( - text = GetString(quitButtonText), + text = GetString(stringResource(id = R.string.quitButton)), color = LocalColors.current.danger, onClick = quit ), diff --git a/app/src/main/res/drawable/conversation_view_background.xml b/app/src/main/res/drawable/conversation_view_background.xml new file mode 100644 index 0000000000..50e38698b4 --- /dev/null +++ b/app/src/main/res/drawable/conversation_view_background.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_create_group.xml b/app/src/main/res/layout/fragment_create_group.xml index 52ff393639..54f6dc1949 100644 --- a/app/src/main/res/layout/fragment_create_group.xml +++ b/app/src/main/res/layout/fragment_create_group.xml @@ -124,7 +124,7 @@ android:id="@+id/emptyStateMessageTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/conversationsNone" + android:text="@string/contactNone" android:textColor="?android:textColorPrimary" android:textSize="@dimen/medium_font_size" app:layout_constraintBottom_toTopOf="@id/createNewPrivateChatButton" From ea24ff67b3e5cc5b54878a8befbf48e7f18806d9 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Tue, 3 Sep 2024 10:49:49 +1000 Subject: [PATCH 08/48] Strings fixes --- .../securesms/conversation/v2/messages/ControlMessageView.kt | 4 +--- .../securesms/conversation/v2/messages/QuoteView.kt | 2 +- .../main/java/org/thoughtcrime/securesms/home/PathActivity.kt | 2 +- .../securesms/recoverypassword/RecoveryPasswordActivity.kt | 2 +- content-descriptions/src/main/res/values/strings.xml | 1 + 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index ab8498acf4..8e3e841809 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -78,9 +78,7 @@ class ControlMessageView : LinearLayout { } message.isMessageRequestResponse -> { binding.textView.text = context.getString(R.string.messageRequestsAccepted) - binding.root.contentDescription = Phrase.from(context, R.string.messageRequestYouHaveAccepted) - .put(NAME_KEY, message.individualRecipient.name) - .format() + binding.root.contentDescription = context.getString(R.string.AccessibilityId_message_request_config_message) } message.isCallLog -> { val drawable = when { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt index 6a5f852409..db6962151c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/QuoteView.kt @@ -106,7 +106,7 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? attachments.audioSlide != null -> { binding.quoteViewAttachmentPreviewImageView.setImageResource(R.drawable.ic_microphone) binding.quoteViewAttachmentPreviewImageView.isVisible = true - binding.quoteViewBodyTextView.text = resources.getString(R.string.audio) + binding.quoteViewBodyTextView.text = resources.getString(R.string.messageVoice) } attachments.documentSlide != null -> { binding.quoteViewAttachmentPreviewImageView.setImageResource(R.drawable.ic_document_large_light) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt index 1530845300..7c115736ab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/PathActivity.kt @@ -114,7 +114,7 @@ class PathActivity : PassphraseRequiredActionBarActivity() { val isGuardSnode = (OnionRequestAPI.guardSnodes.contains(snode)) getPathRow(snode, LineView.Location.Middle, index.toLong() * 1000 + 2000, dotAnimationRepeatInterval, isGuardSnode) } - val youRow = getPathRow(resources.getString(R.string.onionRoutingPath), null, LineView.Location.Top, 1000, dotAnimationRepeatInterval) + val youRow = getPathRow(resources.getString(R.string.you), null, LineView.Location.Top, 1000, dotAnimationRepeatInterval) val destinationRow = getPathRow(resources.getString(R.string.onionRoutingPathDestination), null, LineView.Location.Bottom, path.count().toLong() * 1000 + 2000, dotAnimationRepeatInterval) val rows = listOf( youRow ) + pathRows + listOf( destinationRow ) for (row in rows) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt index 62b602f6f3..543938757c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt @@ -33,7 +33,7 @@ class RecoveryPasswordActivity : BaseActionBarActivity() { private fun onHide() { showSessionDialog { title(R.string.recoveryPasswordHidePermanently) - htmlText(R.string.recoveryPasswordHidePermanentlyDescription1) + text(R.string.recoveryPasswordHidePermanentlyDescription1) dangerButton(R.string.theContinue, R.string.AccessibilityId_theContinue) { onHideConfirm() } cancelButton() } diff --git a/content-descriptions/src/main/res/values/strings.xml b/content-descriptions/src/main/res/values/strings.xml index 25237a222c..2b636e557c 100644 --- a/content-descriptions/src/main/res/values/strings.xml +++ b/content-descriptions/src/main/res/values/strings.xml @@ -124,6 +124,7 @@ Select Voice message Delivered + Message request has been accepted Cancel deletion Delete for everyone From 97db1fe4e63796af897a71fe81f81f8b275eb69b Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Tue, 3 Sep 2024 13:37:36 +1000 Subject: [PATCH 09/48] Reworked preferences Making sure the summary was displaye properly for drop down preferences --- .../preferences/ChatsPreferenceFragment.java | 2 +- .../ListSummaryPreferenceFragment.java | 29 ------ .../NotificationsPreferenceFragment.kt | 99 ++++++++++--------- .../PrivacySettingsPreferenceFragment.kt | 2 +- .../preferences/widgets/DropDownPreference.kt | 70 +++++++++++++ .../widgets/SignalListPreference.java | 70 ------------- .../preferences/widgets/SignalPreference.java | 60 ----------- ...ry_widget.xml => preference_drop_down.xml} | 13 +-- .../res/xml/preferences_notifications.xml | 8 +- 9 files changed, 134 insertions(+), 219 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/preferences/ListSummaryPreferenceFragment.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/DropDownPreference.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalPreference.java rename app/src/main/res/layout/{preference_right_summary_widget.xml => preference_drop_down.xml} (72%) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java index 25d21bbf6d..2c23188429 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java @@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.permissions.Permissions; import network.loki.messenger.R; -public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment { +public class ChatsPreferenceFragment extends CorrectedPreferenceFragment { private static final String TAG = ChatsPreferenceFragment.class.getSimpleName(); @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/ListSummaryPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/ListSummaryPreferenceFragment.java deleted file mode 100644 index a57c0ad728..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/ListSummaryPreferenceFragment.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.thoughtcrime.securesms.preferences; - - -import androidx.preference.ListPreference; -import androidx.preference.Preference; - -import java.util.Arrays; - -import network.loki.messenger.R; - -public abstract class ListSummaryPreferenceFragment extends CorrectedPreferenceFragment { - - protected class ListSummaryListener implements Preference.OnPreferenceChangeListener { - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - ListPreference listPref = (ListPreference) preference; - int entryIndex = Arrays.asList(listPref.getEntryValues()).indexOf(value); - - listPref.setSummary(entryIndex >= 0 && entryIndex < listPref.getEntries().length - ? listPref.getEntries()[entryIndex] - : getString(R.string.unknown)); - return true; - } - } - - protected void initializeListSummary(ListPreference pref) { - pref.setSummary(pref.getEntry()); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.kt index 5614091473..af282d4972 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.preferences import android.annotation.SuppressLint import android.app.Activity -import android.content.Context import android.content.Intent import android.media.RingtoneManager import android.net.Uri @@ -11,7 +10,6 @@ import android.os.Bundle import android.provider.Settings import android.text.TextUtils import androidx.lifecycle.lifecycleScope -import androidx.preference.ListPreference import androidx.preference.Preference import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers @@ -19,17 +17,19 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import network.loki.messenger.R import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsession.utilities.TextSecurePreferences.Companion.isNotificationsEnabled import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.components.SwitchPreferenceCompat import org.thoughtcrime.securesms.notifications.NotificationChannels import org.thoughtcrime.securesms.notifications.PushRegistry +import org.thoughtcrime.securesms.preferences.widgets.DropDownPreference +import java.util.Arrays import javax.inject.Inject @AndroidEntryPoint -class NotificationsPreferenceFragment : ListSummaryPreferenceFragment() { +class NotificationsPreferenceFragment : CorrectedPreferenceFragment() { @Inject lateinit var pushRegistry: PushRegistry + @Inject lateinit var prefs: TextSecurePreferences @@ -41,22 +41,22 @@ class NotificationsPreferenceFragment : ListSummaryPreferenceFragment() { val fcmPreference: SwitchPreferenceCompat = findPreference(fcmKey)!! fcmPreference.isChecked = prefs.isPushEnabled() fcmPreference.setOnPreferenceChangeListener { _: Preference, newValue: Any -> - prefs.setPushEnabled(newValue as Boolean) - val job = pushRegistry.refresh(true) + prefs.setPushEnabled(newValue as Boolean) + val job = pushRegistry.refresh(true) - fcmPreference.isEnabled = false + fcmPreference.isEnabled = false - lifecycleScope.launch(Dispatchers.IO) { - job.join() + lifecycleScope.launch(Dispatchers.IO) { + job.join() - withContext(Dispatchers.Main) { - fcmPreference.isEnabled = true - } + withContext(Dispatchers.Main) { + fcmPreference.isEnabled = true } - - true } + true + } + prefs.setNotificationRingtone( NotificationChannels.getMessageRingtone(requireContext()).toString() ) @@ -64,8 +64,16 @@ class NotificationsPreferenceFragment : ListSummaryPreferenceFragment() { NotificationChannels.getMessageVibrate(requireContext()) ) - findPreference(TextSecurePreferences.RINGTONE_PREF)!!.onPreferenceChangeListener = RingtoneSummaryListener() - findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)!!.onPreferenceChangeListener = NotificationPrivacyListener() + findPreference(TextSecurePreferences.RINGTONE_PREF)?.apply { + setOnViewReady { updateRingtonePref() } + onPreferenceChangeListener = RingtoneSummaryListener() + } + + findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)?.apply { + setOnViewReady { setDropDownLabel(entry) } + onPreferenceChangeListener = NotificationPrivacyListener() + } + findPreference(TextSecurePreferences.VIBRATE_PREF)!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> NotificationChannels.updateMessageVibrate(requireContext(), newValue as Boolean) @@ -91,28 +99,18 @@ class NotificationsPreferenceFragment : ListSummaryPreferenceFragment() { true } - findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { preference: Preference -> - val listPreference = preference as ListPreference - listPreferenceDialog(requireContext(), listPreference) { - initializeListSummary(findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)) - } - true - } - initializeListSummary(findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF) as ListPreference?) - findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) intent.putExtra( - Settings.EXTRA_CHANNEL_ID, NotificationChannels.getMessagesChannel(requireContext()) + Settings.EXTRA_CHANNEL_ID, + NotificationChannels.getMessagesChannel(requireContext()) ) intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName) startActivity(intent) true } - initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF)) initializeMessageVibrateSummary(findPreference(TextSecurePreferences.VIBRATE_PREF) as SwitchPreferenceCompat?) } @@ -131,54 +129,63 @@ class NotificationsPreferenceFragment : ListSummaryPreferenceFragment() { NotificationChannels.updateMessageRingtone(requireContext(), uri) prefs.setNotificationRingtone(uri.toString()) } - initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF)) + updateRingtonePref() } } private inner class RingtoneSummaryListener : Preference.OnPreferenceChangeListener { override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { + val pref = preference as? DropDownPreference ?: return false val value = newValue as? Uri if (value == null || TextUtils.isEmpty(value.toString())) { - preference.setSummary(R.string.none) + pref.setDropDownLabel(context?.getString(R.string.none)) } else { RingtoneManager.getRingtone(activity, value) ?.getTitle(activity) - ?.let { preference.summary = it } + ?.let { pref.setDropDownLabel(it) } } return true } } - private fun initializeRingtoneSummary(pref: Preference?) { - val listener = pref!!.onPreferenceChangeListener as RingtoneSummaryListener? + private fun updateRingtonePref() { + val pref = findPreference(TextSecurePreferences.RINGTONE_PREF) + val listener: RingtoneSummaryListener = + (pref?.onPreferenceChangeListener) as? RingtoneSummaryListener + ?: return + val uri = prefs.getNotificationRingtone() - listener!!.onPreferenceChange(pref, uri) + listener.onPreferenceChange(pref, uri) } private fun initializeMessageVibrateSummary(pref: SwitchPreferenceCompat?) { pref!!.isChecked = prefs.isNotificationVibrateEnabled() } - private inner class NotificationPrivacyListener : ListSummaryListener() { + private inner class NotificationPrivacyListener : Preference.OnPreferenceChangeListener { @SuppressLint("StaticFieldLeak") override fun onPreferenceChange(preference: Preference, value: Any): Boolean { + // update drop down + val pref = preference as? DropDownPreference ?: return false + val entryIndex = Arrays.asList(*pref.entryValues).indexOf(value) + + pref.setDropDownLabel( + if (entryIndex >= 0 && entryIndex < pref.entries.size + ) pref.entries[entryIndex] + else getString(R.string.unknown) + ) + + // update notification object : AsyncTask() { override fun doInBackground(vararg params: Void?): Void? { - ApplicationContext.getInstance(activity).messageNotifier.updateNotification(activity!!) + ApplicationContext.getInstance(activity).messageNotifier.updateNotification( + activity!! + ) return null } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) - return super.onPreferenceChange(preference, value) + return true } } - - companion object { - @Suppress("unused") - private val TAG = NotificationsPreferenceFragment::class.java.simpleName - fun getSummary(context: Context): CharSequence = when (isNotificationsEnabled(context)) { - true -> R.string.on - false -> R.string.off - }.let(context::getString) - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/PrivacySettingsPreferenceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/PrivacySettingsPreferenceFragment.kt index 361f7b5fd5..a2170e2cf7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/PrivacySettingsPreferenceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/PrivacySettingsPreferenceFragment.kt @@ -25,7 +25,7 @@ import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.areNoti import org.thoughtcrime.securesms.util.IntentUtils @AndroidEntryPoint -class PrivacySettingsPreferenceFragment : ListSummaryPreferenceFragment() { +class PrivacySettingsPreferenceFragment : CorrectedPreferenceFragment() { @Inject lateinit var configFactory: ConfigFactory diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/DropDownPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/DropDownPreference.kt new file mode 100644 index 0000000000..73eeb7d194 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/DropDownPreference.kt @@ -0,0 +1,70 @@ +package org.thoughtcrime.securesms.preferences.widgets + +import android.content.Context +import android.util.AttributeSet +import android.widget.TextView +import androidx.preference.ListPreference +import androidx.preference.PreferenceViewHolder +import network.loki.messenger.R + +class DropDownPreference : ListPreference { + private var dropDownLabel: TextView? = null + private var clickListener: OnPreferenceClickListener? = null + private var onViewReady: (()->Unit)? = null + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super( + context!!, attrs, defStyleAttr, defStyleRes + ) { + initialize() + } + + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context!!, attrs, defStyleAttr + ) { + initialize() + } + + constructor(context: Context?, attrs: AttributeSet?) : super( + context!!, attrs + ) { + initialize() + } + + constructor(context: Context?) : super(context!!) { + initialize() + } + + private fun initialize() { + widgetLayoutResource = R.layout.preference_drop_down + } + + override fun onBindViewHolder(view: PreferenceViewHolder) { + super.onBindViewHolder(view) + this.dropDownLabel = view.findViewById(R.id.drop_down_label) as TextView + + onViewReady?.invoke() + } + + override fun setOnPreferenceClickListener(onPreferenceClickListener: OnPreferenceClickListener?) { + this.clickListener = onPreferenceClickListener + } + + fun setOnViewReady(init: (()->Unit)){ + this.onViewReady = init + } + + override fun onClick() { + if (clickListener == null || !clickListener!!.onPreferenceClick(this)) { + super.onClick() + } + } + + fun setDropDownLabel(label: CharSequence?){ + dropDownLabel?.text = label + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java deleted file mode 100644 index 1c483a43e7..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.thoughtcrime.securesms.preferences.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.TextView; -import androidx.preference.ListPreference; -import androidx.preference.PreferenceViewHolder; -import network.loki.messenger.R; - -public class SignalListPreference extends ListPreference { - - private TextView rightSummary; - private CharSequence summary; - private OnPreferenceClickListener clickListener; - - public SignalListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - initialize(); - } - - public SignalListPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initialize(); - } - - public SignalListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public SignalListPreference(Context context) { - super(context); - initialize(); - } - - private void initialize() { - setWidgetLayoutResource(R.layout.preference_right_summary_widget); - } - - @Override - public void onBindViewHolder(PreferenceViewHolder view) { - super.onBindViewHolder(view); - - this.rightSummary = (TextView)view.findViewById(R.id.right_summary); - setSummary(this.summary); - } - - @Override - public void setSummary(CharSequence summary) { - super.setSummary(null); - - this.summary = summary; - - if (this.rightSummary != null) { - this.rightSummary.setText(summary); - } - } - - @Override - public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) { - this.clickListener = onPreferenceClickListener; - } - - @Override - protected void onClick() { - if (clickListener == null || !clickListener.onPreferenceClick(this)) { - super.onClick(); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalPreference.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalPreference.java deleted file mode 100644 index 90635d6d5b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/SignalPreference.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.thoughtcrime.securesms.preferences.widgets; - - -import android.content.Context; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; -import android.util.AttributeSet; -import android.widget.TextView; - -import network.loki.messenger.R; - -public class SignalPreference extends Preference { - - private TextView rightSummary; - private CharSequence summary; - - public SignalPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - initialize(); - } - - public SignalPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initialize(); - } - - public SignalPreference(Context context, AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public SignalPreference(Context context) { - super(context); - initialize(); - } - - private void initialize() { - setWidgetLayoutResource(R.layout.preference_right_summary_widget); - } - - @Override - public void onBindViewHolder(PreferenceViewHolder view) { - super.onBindViewHolder(view); - - this.rightSummary = (TextView)view.findViewById(R.id.right_summary); - setSummary(this.summary); - } - - @Override - public void setSummary(CharSequence summary) { - super.setSummary(null); - - this.summary = summary; - - if (this.rightSummary != null) { - this.rightSummary.setText(summary); - } - } - -} diff --git a/app/src/main/res/layout/preference_right_summary_widget.xml b/app/src/main/res/layout/preference_drop_down.xml similarity index 72% rename from app/src/main/res/layout/preference_right_summary_widget.xml rename to app/src/main/res/layout/preference_drop_down.xml index b8471a9e3d..4ec450bc8b 100644 --- a/app/src/main/res/layout/preference_right_summary_widget.xml +++ b/app/src/main/res/layout/preference_drop_down.xml @@ -2,11 +2,12 @@ + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - - - Date: Tue, 3 Sep 2024 13:57:23 +1000 Subject: [PATCH 10/48] Updated the fake message in appearance --- .../main/res/drawable/quote_accent_line.xml | 6 --- .../layout/activity_appearance_settings.xml | 45 +++++++++++++++---- 2 files changed, 37 insertions(+), 14 deletions(-) delete mode 100644 app/src/main/res/drawable/quote_accent_line.xml diff --git a/app/src/main/res/drawable/quote_accent_line.xml b/app/src/main/res/drawable/quote_accent_line.xml deleted file mode 100644 index 5693f4991b..0000000000 --- a/app/src/main/res/drawable/quote_accent_line.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_appearance_settings.xml b/app/src/main/res/layout/activity_appearance_settings.xml index 140e0be611..b58b3ca5c3 100644 --- a/app/src/main/res/layout/activity_appearance_settings.xml +++ b/app/src/main/res/layout/activity_appearance_settings.xml @@ -209,15 +209,44 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> - + android:layout_height="wrap_content" > + + + + + Date: Tue, 3 Sep 2024 15:42:32 +1000 Subject: [PATCH 11/48] Adding the ability to copy in message details Cleaning up icons --- .../conversation/v2/ConversationActivityV2.kt | 2 ++ .../conversation/v2/MessageDetailActivity.kt | 30 +++++++++++++++++- .../ic_content_copy_white_24dp.png | Bin 233 -> 0 bytes .../ic_content_copy_white_24dp.png | Bin 152 -> 0 bytes .../ic_content_copy_white_24dp.png | Bin 230 -> 0 bytes .../ic_content_copy_white_24dp.png | Bin 354 -> 0 bytes .../ic_content_copy_white_24dp.png | Bin 457 -> 0 bytes .../res/drawable/ic_baseline_file_copy_24.xml | 10 ------ app/src/main/res/drawable/ic_copy.xml | 12 +++++++ .../fragment_conversation_bottom_sheet.xml | 6 ++-- .../menu_conversation_copy_account_id.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- 12 files changed, 48 insertions(+), 16 deletions(-) delete mode 100644 app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png delete mode 100644 app/src/main/res/drawable/ic_baseline_file_copy_24.xml create mode 100644 app/src/main/res/drawable/ic_copy.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 51ca3bf685..c96dc1eb55 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -117,6 +117,7 @@ import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companio import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_DELETE import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND +import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_COPY import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton @@ -2204,6 +2205,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe ON_REPLY -> reply(set) ON_RESEND -> resendMessage(set) ON_DELETE -> deleteMessages(set) + ON_COPY -> copyMessages(set) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt index a830543ec1..0ac008792d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt @@ -95,6 +95,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { const val ON_REPLY = 1 const val ON_RESEND = 2 const val ON_DELETE = 3 + const val ON_COPY = 4 } override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { @@ -126,6 +127,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { onReply = if (state.canReply) { { setResultAndFinish(ON_REPLY) } } else null, onResend = state.error?.let { { setResultAndFinish(ON_RESEND) } }, onDelete = { setResultAndFinish(ON_DELETE) }, + onCopy = { setResultAndFinish(ON_COPY) }, onClickImage = { viewModel.onClickImage(it) }, onAttachmentNeedsDownload = viewModel::onAttachmentNeedsDownload, ) @@ -147,6 +149,7 @@ fun MessageDetails( onReply: (() -> Unit)? = null, onResend: (() -> Unit)? = null, onDelete: () -> Unit = {}, + onCopy: () -> Unit = {}, onClickImage: (Int) -> Unit = {}, onAttachmentNeedsDownload: (DatabaseAttachment) -> Unit = { _ -> } ) { @@ -183,6 +186,7 @@ fun MessageDetails( onReply, onResend, onDelete, + onCopy ) } } @@ -218,7 +222,8 @@ fun CellMetadata( fun CellButtons( onReply: (() -> Unit)? = null, onResend: (() -> Unit)? = null, - onDelete: () -> Unit = {}, + onDelete: () -> Unit, + onCopy: () -> Unit ) { Cell(modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing)) { Column { @@ -230,6 +235,14 @@ fun CellButtons( ) Divider() } + + LargeItemButton( + R.string.copy, + R.drawable.ic_copy, + onClick = onCopy + ) + Divider() + onResend?.let { LargeItemButton( R.string.resend, @@ -238,6 +251,7 @@ fun CellButtons( ) Divider() } + LargeItemButton( R.string.delete, R.drawable.ic_delete, @@ -319,6 +333,20 @@ fun ExpandButton(modifier: Modifier = Modifier, onClick: () -> Unit) { } } +@Preview +@Composable +fun PreviewMessageDetailsButtons( + @PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors +) { + PreviewTheme(colors) { + CellButtons( + onReply = {}, + onResend = {}, + onDelete = {}, + onCopy = {} + ) + } +} @Preview @Composable diff --git a/app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png deleted file mode 100644 index aecd68fb57b9a4aca3795d448c2e95cfdafac7d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBHh8)?hE&{2{_+36{o#Z|H&{{| zE#y0-SF~srP0$sn|LGs=FtPdE-{p1-PB_+27UNQ4GpTf*gFzbf&1sn5M3j*1Dtun4SF6NUey|AMB z#Y=^l-p`E10(v$eDPC*#ztSt*?DTwA=S|?>$+u~tqkEyLp{#37M4MOa%czVK0#~QX c74R@Tw3@m1=MwHLpxYTdUHx3vIVCg!0CSOD3IG5A diff --git a/app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png deleted file mode 100644 index 66a0a250b91891d192b376c6e210cc3e316bd209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj@t!V@Ar-fhfBgS%&#Y@`q%P1A z|4&_3AeYgyZE^}@pp*uu(ynL+zd3uDlIoLm70mtOgt8ee9orVBUug>DcGF$3nUzJf zKgyw;J8oiR%zlMyO!Y>uSSCE&cO=R|l!w9jS;7{T4ZU7Ks~9|8{an^LB{Ts5ZQ3rf diff --git a/app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png deleted file mode 100644 index b0b3718738c74f80b9c88d540ca32465626db34d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtwVp1HAr-gY-a5_IpdiqiIA5*m zw;sP((p&ZBYhtBR+W#6i=l)TU3}~L&s;~Y>^un_*mM7=wTP8%;nCzd#T=iMkQlVB> zAvYjdn3>@L!-pBd-sg6FpTxB1xr>hCI)**ZkAyV~P0(UUQ$3J9dHySAppD3YgK-i+ zSgheb)3ojK@8nX~Fua(;@SeL*b9vzYsTtqB+kZa1zf4>AA78_DtyOCr{x%)6`xgh+ N;_2$=vd$@?2>@bRQLO*~ diff --git a/app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png deleted file mode 100644 index 6f8c7a1dc92733946835b06e8c0e47d3f9ea8baf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2VAS+hc_V9Bsyyc&gRph%=Qgt5} zSIMP2D(|@1rbr#&3``t^35_U)d|w8jePBzW#1_kX^R5kMYYi9NG7m`P(fH2$#7&l6*&_VsA&0xu zb_5>3$8hfBWz)BXNjua}`hGV3>?U!#E$00C&|PV^f7-Ye8p_TJM>eJzU3=5T0t`C_ MPgg&ebxsLQ0JEle%>V!Z diff --git a/app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png deleted file mode 100644 index ff65f6d247d1b32baa93b1cfa8d8c016d2b232f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 457 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>V4UFT;uunK>+M}fzrzLstQX#K zwXX~~&$S}*iw;L&N7!4>7i!0*UE*e0ar~R~%lD5f19MJK+U%*ByClwpk%1wTCt<$v z)0pDCm4CC?9#}q~@oTjjgV*Q%LG!P&95DPE{gCn7%J*FS28=7X3s?ihAFwUZb9lkn zvq6v<=mIEMz}#@{yznXG_#!?_eO<;c74r=A^)CmPG|W3M>{YwYwL-+<{BzFlRxYeJ zmK$cp8LQhcC3ro)Qti_4+JWJD2gCM8hJDIRU$#yBefcBIOtR?@{tOG{ByegM5IS&l z?NmlRX2v;6Ofqat6}=n*>q_RcXVghP)>Cpg$q{~I|Js*l7c-oCZ)<0r_s{*Dnb85+ z#8+>MP4x5smF31~tyz3}PQX8t!nkR - - diff --git a/app/src/main/res/drawable/ic_copy.xml b/app/src/main/res/drawable/ic_copy.xml new file mode 100644 index 0000000000..d1d99d4327 --- /dev/null +++ b/app/src/main/res/drawable/ic_copy.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/fragment_conversation_bottom_sheet.xml b/app/src/main/res/layout/fragment_conversation_bottom_sheet.xml index 7e18e98b52..2170cebd8c 100644 --- a/app/src/main/res/layout/fragment_conversation_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_conversation_bottom_sheet.xml @@ -20,15 +20,15 @@ diff --git a/app/src/main/res/menu/menu_conversation_copy_account_id.xml b/app/src/main/res/menu/menu_conversation_copy_account_id.xml index b788d7a148..3ceed5b16b 100644 --- a/app/src/main/res/menu/menu_conversation_copy_account_id.xml +++ b/app/src/main/res/menu/menu_conversation_copy_account_id.xml @@ -5,6 +5,6 @@ \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 69acb6d381..8b4ee40e70 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -42,7 +42,7 @@ @drawable/ic_baseline_save_24 @drawable/ic_baseline_photo_library_24 @drawable/ic_baseline_delete_24 - @drawable/ic_baseline_file_copy_24 + @drawable/ic_copy @drawable/ic_baseline_reply_24 @drawable/ic_baseline_check_circle_outline_24 @drawable/ic_baseline_select_all_24 From 4d47354e6e170eaf9fa14333cfc25b0b6391666b Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Tue, 3 Sep 2024 16:06:57 +1000 Subject: [PATCH 12/48] Showing 'copy account id' in menu in 1to1 too --- .../conversation/v2/ConversationReactionOverlay.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt index 8fff54833f..f1738fd8c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt @@ -24,9 +24,6 @@ import androidx.core.view.doOnLayout import androidx.vectordrawable.graphics.drawable.AnimatorInflaterCompat import com.squareup.phrase.Phrase import dagger.hilt.android.AndroidEntryPoint -import java.util.Locale -import javax.inject.Inject -import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -52,6 +49,9 @@ import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get import org.thoughtcrime.securesms.repository.ConversationRepository import org.thoughtcrime.securesms.util.AnimationCompleteListener import org.thoughtcrime.securesms.util.DateUtils +import java.util.Locale +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds @AndroidEntryPoint class ConversationReactionOverlay : FrameLayout { @@ -538,7 +538,7 @@ class ConversationReactionOverlay : FrameLayout { items += ActionItem(R.attr.menu_copy_icon, R.string.copy, { handleActionItemClicked(Action.COPY_MESSAGE) }) } // Copy Account ID - if (recipient.isGroupRecipient && !recipient.isCommunityRecipient && message.recipient.address.toString() != userPublicKey) { + if (!recipient.isCommunityRecipient && message.isIncoming) { items += ActionItem(R.attr.menu_copy_icon, R.string.accountIDCopy, { handleActionItemClicked(Action.COPY_ACCOUNT_ID) }) } // Delete message From ffbb7d8a1b5f49c59f57814790d2794524ca5728 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Tue, 3 Sep 2024 16:29:52 +1000 Subject: [PATCH 13/48] Updating files tab in "All media" --- .../org/thoughtcrime/securesms/media/MediaOverviewScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt index e395987e3f..4ce4c90a18 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/media/MediaOverviewScreen.kt @@ -290,5 +290,5 @@ private fun ActionProgressDialog( private val MediaOverviewTab.titleResId: Int get() = when (this) { MediaOverviewTab.Media -> R.string.media - MediaOverviewTab.Documents -> R.string.document + MediaOverviewTab.Documents -> R.string.files } \ No newline at end of file From 2f4c605613e54cefb3c4672ce409e0346f099587 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 10:15:58 +1000 Subject: [PATCH 14/48] Strings updates Latest strings Removed the LEGACY disappearing messages New title for Share activity (also formatted the lines) --- .../thoughtcrime/securesms/ShareActivity.java | 487 +++++++++--------- .../DisappearingMessagesViewModel.kt | 8 +- .../disappearingmessages/State.kt | 20 +- .../disappearingmessages/ui/Adapter.kt | 8 +- .../ui/DisappearingMessages.kt | 19 +- .../ui/DisappearingMessagesPreview.kt | 5 +- .../v2/messages/VisibleMessageView.kt | 2 +- app/src/main/res/layout/share_activity.xml | 6 +- .../DisappearingMessagesViewModelTest.kt | 86 ---- .../src/main/res/values/strings.xml | 4 - .../libsession_util/util/ExpiryMode.kt | 1 - .../utilities/UpdateMessageBuilder.kt | 4 +- libsession/src/main/res/values/strings.xml | 68 ++- 13 files changed, 306 insertions(+), 412 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java index 284a0e929a..3b939bf647 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java @@ -17,6 +17,8 @@ package org.thoughtcrime.securesms; +import static org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY; + import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; @@ -29,14 +31,21 @@ import android.provider.OpenableColumns; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; +import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.Toolbar; + +import com.squareup.phrase.Phrase; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; + import network.loki.messenger.R; + import org.session.libsession.utilities.Address; import org.session.libsession.utilities.DistributionTypes; import org.session.libsession.utilities.ViewUtil; @@ -57,261 +66,261 @@ import org.thoughtcrime.securesms.util.MediaUtil; * @author Jake McGinty */ public class ShareActivity extends PassphraseRequiredActionBarActivity - implements ContactSelectionListFragment.OnContactSelectedListener -{ - private static final String TAG = ShareActivity.class.getSimpleName(); + implements ContactSelectionListFragment.OnContactSelectedListener { + private static final String TAG = ShareActivity.class.getSimpleName(); - public static final String EXTRA_THREAD_ID = "thread_id"; - public static final String EXTRA_ADDRESS_MARSHALLED = "address_marshalled"; - public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type"; + public static final String EXTRA_THREAD_ID = "thread_id"; + public static final String EXTRA_ADDRESS_MARSHALLED = "address_marshalled"; + public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type"; - private ContactSelectionListFragment contactsFragment; - private SearchToolbar searchToolbar; - private ImageView searchAction; - private View progressWheel; - private Uri resolvedExtra; - private CharSequence resolvedPlaintext; - private String mimeType; - private boolean isPassingAlongMedia; + private ContactSelectionListFragment contactsFragment; + private SearchToolbar searchToolbar; + private ImageView searchAction; + private View progressWheel; + private Uri resolvedExtra; + private CharSequence resolvedPlaintext; + private String mimeType; + private boolean isPassingAlongMedia; - @Override - protected void onCreate(Bundle icicle, boolean ready) { - if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) { - getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL); - } - - getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false); - - setContentView(R.layout.share_activity); - - // initializeToolbar(); - initializeResources(); - initializeSearch(); - initializeMedia(); - } - - @Override - protected void onNewIntent(Intent intent) { - Log.i(TAG, "onNewIntent()"); - super.onNewIntent(intent); - setIntent(intent); - initializeMedia(); - } - - @Override - public void onPause() { - super.onPause(); - if (!isPassingAlongMedia && resolvedExtra != null) { - BlobProvider.getInstance().delete(this, resolvedExtra); - - if (!isFinishing()) { - finish(); - } - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - if (searchToolbar.isVisible()) searchToolbar.collapse(); - else super.onBackPressed(); - } - - /* private void initializeToolbar() { - SearchToolbar toolbar = findViewById(R.id.search_toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - }*/ - - private void initializeResources() { - progressWheel = findViewById(R.id.progress_wheel); - searchToolbar = findViewById(R.id.search_toolbar); - searchAction = findViewById(R.id.search_action); - contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment); - contactsFragment.setOnContactSelectedListener(this); - } - - private void initializeSearch() { - searchAction.setOnClickListener(v -> searchToolbar.display(searchAction.getX() + (searchAction.getWidth() / 2), - searchAction.getY() + (searchAction.getHeight() / 2))); - - searchToolbar.setListener(new SearchToolbar.SearchListener() { - @Override - public void onSearchTextChange(String text) { - if (contactsFragment != null) { - contactsFragment.setQueryFilter(text); + @Override + protected void onCreate(Bundle icicle, boolean ready) { + if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) { + getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_ALL); } - } - @Override - public void onSearchClosed() { - if (contactsFragment != null) { - contactsFragment.resetQueryFilter(); - } - } - }); - } + getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false); - private void initializeMedia() { - final Context context = this; - isPassingAlongMedia = false; + setContentView(R.layout.share_activity); - Uri streamExtra = getIntent().getParcelableExtra(Intent.EXTRA_STREAM); - CharSequence charSequenceExtra = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT); - mimeType = getMimeType(streamExtra); - - if (streamExtra != null && PartAuthority.isLocalUri(streamExtra)) { - isPassingAlongMedia = true; - resolvedExtra = streamExtra; - handleResolvedMedia(getIntent(), false); - } else if (charSequenceExtra != null && mimeType != null && mimeType.startsWith("text/")) { - resolvedPlaintext = charSequenceExtra; - handleResolvedMedia(getIntent(), false); - } else { - contactsFragment.getView().setVisibility(View.GONE); - progressWheel.setVisibility(View.VISIBLE); - new ResolveMediaTask(context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, streamExtra); - } - } - - private void handleResolvedMedia(Intent intent, boolean animate) { - long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1); - int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1); - Address address = null; - - if (intent.hasExtra(EXTRA_ADDRESS_MARSHALLED)) { - Parcel parcel = Parcel.obtain(); - byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESS_MARSHALLED); - parcel.unmarshall(marshalled, 0, marshalled.length); - parcel.setDataPosition(0); - address = parcel.readParcelable(getClassLoader()); - parcel.recycle(); - } - - boolean hasResolvedDestination = threadId != -1 && address != null && distributionType != -1; - - if (!hasResolvedDestination && animate) { - ViewUtil.fadeIn(contactsFragment.getView(), 300); - ViewUtil.fadeOut(progressWheel, 300); - } else if (!hasResolvedDestination) { - contactsFragment.getView().setVisibility(View.VISIBLE); - progressWheel.setVisibility(View.GONE); - } else { - createConversation(threadId, address, distributionType); - } - } - - private void createConversation(long threadId, Address address, int distributionType) { - final Intent intent = getBaseShareIntent(ConversationActivityV2.class); - intent.putExtra(ConversationActivityV2.ADDRESS, address); - intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); - - isPassingAlongMedia = true; - startActivity(intent); - } - - private Intent getBaseShareIntent(final @NonNull Class target) { - final Intent intent = new Intent(this, target); - - if (resolvedExtra != null) { - intent.setDataAndType(resolvedExtra, mimeType); - } else if (resolvedPlaintext != null) { - intent.putExtra(Intent.EXTRA_TEXT, resolvedPlaintext); - intent.setType("text/plain"); - } - - return intent; - } - - private String getMimeType(@Nullable Uri uri) { - if (uri != null) { - final String mimeType = MediaUtil.getMimeType(getApplicationContext(), uri); - if (mimeType != null) return mimeType; - } - return MediaUtil.getCorrectedMimeType(getIntent().getType()); - } - - @Override - public void onContactSelected(String number) { - Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true); - long existingThread = DatabaseComponent.get(this).threadDatabase().getThreadIdIfExistsFor(recipient); - createConversation(existingThread, recipient.getAddress(), DistributionTypes.DEFAULT); - } - - @Override - public void onContactDeselected(String number) { - } - - @SuppressLint("StaticFieldLeak") - private class ResolveMediaTask extends AsyncTask { - private final Context context; - - ResolveMediaTask(Context context) { - this.context = context; + initializeToolbar(); + initializeResources(); + initializeSearch(); + initializeMedia(); } @Override - protected Uri doInBackground(Uri... uris) { - try { - if (uris.length != 1 || uris[0] == null) { - return null; - } + protected void onNewIntent(Intent intent) { + Log.i(TAG, "onNewIntent()"); + super.onNewIntent(intent); + setIntent(intent); + initializeMedia(); + } - InputStream inputStream; + @Override + public void onPause() { + super.onPause(); + if (!isPassingAlongMedia && resolvedExtra != null) { + BlobProvider.getInstance().delete(this, resolvedExtra); - if ("file".equals(uris[0].getScheme())) { - inputStream = new FileInputStream(uris[0].getPath()); - } else { - inputStream = context.getContentResolver().openInputStream(uris[0]); - } - - if (inputStream == null) { - return null; - } - - Cursor cursor = getContentResolver().query(uris[0], new String[] {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null); - String fileName = null; - Long fileSize = null; - - try { - if (cursor != null && cursor.moveToFirst()) { - try { - fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)); - fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)); - } catch (IllegalArgumentException e) { - Log.w(TAG, e); + if (!isFinishing()) { + finish(); } - } - } finally { - if (cursor != null) cursor.close(); } - - return BlobProvider.getInstance() - .forData(inputStream, fileSize == null ? 0 : fileSize) - .withMimeType(mimeType) - .withFileName(fileName) - .createForMultipleSessionsOnDisk(context, e -> Log.w(TAG, "Failed to write to disk.", e)); - } catch (IOException ioe) { - Log.w(TAG, ioe); - return null; - } } @Override - protected void onPostExecute(Uri uri) { - resolvedExtra = uri; - handleResolvedMedia(getIntent(), true); + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onBackPressed() { + if (searchToolbar.isVisible()) searchToolbar.collapse(); + else super.onBackPressed(); + } + + private void initializeToolbar() { + TextView tootlbarTitle = findViewById(R.id.title); + tootlbarTitle.setText( + Phrase.from(getApplicationContext(), R.string.shareToSession) + .put(APP_NAME_KEY, getString(R.string.app_name)) + .format().toString() + ); + } + + private void initializeResources() { + progressWheel = findViewById(R.id.progress_wheel); + searchToolbar = findViewById(R.id.search_toolbar); + searchAction = findViewById(R.id.search_action); + contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment); + contactsFragment.setOnContactSelectedListener(this); + } + + private void initializeSearch() { + searchAction.setOnClickListener(v -> searchToolbar.display(searchAction.getX() + (searchAction.getWidth() / 2), + searchAction.getY() + (searchAction.getHeight() / 2))); + + searchToolbar.setListener(new SearchToolbar.SearchListener() { + @Override + public void onSearchTextChange(String text) { + if (contactsFragment != null) { + contactsFragment.setQueryFilter(text); + } + } + + @Override + public void onSearchClosed() { + if (contactsFragment != null) { + contactsFragment.resetQueryFilter(); + } + } + }); + } + + private void initializeMedia() { + final Context context = this; + isPassingAlongMedia = false; + + Uri streamExtra = getIntent().getParcelableExtra(Intent.EXTRA_STREAM); + CharSequence charSequenceExtra = getIntent().getCharSequenceExtra(Intent.EXTRA_TEXT); + mimeType = getMimeType(streamExtra); + + if (streamExtra != null && PartAuthority.isLocalUri(streamExtra)) { + isPassingAlongMedia = true; + resolvedExtra = streamExtra; + handleResolvedMedia(getIntent(), false); + } else if (charSequenceExtra != null && mimeType != null && mimeType.startsWith("text/")) { + resolvedPlaintext = charSequenceExtra; + handleResolvedMedia(getIntent(), false); + } else { + contactsFragment.getView().setVisibility(View.GONE); + progressWheel.setVisibility(View.VISIBLE); + new ResolveMediaTask(context).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, streamExtra); + } + } + + private void handleResolvedMedia(Intent intent, boolean animate) { + long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1); + int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1); + Address address = null; + + if (intent.hasExtra(EXTRA_ADDRESS_MARSHALLED)) { + Parcel parcel = Parcel.obtain(); + byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESS_MARSHALLED); + parcel.unmarshall(marshalled, 0, marshalled.length); + parcel.setDataPosition(0); + address = parcel.readParcelable(getClassLoader()); + parcel.recycle(); + } + + boolean hasResolvedDestination = threadId != -1 && address != null && distributionType != -1; + + if (!hasResolvedDestination && animate) { + ViewUtil.fadeIn(contactsFragment.getView(), 300); + ViewUtil.fadeOut(progressWheel, 300); + } else if (!hasResolvedDestination) { + contactsFragment.getView().setVisibility(View.VISIBLE); + progressWheel.setVisibility(View.GONE); + } else { + createConversation(threadId, address, distributionType); + } + } + + private void createConversation(long threadId, Address address, int distributionType) { + final Intent intent = getBaseShareIntent(ConversationActivityV2.class); + intent.putExtra(ConversationActivityV2.ADDRESS, address); + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); + + isPassingAlongMedia = true; + startActivity(intent); + } + + private Intent getBaseShareIntent(final @NonNull Class target) { + final Intent intent = new Intent(this, target); + + if (resolvedExtra != null) { + intent.setDataAndType(resolvedExtra, mimeType); + } else if (resolvedPlaintext != null) { + intent.putExtra(Intent.EXTRA_TEXT, resolvedPlaintext); + intent.setType("text/plain"); + } + + return intent; + } + + private String getMimeType(@Nullable Uri uri) { + if (uri != null) { + final String mimeType = MediaUtil.getMimeType(getApplicationContext(), uri); + if (mimeType != null) return mimeType; + } + return MediaUtil.getCorrectedMimeType(getIntent().getType()); + } + + @Override + public void onContactSelected(String number) { + Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true); + long existingThread = DatabaseComponent.get(this).threadDatabase().getThreadIdIfExistsFor(recipient); + createConversation(existingThread, recipient.getAddress(), DistributionTypes.DEFAULT); + } + + @Override + public void onContactDeselected(String number) { + } + + @SuppressLint("StaticFieldLeak") + private class ResolveMediaTask extends AsyncTask { + private final Context context; + + ResolveMediaTask(Context context) { + this.context = context; + } + + @Override + protected Uri doInBackground(Uri... uris) { + try { + if (uris.length != 1 || uris[0] == null) { + return null; + } + + InputStream inputStream; + + if ("file".equals(uris[0].getScheme())) { + inputStream = new FileInputStream(uris[0].getPath()); + } else { + inputStream = context.getContentResolver().openInputStream(uris[0]); + } + + if (inputStream == null) { + return null; + } + + Cursor cursor = getContentResolver().query(uris[0], new String[]{OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE}, null, null, null); + String fileName = null; + Long fileSize = null; + + try { + if (cursor != null && cursor.moveToFirst()) { + try { + fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)); + fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE)); + } catch (IllegalArgumentException e) { + Log.w(TAG, e); + } + } + } finally { + if (cursor != null) cursor.close(); + } + + return BlobProvider.getInstance() + .forData(inputStream, fileSize == null ? 0 : fileSize) + .withMimeType(mimeType) + .withFileName(fileName) + .createForMultipleSessionsOnDisk(context, e -> Log.w(TAG, "Failed to write to disk.", e)); + } catch (IOException ioe) { + Log.w(TAG, ioe); + return null; + } + } + + @Override + protected void onPostExecute(Uri uri) { + resolvedExtra = uri; + handleResolvedMedia(getIntent(), true); + } } - } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt index 32e20b73d9..915ff66971 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt @@ -58,7 +58,7 @@ class DisappearingMessagesViewModel( init { viewModelScope.launch { - val expiryMode = storage.getExpirationConfiguration(threadId)?.expiryMode?.maybeConvertToLegacy(isNewConfigEnabled) ?: ExpiryMode.NONE + val expiryMode = storage.getExpirationConfiguration(threadId)?.expiryMode ?: ExpiryMode.NONE val recipient = threadDb.getRecipientForThreadId(threadId) val groupRecord = recipient?.takeIf { it.isClosedGroupRecipient } ?.run { groupDb.getGroup(address.toGroupString()).orNull() } @@ -80,7 +80,7 @@ class DisappearingMessagesViewModel( override fun onSetClick() = viewModelScope.launch { val state = _state.value - val mode = state.expiryMode?.coerceLegacyToAfterSend() + val mode = state.expiryMode val address = state.address if (address == null || mode == null) { _event.send(Event.FAIL) @@ -92,8 +92,6 @@ class DisappearingMessagesViewModel( _event.send(Event.SUCCESS) } - private fun ExpiryMode.coerceLegacyToAfterSend() = takeUnless { it is ExpiryMode.Legacy } ?: ExpiryMode.AfterSend(expirySeconds) - @dagger.assisted.AssistedFactory interface AssistedFactory { fun create(threadId: Long): Factory @@ -125,5 +123,3 @@ class DisappearingMessagesViewModel( ) as T } } - -private fun ExpiryMode.maybeConvertToLegacy(isNewConfigEnabled: Boolean): ExpiryMode = takeIf { isNewConfigEnabled } ?: ExpiryMode.Legacy(expirySeconds) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt index 739d7d6c9f..f7c5a38e9d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt @@ -18,7 +18,7 @@ data class State( val isSelfAdmin: Boolean = true, val address: Address? = null, val isNoteToSelf: Boolean = false, - val expiryMode: ExpiryMode? = null, + val expiryMode: ExpiryMode = ExpiryMode.NONE, val isNewConfigEnabled: Boolean = true, val persistedMode: ExpiryMode? = null, val showDebugOptions: Boolean = false @@ -30,16 +30,10 @@ data class State( val typeOptionsHidden get() = isNoteToSelf || (isGroup && isNewConfigEnabled) - val nextType get() = when { - expiryType == ExpiryType.AFTER_READ -> ExpiryType.AFTER_READ - isNewConfigEnabled -> ExpiryType.AFTER_SEND - else -> ExpiryType.LEGACY - } + val duration get() = expiryMode.duration + val expiryType get() = expiryMode.type - val duration get() = expiryMode?.duration - val expiryType get() = expiryMode?.type - - val isTimeOptionsEnabled = isNoteToSelf || isSelfAdmin && (isNewConfigEnabled || expiryType == ExpiryType.LEGACY) + val isTimeOptionsEnabled = isNoteToSelf || isSelfAdmin && isNewConfigEnabled } @@ -54,11 +48,6 @@ enum class ExpiryType( R.string.off, contentDescription = R.string.AccessibilityId_disappearingMessagesOff, ), - LEGACY( - ExpiryMode::Legacy, - R.string.expiration_type_disappear_legacy, - contentDescription = R.string.AccessibilityId_disappearingMessagesLegacy - ), AFTER_READ( ExpiryMode::AfterRead, R.string.disappearingMessagesDisappearAfterRead, @@ -83,7 +72,6 @@ enum class ExpiryType( } val ExpiryMode.type: ExpiryType get() = when(this) { - is ExpiryMode.Legacy -> ExpiryType.LEGACY is ExpiryMode.AfterSend -> ExpiryType.AFTER_SEND is ExpiryMode.AfterRead -> ExpiryType.AFTER_READ else -> ExpiryType.NONE diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt index dbd40354a2..3900c06bcf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt @@ -23,7 +23,6 @@ fun State.toUiState() = UiState( private fun State.typeOptions(): List? = if (typeOptionsHidden) null else { buildList { add(offTypeOption()) - if (!isNewConfigEnabled) add(legacyTypeOption()) if (!isGroup) add(afterReadTypeOption()) add(afterSendTypeOption()) } @@ -33,7 +32,7 @@ private fun State.timeOptions(): List? { // Don't show times card if we have a types card, and type is off. if (!typeOptionsHidden && expiryType == ExpiryType.NONE) return null - return nextType.let { type -> + return expiryType.let { type -> when (type) { ExpiryType.AFTER_READ -> afterReadTimes else -> afterSendTimes @@ -48,7 +47,6 @@ private fun State.timeOptions(): List? { } private fun State.offTypeOption() = typeOption(ExpiryType.NONE) -private fun State.legacyTypeOption() = typeOption(ExpiryType.LEGACY) private fun State.afterReadTypeOption() = newTypeOption(ExpiryType.AFTER_READ) private fun State.afterSendTypeOption() = newTypeOption(ExpiryType.AFTER_SEND) private fun State.newTypeOption(type: ExpiryType) = typeOption(type, isNewConfigEnabled && isSelfAdmin) @@ -71,7 +69,7 @@ private fun debugModes(isDebug: Boolean, type: ExpiryType) = debugTimes(isDebug).map { type.mode(it.inWholeSeconds) } private fun State.debugOptions(): List = - debugModes(showDebugOptions, nextType).map { timeOption(it, subtitle = GetString("for testing purposes")) } + debugModes(showDebugOptions, expiryType).map { timeOption(it, subtitle = GetString("for testing purposes")) } // Standard list of available disappearing message times private val afterSendTimes = listOf(12.hours, 1.days, 7.days, 14.days) @@ -96,6 +94,6 @@ private fun State.timeOption( title = title, subtitle = subtitle, contentDescription = title, - selected = mode.duration == expiryMode?.duration, + selected = mode.duration == expiryMode.duration, enabled = isTimeOptionsEnabled ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessages.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessages.kt index ace4097c48..b066a96cc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessages.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessages.kt @@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.ui.Callbacks import org.thoughtcrime.securesms.ui.NoOpCallbacks import org.thoughtcrime.securesms.ui.OptionsCard import org.thoughtcrime.securesms.ui.RadioOption +import org.thoughtcrime.securesms.ui.components.PrimaryOutlineButton import org.thoughtcrime.securesms.ui.components.SlimOutlineButton import org.thoughtcrime.securesms.ui.contentDescription import org.thoughtcrime.securesms.ui.fadingEdges @@ -71,13 +72,15 @@ fun DisappearingMessages( } } - if (state.showSetButton) SlimOutlineButton( - stringResource(R.string.set), - modifier = Modifier - .contentDescription(R.string.AccessibilityId_setButton) - .align(Alignment.CenterHorizontally) - .padding(bottom = LocalDimensions.current.spacing), - onClick = callbacks::onSetClick - ) + if (state.showSetButton){ + PrimaryOutlineButton( + stringResource(R.string.set), + modifier = Modifier + .contentDescription(R.string.AccessibilityId_setButton) + .align(Alignment.CenterHorizontally) + .padding(bottom = LocalDimensions.current.spacing), + onClick = callbacks::onSetClick + ) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessagesPreview.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessagesPreview.kt index d043cc314f..48d6539d8a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessagesPreview.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/DisappearingMessagesPreview.kt @@ -27,21 +27,18 @@ fun PreviewStates( } class StatePreviewParameterProvider : PreviewParameterProvider { - override val values = newConfigValues.filter { it.expiryType != ExpiryType.LEGACY } + newConfigValues.map { it.copy(isNewConfigEnabled = false) } + override val values = newConfigValues + newConfigValues.map { it.copy(isNewConfigEnabled = false) } private val newConfigValues get() = sequenceOf( // new 1-1 State(expiryMode = ExpiryMode.NONE), - State(expiryMode = ExpiryMode.Legacy(43200)), State(expiryMode = ExpiryMode.AfterRead(300)), State(expiryMode = ExpiryMode.AfterSend(43200)), // new group non-admin State(isGroup = true, isSelfAdmin = false), - State(isGroup = true, isSelfAdmin = false, expiryMode = ExpiryMode.Legacy(43200)), State(isGroup = true, isSelfAdmin = false, expiryMode = ExpiryMode.AfterSend(43200)), // new group admin State(isGroup = true), - State(isGroup = true, expiryMode = ExpiryMode.Legacy(43200)), State(isGroup = true, expiryMode = ExpiryMode.AfterSend(43200)), // new note-to-self State(isNoteToSelf = true), diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 205f28a078..0fce0036d5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -404,7 +404,7 @@ class VisibleMessageView : FrameLayout { MessageStatusInfo( R.drawable.ic_delivery_status_sending, context.getColorFromAttr(R.attr.message_status_color), - R.string.messageStatusUploading + R.string.uploading ) } message.isSyncing || message.isResyncing -> diff --git a/app/src/main/res/layout/share_activity.xml b/app/src/main/res/layout/share_activity.xml index 4dec894d88..1d7ad6aed9 100644 --- a/app/src/main/res/layout/share_activity.xml +++ b/app/src/main/res/layout/share_activity.xml @@ -21,9 +21,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - Expand Media message - - - Original version of disappearing messages. - \ No newline at end of file diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt index 9761ce5083..9094754564 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/ExpiryMode.kt @@ -4,7 +4,6 @@ import kotlin.time.Duration.Companion.seconds sealed class ExpiryMode(val expirySeconds: Long) { object NONE: ExpiryMode(0) - data class Legacy(private val seconds: Long = 0L): ExpiryMode(seconds) data class AfterSend(private val seconds: Long = 0L): ExpiryMode(seconds) data class AfterRead(private val seconds: Long = 0L): ExpiryMode(seconds) diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index c9f91cf11c..51a07ca65d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -74,14 +74,14 @@ object UpdateMessageBuilder { .format() } 2 -> { - Phrase.from(context, R.string.groupMemberTwoNew) + Phrase.from(context, R.string.groupMemberNewTwo) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(OTHER_NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(1))) .format() } else -> { val newMemberCountMinusOne = newMemberCount - 1 - Phrase.from(context, R.string.groupMemberMoreNew) + Phrase.from(context, R.string.groupMemberNewMultiple) .put(NAME_KEY, getSenderName(updateData.updatedMembers.elementAt(0))) .put(COUNT_KEY, newMemberCountMinusOne) .format() diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index 9db042567c..cacaa32144 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -1,6 +1,7 @@ Session + Notifications - Muted About Accept Copy Account ID @@ -156,7 +157,7 @@ Voice and Video Calls Voice and Video Calls (Beta) Your IP is visible to your call partner and an Oxen Foundation server while using beta calls. - Enables voice and video calls to and from other users + Enables voice and video calls to and from other users. You called {name} You missed a call from {name} because you haven\'t enabled Voice and Video Calls in Privacy Settings. No camera found @@ -192,8 +193,9 @@ Are you sure you want to clear all Note to Self messages from your device? Close Close Window - This will ban the selected user from this Community. Are you sure you want to continue? + Commit Hash: {hash} This will ban the selected user from this Community and delete all their messages. Are you sure you want to continue? + This will ban the selected user from this Community. Are you sure you want to continue? Enter Community URL Invalid URL Please check the Community URL and try again. @@ -228,7 +230,7 @@ Added to home screen Audio Messages Autoplay Audio Messages - Autoplay consecutively sent audio messages + Autoplay consecutively sent audio messages. Blocked Contacts Communities Delete Conversation @@ -249,7 +251,7 @@ Tapping the Enter Key will send message instead of starting a new line. All Media Spell Check - Enable spell check when typing messages + Enable spell check when typing messages. Start Conversation Copied Copy @@ -328,6 +330,7 @@ {name} has turned disappearing messages off. Messages they send will no longer disappear. {name} has turned disappearing messages off. You turned off disappearing messages. Messages you send will no longer disappear. + You turned off disappearing messages. read sent {admin_name} updated disappearing message settings. @@ -363,6 +366,12 @@ And %1$d other has reacted %2$s to this message. And %1$d others have reacted %2$s to this message. + {name} reacted with {emoji_name} + {name} and {other_name} reacted with {emoji_name} + {name} and {count} others reacted with {emoji_name} + You reacted with {emoji_name} + You and {count} others reacted with {emoji_name} + You and {name} reacted with {emoji_name} Reacted to your message {emoji} Enable Please check your internet connection and try again. @@ -375,6 +384,7 @@ Follow system settings From: Toggle Full Screen + GIF Giphy {app_name} will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs. Groups have a maximum of 100 members @@ -409,23 +419,15 @@ {name} left the group. {name} and {count} others left the group. {name} and {other_name} left the group. - {name} and {count} others joined the group. - {name} joined the group. + {name} was invited to join the group. {name} was invited to join the group. Chat history was shared. {name} and {count} others were invited to join the group. Chat history was shared. {name} and {other_name} were invited to join the group. Chat history was shared. - {name} and {count} others joined the group. + {name} and {count} others were invited to join the group. {name} and {other_name} were invited to join the group. - {name} was invited to join the group. Chat history was shared. You and {count} others were invited to join the group. Chat history was shared. You and {name} were invited to join the group. Chat history was shared. - You and {count} others were invited to join the group. - You and {name} were invited to join the group. - You and {count} others joined the group. - You and {other_name} joined the group. - {name} and {other_name} joined the group. You left the group. - You joined the group. Group Members There are no other members in this group. Group Name @@ -440,9 +442,8 @@ You and {count} others were promoted to Admin. You and {name} were promoted to Admin. Would you like to remove {name} from {group_name}? - Would you like to remove {name} and {other_name} from {group_name}? - Remove user and their messages Would you like to remove {name} and {count} others from {group_name}? + Would you like to remove {name} and {other_name} from {group_name}? Remove user and their messages Remove users and their messages @@ -504,6 +505,7 @@ Loading... Lock App Require fingerprint, PIN, pattern or password to unlock {app_name}. + Require Touch ID, Face ID or your passcode to unlock {app_name}. You must enable a passcode in your iOS Settings in order to use Screen Lock. {app_name} is locked Quick response unavailable when {app_name} is locked! @@ -602,6 +604,8 @@ You\'ll be notified of new messages reliably and immediately using Google\'s notification Servers. You\'ll be notified of new messages reliably and immediately using Apple\'s notification Servers. Go to device notification settings + Notifications - All + Notifications - Mentions Only {name} to {conversation_name} You may have received messages while your {device} was restarting. LED color @@ -657,7 +661,7 @@ Your current password is incorrect. Require password to unlock {app_name}. Enter password - Please enter your current password. + Please enter your current password Please enter your new password Password must only contain letters, numbers and symbols Password must be between 6 and 64 characters long @@ -672,14 +676,16 @@ Paste {app_name} needs to use Apple Music to play media attachments. Auto Update - Automatically check for updates on startup + Automatically check for updates on startup. The screen lock feature on {app_name} uses Face ID. Keep in System Tray {app_name} continues running in the background when you close the window {app_name} needs photo library access to continue. You can enable access in the iOS settings. Microphone {app_name} needs microphone access to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". - Allow access to microphone + You can enable microphone access in {app_name}\'s privacy settings + {app_name} needs microphone access to make calls and record audio messages. + Allow access to microphone. Permission required {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Files and media\" on. {app_name} needs storage access so you can send and save attachments. Tap Settings -> Permissions, and turn \"Storage\" on. @@ -722,10 +728,10 @@ Incorrect Recovery Password To load your account, enter your recovery password. Hide Recovery Password Permanently - Without your recovery password, you cannot load your account on new devices.\n\nWe strongly recommend you save your recovery password in a safe and secure place before continuing. + Without your recovery password, you cannot load your account on new devices. \n\nWe strongly recommend you save your recovery password in a safe and secure place before continuing. Are you sure you want to permanently hide your recovery password on this device? This cannot be undone. Hide Recovery Password - Permanently hide your recover password on this device. + Permanently hide your recovery password on this device. Enter your recovery password to load your account. If you haven\'t saved it, you can find it in your app settings. View Password This is your recovery password. If you send it to someone they\'ll have full access to your account. @@ -770,7 +776,6 @@ Help Invite a Friend Message Requests - {token_name_long} ({{token_name_short}) Notifications Permissions Privacy @@ -782,18 +787,19 @@ Invite your friend to chat with you on {app_name} by sharing your Account ID with them. Share with your friends wherever you usually speak with them — then move the conversation here. There is an issue opening the database. Please restart the app and try again. - Share to {app_Name} + Share to {app_name} Show Show All Show Less Stickers Go to Support Page + System Information: {information} Continue Default Error Try Again Typing Indicators - See and share typing indicators + See and share typing indicators. Undo Unknown App updates @@ -821,18 +827,4 @@ Window Yes You - - - Legacy - - - Uploading - \ No newline at end of file From 81f56de11caa5a46c84761abd0b4a2a0e03387f1 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 10:26:30 +1000 Subject: [PATCH 15/48] Latest strings and handling bold --- .../conversation/v2/menus/ConversationMenuHelper.kt | 4 ++-- libsession/src/main/res/values/strings.xml | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 090bf47574..ca43a8decd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -275,11 +275,11 @@ object ConversationMenuHelper { val message = if (isCurrentUserAdmin) { Phrase.from(context, R.string.groupLeaveDescriptionAdmin) .put(GROUP_NAME_KEY, group.title) - .format().toString() + .format() } else { Phrase.from(context, R.string.groupLeaveDescription) .put(GROUP_NAME_KEY, group.title) - .format().toString() + .format() } fun onLeaveFailed() { diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index cacaa32144..e1effe3ee6 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -1,7 +1,6 @@ Session - Notifications - Muted About Accept Copy Account ID @@ -316,8 +315,10 @@ Disappear After {disappearing_messages_type} - {time} Disappear After Read Messages delete after they have been read. + Disappear After Read - {time} Disappear After Send Messages delete after they have been sent. + Disappear After Send - {time} Follow Setting Messages you send will no longer disappear. Are you sure you want to turn off disappearing messages? Set your messages to disappear {time} after they have been {disappearing_messages_type}? @@ -413,7 +414,7 @@ You and {other_name} were invited to join the group. Leave Group Are you sure you want to leave {group_name}? - Are you sure you want to leave {group_name}? This will deactivate the group for all members. + Are you sure you want to leave {group_name}?\n\nThis will remove all members and delete all group content. Failed to leave {group_name} Groups have been upgraded, create a new group to upgrade. Old group functionality will be degraded from {date}. {name} left the group. @@ -582,9 +583,9 @@ Messages Minimize Next - Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations. + Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations. Enter nickname - Remove nickname + Remove Nickname Set Nickname No No Suggestions @@ -606,6 +607,7 @@ Go to device notification settings Notifications - All Notifications - Mentions Only + Notifications - Muted {name} to {conversation_name} You may have received messages while your {device} was restarting. LED color @@ -682,7 +684,7 @@ {app_name} continues running in the background when you close the window {app_name} needs photo library access to continue. You can enable access in the iOS settings. Microphone - {app_name} needs microphone access to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". + {app_name} needs microphone access to send audio messages, but it has been permanently denied. Tap settings -> Permissions, and turn \"Microphone\" on. You can enable microphone access in {app_name}\'s privacy settings {app_name} needs microphone access to make calls and record audio messages. Allow access to microphone. From 86f89f8c61aa5383c7c0bd408e00cf2480ae388a Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 10:56:32 +1000 Subject: [PATCH 16/48] Updated constants file --- .../main/java/org/thoughtcrime/securesms/home/EmptyView.kt | 3 +-- .../thoughtcrime/securesms/onboarding/landing/Landing.kt | 6 ++---- .../thoughtcrime/securesms/preferences/SettingsActivity.kt | 2 +- .../libsession/utilities/NonTranslatableStringConstants.kt | 4 +++- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/EmptyView.kt b/app/src/main/java/org/thoughtcrime/securesms/home/EmptyView.kt index 1457d731d7..2ab5cad673 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/EmptyView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/EmptyView.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import com.squareup.phrase.Phrase import network.loki.messenger.R -import org.session.libsession.utilities.NonTranslatableStringConstants.WAVING_HAND_EMOJI import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY import org.thoughtcrime.securesms.ui.Divider @@ -53,7 +52,7 @@ internal fun EmptyView(newAccount: Boolean) { val c = LocalContext.current Phrase.from(txt) .put(APP_NAME_KEY, c.getString(R.string.app_name)) - .put(EMOJI_KEY, WAVING_HAND_EMOJI) + .put(EMOJI_KEY, "\uD83D\uDC4B") // this hardcoded emoji might be moved to NonTranslatableConstants eventually .format().toString() }, style = LocalType.current.base, diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/landing/Landing.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/landing/Landing.kt index 9a478e6ecc..aab1421185 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/landing/Landing.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/landing/Landing.kt @@ -37,8 +37,6 @@ import androidx.compose.ui.unit.dp import com.squareup.phrase.Phrase import kotlinx.coroutines.delay import network.loki.messenger.R -import org.session.libsession.utilities.NonTranslatableStringConstants.BACKHAND_INDEX_POINTING_DOWN_EMOJI -import org.session.libsession.utilities.NonTranslatableStringConstants.WAVING_HAND_EMOJI import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY import org.thoughtcrime.securesms.ui.AlertDialog @@ -139,7 +137,7 @@ internal fun LandingScreen( R.string.onboardingBubbleWelcomeToSession -> { Phrase.from(stringResource(item.stringId)) .put(APP_NAME_KEY, stringResource(R.string.app_name)) - .put(EMOJI_KEY, WAVING_HAND_EMOJI) + .put(EMOJI_KEY, "\uD83D\uDC4B") // this hardcoded emoji might be moved to NonTranslatableConstants eventually .format().toString() } R.string.onboardingBubbleSessionIsEngineered -> { @@ -149,7 +147,7 @@ internal fun LandingScreen( } R.string.onboardingBubbleCreatingAnAccountIsEasy -> { Phrase.from(stringResource(item.stringId)) - .put(EMOJI_KEY, BACKHAND_INDEX_POINTING_DOWN_EMOJI) + .put(EMOJI_KEY, "\uD83D\uDC47") // this hardcoded emoji might be moved to NonTranslatableConstants eventually .format().toString() } else -> { diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt index bfba7377a7..c6fa5998d0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -523,7 +523,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { Column { // add the debug menu in non release builds if (BuildConfig.BUILD_TYPE != "release") { - LargeItemButton(DEBUG_MENU, R.drawable.ic_settings) { push() } + LargeItemButton("Debug Menu", R.drawable.ic_settings) { push() } Divider() } diff --git a/libsession/src/main/java/org/session/libsession/utilities/NonTranslatableStringConstants.kt b/libsession/src/main/java/org/session/libsession/utilities/NonTranslatableStringConstants.kt index 78691fb1a5..af63265e97 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/NonTranslatableStringConstants.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/NonTranslatableStringConstants.kt @@ -1,10 +1,12 @@ package org.session.libsession.utilities -// Non-translatable strings for UI substitutions + +// Non-translatable strings for use with the UI object NonTranslatableStringConstants { const val APP_NAME = "Session" const val DEBUG_MENU = "Debug Menu" const val GIF = "GIF" + const val SESSION_DOWNLOAD_URL = "https://getsession.org/download" const val WAVING_HAND_EMOJI = "\uD83D\uDC4B" // Used on the landing page & substituted into `onboardingBubbleWelcomeToSession` const val BACKHAND_INDEX_POINTING_DOWN_EMOJI = "\uD83D\uDC47" // Used on the landing page & substituted into `onboardingBubbleCreatingAnAccountIsEasy` } \ No newline at end of file From d7bd0bf3ea2ddf4f658e7d05f7a40cd2cb1e1372 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 14:28:52 +1000 Subject: [PATCH 17/48] Can save media in message details page now --- .../conversation/v2/ConversationActivityV2.kt | 4 ++ .../conversation/v2/MessageDetailActivity.kt | 23 ++++++++-- .../securesms/preferences/SettingsActivity.kt | 6 +-- .../thoughtcrime/securesms/ui/Components.kt | 46 ++++++++++++++----- .../securesms/ui/theme/Dimensions.kt | 1 + .../main/res/menu/media_overview_context.xml | 17 ------- app/src/main/res/menu/media_preview.xml | 4 ++ 7 files changed, 64 insertions(+), 37 deletions(-) delete mode 100644 app/src/main/res/menu/media_overview_context.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index c96dc1eb55..5ec72a7f7e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -118,6 +118,7 @@ import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companio import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_REPLY import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_RESEND import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_COPY +import org.thoughtcrime.securesms.conversation.v2.MessageDetailActivity.Companion.ON_SAVE import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog import org.thoughtcrime.securesms.conversation.v2.dialogs.LinkPreviewDialog import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton @@ -2206,6 +2207,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe ON_RESEND -> resendMessage(set) ON_DELETE -> deleteMessages(set) ON_COPY -> copyMessages(set) + ON_SAVE -> { + if(message is MmsMessageRecord) saveAttachments(message) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt index 0ac008792d..98332b8661 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/MessageDetailActivity.kt @@ -96,6 +96,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { const val ON_RESEND = 2 const val ON_DELETE = 3 const val ON_COPY = 4 + const val ON_SAVE = 5 } override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { @@ -126,6 +127,7 @@ class MessageDetailActivity : PassphraseRequiredActionBarActivity() { state = state, onReply = if (state.canReply) { { setResultAndFinish(ON_REPLY) } } else null, onResend = state.error?.let { { setResultAndFinish(ON_RESEND) } }, + onSave = if(state.mmsRecord != null) { { setResultAndFinish(ON_SAVE) } } else null, onDelete = { setResultAndFinish(ON_DELETE) }, onCopy = { setResultAndFinish(ON_COPY) }, onClickImage = { viewModel.onClickImage(it) }, @@ -148,6 +150,7 @@ fun MessageDetails( state: MessageDetailsState, onReply: (() -> Unit)? = null, onResend: (() -> Unit)? = null, + onSave: (() -> Unit)? = null, onDelete: () -> Unit = {}, onCopy: () -> Unit = {}, onClickImage: (Int) -> Unit = {}, @@ -183,10 +186,11 @@ fun MessageDetails( state.nonImageAttachmentFileDetails?.let { FileDetails(it) } CellMetadata(state) CellButtons( - onReply, - onResend, - onDelete, - onCopy + onReply = onReply, + onResend = onResend, + onSave = onSave, + onDelete = onDelete, + onCopy = onCopy ) } } @@ -222,6 +226,7 @@ fun CellMetadata( fun CellButtons( onReply: (() -> Unit)? = null, onResend: (() -> Unit)? = null, + onSave: (() -> Unit)? = null, onDelete: () -> Unit, onCopy: () -> Unit ) { @@ -243,6 +248,15 @@ fun CellButtons( ) Divider() + onSave?.let { + LargeItemButton( + R.string.save, + R.drawable.ic_baseline_save_24, + onClick = it + ) + Divider() + } + onResend?.let { LargeItemButton( R.string.resend, @@ -342,6 +356,7 @@ fun PreviewMessageDetailsButtons( CellButtons( onReply = {}, onResend = {}, + onSave = {}, onDelete = {}, onCopy = {} ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt index c6fa5998d0..75abce49a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -38,8 +38,6 @@ import com.canhub.cropper.CropImage import com.canhub.cropper.CropImageContract import com.squareup.phrase.Phrase import dagger.hilt.android.AndroidEntryPoint -import java.io.File -import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -60,7 +58,6 @@ import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.snode.OnionRequestAPI import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.Address -import org.session.libsession.utilities.NonTranslatableStringConstants.DEBUG_MENU import org.session.libsession.utilities.ProfileKeyUtil import org.session.libsession.utilities.ProfilePictureUtilities import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol @@ -97,7 +94,8 @@ import org.thoughtcrime.securesms.util.BitmapUtil import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import org.thoughtcrime.securesms.util.NetworkUtils import org.thoughtcrime.securesms.util.push -import org.thoughtcrime.securesms.util.show +import java.io.File +import javax.inject.Inject @AndroidEntryPoint class SettingsActivity : PassphraseRequiredActionBarActivity() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt index baf0c1f122..d04d73fda1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt @@ -11,8 +11,12 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn @@ -45,6 +49,7 @@ import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -126,7 +131,7 @@ fun LargeItemButtonWithDrawable( onClick: () -> Unit ) { ItemButtonWithDrawable( - textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight), + textId, icon, modifier, LocalType.current.h8, colors, onClick ) } @@ -167,8 +172,13 @@ fun LargeItemButton( onClick: () -> Unit ) { ItemButton( - textId, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight), - LocalType.current.h8, colors, onClick + textId = textId, + icon = icon, + modifier = modifier, + minHeight = LocalDimensions.current.minLargeItemButtonHeight, + textStyle = LocalType.current.h8, + colors = colors, + onClick = onClick ) } @@ -181,8 +191,13 @@ fun LargeItemButton( onClick: () -> Unit ) { ItemButton( - text, icon, modifier.heightIn(min = LocalDimensions.current.minLargeItemButtonHeight), - LocalType.current.h8, colors, onClick + text = text, + icon = icon, + modifier = modifier, + minHeight = LocalDimensions.current.minLargeItemButtonHeight, + textStyle = LocalType.current.h8, + colors = colors, + onClick = onClick ) } @@ -191,6 +206,7 @@ fun ItemButton( text: String, icon: Int, modifier: Modifier, + minHeight: Dp = LocalDimensions.current.minItemButtonHeight, textStyle: TextStyle = LocalType.current.xl, colors: ButtonColors = transparentButtonColors(), onClick: () -> Unit @@ -205,6 +221,7 @@ fun ItemButton( modifier = Modifier.align(Alignment.Center) ) }, + minHeight = minHeight, textStyle = textStyle, colors = colors, onClick = onClick @@ -219,6 +236,7 @@ fun ItemButton( @StringRes textId: Int, @DrawableRes icon: Int, modifier: Modifier = Modifier, + minHeight: Dp = LocalDimensions.current.minItemButtonHeight, textStyle: TextStyle = LocalType.current.xl, colors: ButtonColors = transparentButtonColors(), onClick: () -> Unit @@ -233,6 +251,7 @@ fun ItemButton( modifier = Modifier.align(Alignment.Center) ) }, + minHeight = minHeight, textStyle = textStyle, colors = colors, onClick = onClick @@ -249,20 +268,23 @@ fun ItemButton( text: String, icon: @Composable BoxScope.() -> Unit, modifier: Modifier = Modifier, + minHeight: Dp = LocalDimensions.current.minLargeItemButtonHeight, textStyle: TextStyle = LocalType.current.xl, colors: ButtonColors = transparentButtonColors(), onClick: () -> Unit ) { TextButton( - modifier = modifier.fillMaxWidth(), + modifier = modifier.fillMaxWidth() + .height(IntrinsicSize.Min) + .heightIn(min = minHeight) + .padding(horizontal = LocalDimensions.current.xsSpacing), colors = colors, onClick = onClick, shape = RectangleShape, ) { Box( - modifier = Modifier - .width(50.dp) - .wrapContentHeight() + modifier = Modifier.fillMaxHeight() + .aspectRatio(1f) .align(Alignment.CenterVertically) ) { icon() @@ -274,7 +296,6 @@ fun ItemButton( text, Modifier .fillMaxWidth() - .padding(vertical = LocalDimensions.current.xsSpacing) .align(Alignment.CenterVertically), style = textStyle ) @@ -371,7 +392,8 @@ fun Modifier.fadingEdges( @Composable fun Divider(modifier: Modifier = Modifier, startIndent: Dp = 0.dp) { HorizontalDivider( - modifier = modifier.padding(horizontal = LocalDimensions.current.smallSpacing) + modifier = modifier + .padding(horizontal = LocalDimensions.current.smallSpacing) .padding(start = startIndent), color = LocalColors.current.borders, ) @@ -471,4 +493,4 @@ fun LoadingArcOr(loading: Boolean, content: @Composable () -> Unit) { AnimatedVisibility(!loading) { content() } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt index 66e5b74e8b..ac5ce8c4cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/theme/Dimensions.kt @@ -17,6 +17,7 @@ data class Dimensions( val dividerIndent: Dp = 60.dp, val appBarHeight: Dp = 64.dp, + val minItemButtonHeight: Dp = 50.dp, val minLargeItemButtonHeight: Dp = 60.dp, val indicatorHeight: Dp = 4.dp, diff --git a/app/src/main/res/menu/media_overview_context.xml b/app/src/main/res/menu/media_overview_context.xml deleted file mode 100644 index a0ff4ab988..0000000000 --- a/app/src/main/res/menu/media_overview_context.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/menu/media_preview.xml b/app/src/main/res/menu/media_preview.xml index 8689bd4c55..9818143be5 100644 --- a/app/src/main/res/menu/media_preview.xml +++ b/app/src/main/res/menu/media_preview.xml @@ -4,24 +4,28 @@ From bc067b68481e427406f2e9774fa28ec12dad092c Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 14:46:15 +1000 Subject: [PATCH 18/48] Adding padding so that context menu doesn't hit the bottom of the screen --- .../securesms/conversation/v2/ConversationReactionOverlay.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt index f1738fd8c5..ebf1eacfd4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationReactionOverlay.kt @@ -213,7 +213,7 @@ class ConversationReactionOverlay : FrameLayout { endY = backgroundView.height + menuPadding + reactionBarTopPadding } } else { - endY = overlayHeight - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.height + endY = overlayHeight - contextMenu.getMaxHeight() - 2*menuPadding - conversationItemSnapshot.height reactionBarBackgroundY = endY - reactionBarHeight - menuPadding } endApparentTop = endY From 3db8b46be17fa894f9f54c33e9d1dfd98c12594a Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 16:44:05 +1000 Subject: [PATCH 19/48] Strings update --- .../home/ConversationOptionsBottomSheet.kt | 29 ++++++++++++++++++- .../securesms/home/HomeActivity.kt | 14 ++++++--- .../src/main/res/values/strings.xml | 4 ++- .../utilities/UpdateMessageBuilder.kt | 12 ++++++-- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt index 82b9f16dcd..ed7abc7fcd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/ConversationOptionsBottomSheet.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.core.view.isVisible import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint +import network.loki.messenger.R import network.loki.messenger.databinding.FragmentConversationBottomSheetBinding import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.dependencies.ConfigFactory @@ -82,7 +83,33 @@ class ConversationOptionsBottomSheet(private val parentContext: Context) : Botto binding.muteNotificationsTextView.setOnClickListener(this) binding.notificationsTextView.isVisible = recipient.isGroupRecipient && !recipient.isMuted binding.notificationsTextView.setOnClickListener(this) - binding.deleteTextView.setOnClickListener(this) + + // delete + binding.deleteTextView.apply { + setOnClickListener(this@ConversationOptionsBottomSheet) + + // the text and content description will change depending on the type + when{ + // groups and communities + recipient.isGroupRecipient -> { + text = context.getString(R.string.leave) + contentDescription = context.getString(R.string.AccessibilityId_leave) + } + + // note to self + recipient.isLocalNumber -> { + text = context.getString(R.string.clear) + contentDescription = context.getString(R.string.AccessibilityId_clear) + } + + // 1on1 + else -> { + text = context.getString(R.string.delete) + contentDescription = context.getString(R.string.AccessibilityId_delete) + } + } + } + binding.markAllAsReadTextView.isVisible = thread.unreadCount > 0 || configFactory.convoVolatile?.getConversationUnread(thread) == true binding.markAllAsReadTextView.setOnClickListener(this) binding.pinTextView.isVisible = !thread.isPinned diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index 5af7e7be52..69442b512e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -583,16 +583,20 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), val recipient = thread.recipient val title: String val message: CharSequence + var positiveButtonId: Int = R.string.yes + var negativeButtonId: Int = R.string.no if (recipient.isGroupRecipient) { val group = groupDatabase.getGroup(recipient.address.toString()).orNull() // If you are an admin of this group you can delete it if (group != null && group.admins.map { it.toString() }.contains(textSecurePreferences.getLocalNumber())) { - title = getString(R.string.groupDelete) + title = getString(R.string.groupLeave) message = Phrase.from(this.applicationContext, R.string.groupDeleteDescription) .put(GROUP_NAME_KEY, group.title) .format() + positiveButtonId = R.string.leave + negativeButtonId = R.string.cancel } else { // Otherwise this is either a community, or it's a group you're not an admin of title = if (recipient.isCommunityRecipient) getString(R.string.communityLeave) else getString(R.string.groupLeave) @@ -610,15 +614,17 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), } else { // If not group-related and we don't have a recipient name then this must be our Note to Self conversation - title = getString(R.string.noteToSelf) + title = getString(R.string.clearMessages) message = getString(R.string.clearMessagesNoteToSelfDescription) + positiveButtonId = R.string.clear + negativeButtonId = R.string.cancel } } showSessionDialog { title(title) text(message) - button(R.string.yes) { + dangerButton(positiveButtonId) { lifecycleScope.launch(Dispatchers.Main) { val context = this@HomeActivity // Cancel any outstanding jobs @@ -650,7 +656,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show() } } - button(R.string.no) + button(negativeButtonId) } } diff --git a/content-descriptions/src/main/res/values/strings.xml b/content-descriptions/src/main/res/values/strings.xml index 541e62e29b..4dae1db1c5 100644 --- a/content-descriptions/src/main/res/values/strings.xml +++ b/content-descriptions/src/main/res/values/strings.xml @@ -66,6 +66,8 @@ Confirm block Confirm unblock Delete + Leave + Clear Disappearing messages Enable Mute notifications @@ -73,7 +75,7 @@ Search Accept name change - Add members + Invite Contacts Apply changes Cancel name change Contact mentions diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index 51a07ca65d..dc85b58e77 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -196,11 +196,19 @@ object UpdateMessageBuilder { if (duration <= 0) { // ..by you.. return if (isOutgoing) { - context.getText(R.string.disappearingMessagesTurnedOffYou) + // in a group + if(isGroup) context.getText(R.string.disappearingMessagesTurnedOffYouGroup) + // 1on1 + else context.getText(R.string.disappearingMessagesTurnedOffYou) } else // ..or by someone else. { - Phrase.from(context, R.string.disappearingMessagesTurnedOff) + Phrase.from(context, + // in a group + if(isGroup) R.string.disappearingMessagesTurnedOffGroup + // 1on1 + else R.string.disappearingMessagesTurnedOff + ) .put(NAME_KEY, senderName) .format() } From 7f8e9fd5825447343e073973ee9464242329b5ae Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Wed, 4 Sep 2024 17:35:17 +1000 Subject: [PATCH 20/48] Reverted changes on DMs --- .../conversation/disappearingmessages/State.kt | 11 ++++++++--- .../conversation/disappearingmessages/ui/Adapter.kt | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt index f7c5a38e9d..eb4114ab54 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/State.kt @@ -18,7 +18,7 @@ data class State( val isSelfAdmin: Boolean = true, val address: Address? = null, val isNoteToSelf: Boolean = false, - val expiryMode: ExpiryMode = ExpiryMode.NONE, + val expiryMode: ExpiryMode? = null, val isNewConfigEnabled: Boolean = true, val persistedMode: ExpiryMode? = null, val showDebugOptions: Boolean = false @@ -30,8 +30,13 @@ data class State( val typeOptionsHidden get() = isNoteToSelf || (isGroup && isNewConfigEnabled) - val duration get() = expiryMode.duration - val expiryType get() = expiryMode.type + val nextType get() = when { + expiryType == ExpiryType.AFTER_READ -> ExpiryType.AFTER_READ + else -> ExpiryType.AFTER_SEND + } + + val duration get() = expiryMode?.duration + val expiryType get() = expiryMode?.type val isTimeOptionsEnabled = isNoteToSelf || isSelfAdmin && isNewConfigEnabled } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt index 3900c06bcf..d4b3b0602a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/ui/Adapter.kt @@ -32,7 +32,7 @@ private fun State.timeOptions(): List? { // Don't show times card if we have a types card, and type is off. if (!typeOptionsHidden && expiryType == ExpiryType.NONE) return null - return expiryType.let { type -> + return nextType.let { type -> when (type) { ExpiryType.AFTER_READ -> afterReadTimes else -> afterSendTimes @@ -69,7 +69,7 @@ private fun debugModes(isDebug: Boolean, type: ExpiryType) = debugTimes(isDebug).map { type.mode(it.inWholeSeconds) } private fun State.debugOptions(): List = - debugModes(showDebugOptions, expiryType).map { timeOption(it, subtitle = GetString("for testing purposes")) } + debugModes(showDebugOptions, nextType).map { timeOption(it, subtitle = GetString("for testing purposes")) } // Standard list of available disappearing message times private val afterSendTimes = listOf(12.hours, 1.days, 7.days, 14.days) @@ -94,6 +94,6 @@ private fun State.timeOption( title = title, subtitle = subtitle, contentDescription = title, - selected = mode.duration == expiryMode.duration, + selected = mode.duration == expiryMode?.duration, enabled = isTimeOptionsEnabled ) From 14207c75c71b136cfe781dd5fce754dc4f6ca22b Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 5 Sep 2024 11:03:30 +1000 Subject: [PATCH 21/48] Better ripple for home FAB --- .../main/res/drawable/new_conversation_button_background.xml | 4 ---- app/src/main/res/layout/activity_home.xml | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 app/src/main/res/drawable/new_conversation_button_background.xml diff --git a/app/src/main/res/drawable/new_conversation_button_background.xml b/app/src/main/res/drawable/new_conversation_button_background.xml deleted file mode 100644 index 4de519558a..0000000000 --- a/app/src/main/res/drawable/new_conversation_button_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml index aa522cc097..b47c67e5c9 100644 --- a/app/src/main/res/layout/activity_home.xml +++ b/app/src/main/res/layout/activity_home.xml @@ -171,10 +171,9 @@ android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" - android:background="@drawable/new_conversation_button_background" android:layout_marginBottom="@dimen/new_conversation_button_bottom_offset" - android:src="@drawable/ic_plus" - app:tint="@color/white" /> + app:rippleColor="@color/button_primary_ripple" + android:src="@drawable/ic_plus" /> From 2c3e73b2a762ffd1ddb530b38331787adb1be23a Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 5 Sep 2024 13:33:50 +1000 Subject: [PATCH 22/48] Added a control message when the current user accepts a message request --- .../v2/messages/ControlMessageView.kt | 16 ++++++++- .../securesms/database/Storage.kt | 34 ++++++++++++++++++- .../repository/ConversationRepository.kt | 2 ++ .../libsession/database/StorageProtocol.kt | 3 +- .../ReceivedMessageHandler.kt | 3 +- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index 8e3e841809..315e24da5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context import android.util.AttributeSet +import android.util.Log import android.view.LayoutInflater import android.widget.LinearLayout import androidx.core.content.res.ResourcesCompat @@ -17,10 +18,12 @@ import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.messages.ExpirationConfiguration import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY +import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.conversation.disappearingmessages.DisappearingMessages import org.thoughtcrime.securesms.conversation.disappearingmessages.expiryMode import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent +import org.thoughtcrime.securesms.ui.getSubbedCharSequence @AndroidEntryPoint class ControlMessageView : LinearLayout { @@ -77,7 +80,18 @@ class ControlMessageView : LinearLayout { } } message.isMessageRequestResponse -> { - binding.textView.text = context.getString(R.string.messageRequestsAccepted) + val msgRecipient = message.recipient.address.serialize() + val me = TextSecurePreferences.getLocalNumber(context) + binding.textView.text = if(me == msgRecipient) { // you accepted the user's request + val threadRecipient = DatabaseComponent.get(context).threadDatabase().getRecipientForThreadId(message.threadId) + context.getSubbedCharSequence( + R.string.messageRequestYouHaveAccepted, + NAME_KEY to (threadRecipient?.name ?: "") + ) + } else { // they accepted your request + context.getString(R.string.messageRequestsAccepted) + } + binding.root.contentDescription = context.getString(R.string.AccessibilityId_message_request_config_message) } message.isCallLog -> { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index a39598c55b..8fdbe2accc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.database import android.content.Context import android.net.Uri +import network.loki.messenger.R import java.security.MessageDigest import network.loki.messenger.libsession_util.ConfigBase import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN @@ -1448,7 +1449,10 @@ open class Storage( SSKEnvironment.shared.messageExpirationManager.maybeStartExpiration(sentTimestamp, senderPublicKey, expiryMode) } - override fun insertMessageRequestResponse(response: MessageRequestResponse) { + /** + * This will create a control message used to indicate that a contact has accepted our message request + */ + override fun insertMessageRequestResponseFromContact(response: MessageRequestResponse) { val userPublicKey = getUserPublicKey() val senderPublicKey = response.sender!! val recipientPublicKey = response.recipient!! @@ -1542,6 +1546,34 @@ open class Storage( } } + /** + * This will create a control message used to indicate that you have accepted a message request + */ + override fun insertMessageRequestResponseFromYou(threadId: Long){ + val userPublicKey = getUserPublicKey() ?: return + + val mmsDb = DatabaseComponent.get(context).mmsDatabase() + val message = IncomingMediaMessage( + fromSerialized(userPublicKey), + SnodeAPI.nowWithOffset, + -1, + 0, + 0, + false, + false, + true, + false, + Optional.absent(), + Optional.absent(), + Optional.absent(), + Optional.absent(), + Optional.absent(), + Optional.absent(), + Optional.absent() + ) + mmsDb.insertSecureDecryptedMessageInbox(message, threadId, runThreadUpdate = false) + } + override fun getRecipientApproved(address: Address): Boolean { return DatabaseComponent.get(context).recipientDatabase().getApproved(address) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt index 7f10b1eb20..b472c2c0c0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/repository/ConversationRepository.kt @@ -333,6 +333,8 @@ class DefaultConversationRepository @Inject constructor( MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = recipient.isLocalNumber) .success { threadDb.setHasSent(threadId, true) + // add a control message for our user + storage.insertMessageRequestResponseFromYou(threadId) continuation.resume(Result.success(Unit)) }.fail { error -> continuation.resume(Result.failure(error)) diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 581cc51570..aac481776f 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -202,7 +202,8 @@ interface StorageProtocol { fun getLastSeen(threadId: Long): Long fun updateThread(threadId: Long, unarchive: Boolean) fun insertDataExtractionNotificationMessage(senderPublicKey: String, message: DataExtractionNotificationInfoMessage, sentTimestamp: Long) - fun insertMessageRequestResponse(response: MessageRequestResponse) + fun insertMessageRequestResponseFromContact(response: MessageRequestResponse) + fun insertMessageRequestResponseFromYou(threadId: Long) fun setRecipientApproved(recipient: Recipient, approved: Boolean) fun getRecipientApproved(address: Address): Boolean fun setRecipientApprovedMe(recipient: Recipient, approvedMe: Boolean) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 525d60e821..2003aacf87 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -1,7 +1,6 @@ package org.session.libsession.messaging.sending_receiving import android.text.TextUtils -import network.loki.messenger.libsession_util.ConfigBase import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.avatars.AvatarHelper import org.session.libsession.messaging.MessagingModuleConfiguration @@ -266,7 +265,7 @@ fun MessageReceiver.handleUnsendRequest(message: UnsendRequest): Long? { } fun handleMessageRequestResponse(message: MessageRequestResponse) { - MessagingModuleConfiguration.shared.storage.insertMessageRequestResponse(message) + MessagingModuleConfiguration.shared.storage.insertMessageRequestResponseFromContact(message) } //endregion From a7843af3061d8f07563dbf0e926abadc24176366 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 5 Sep 2024 14:55:53 +1000 Subject: [PATCH 23/48] Updated QR screen to show dialog when permission is permanently denied Missing the real string for it! --- .../securesms/ui/components/QR.kt | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/components/QR.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/components/QR.kt index 70b6634cb8..0e82058679 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/components/QR.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/components/QR.kt @@ -30,8 +30,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -62,6 +65,10 @@ import kotlinx.coroutines.launch import network.loki.messenger.R import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.ui.AlertDialog +import org.thoughtcrime.securesms.ui.DialogButtonModel +import org.thoughtcrime.securesms.ui.GetString +import org.thoughtcrime.securesms.ui.theme.LocalColors import org.thoughtcrime.securesms.ui.theme.LocalDimensions import org.thoughtcrime.securesms.ui.theme.LocalType @@ -86,29 +93,10 @@ fun QRScannerScreen( val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA) + var showCameraPermissionDialog by remember { mutableStateOf(false) } + if (cameraPermissionState.status.isGranted) { ScanQrCode(errors, onScan) - } else if (cameraPermissionState.status.shouldShowRationale) { - Column( - modifier = Modifier - .align(Alignment.Center) - .padding(horizontal = 60.dp) - ) { - Text( - stringResource(R.string.cameraGrantAccessDenied).let { txt -> - val c = LocalContext.current - Phrase.from(txt).put(APP_NAME_KEY, c.getString(R.string.app_name)).format().toString() - }, - style = LocalType.current.base, - textAlign = TextAlign.Center - ) - Spacer(modifier = Modifier.size(LocalDimensions.current.spacing)) - OutlineButton( - stringResource(R.string.sessionSettings), - modifier = Modifier.align(Alignment.CenterHorizontally), - onClick = onClickSettings - ) - } } else { Column( modifier = Modifier @@ -129,11 +117,38 @@ fun QRScannerScreen( PrimaryOutlineButton( stringResource(R.string.cameraGrantAccess), modifier = Modifier.fillMaxWidth(), - onClick = { cameraPermissionState.run { launchPermissionRequest() } } + onClick = { + // if the permission has been denied permanently, ask the user to go to the settings + if (cameraPermissionState.status.shouldShowRationale){ + showCameraPermissionDialog = true + } + // otherwise ask for permission + else { + cameraPermissionState.run { launchPermissionRequest() } + } + } ) Spacer(modifier = Modifier.weight(1f)) } } + + // camera permission denied permanently dialog + if(showCameraPermissionDialog){ + AlertDialog( + onDismissRequest = { showCameraPermissionDialog = false }, + title = stringResource(R.string.permissionsRequired), + text = stringResource(R.string.cameraGrantAccessDenied), //todo UPDATE TO PROPER STRING !!!!!!!!!!!!!!!!!!!!!!! + buttons = listOf( + DialogButtonModel( + text = GetString(stringResource(id = R.string.sessionSettings)), + onClick = onClickSettings + ), + DialogButtonModel( + GetString(stringResource(R.string.cancel)) + ) + ) + ) + } } } From fa90b746b23cd8eeac605fe95bf47b39a111cf67 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 5 Sep 2024 15:33:33 +1000 Subject: [PATCH 24/48] Using the Compose version of our QR scanning Deleting non needed files --- .../securesms/groups/JoinCommunityFragment.kt | 94 ++++++++----- .../securesms/qr/ScanListener.java | 5 - .../securesms/qr/ScanningThread.java | 125 ------------------ .../securesms/util/ScanQRCodeFragment.kt | 65 --------- .../util/ScanQRCodePlaceholderFragment.kt | 34 ----- .../util/ScanQRCodeWrapperFragment.kt | 80 ++--------- .../main/res/layout/fragment_scan_qr_code.xml | 40 ------ .../fragment_scan_qr_code_placeholder.xml | 36 ----- .../layout/fragment_scan_qr_code_wrapper.xml | 6 - 9 files changed, 70 insertions(+), 415 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/qr/ScanListener.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/qr/ScanningThread.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeFragment.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodePlaceholderFragment.kt delete mode 100644 app/src/main/res/layout/fragment_scan_qr_code.xml delete mode 100644 app/src/main/res/layout/fragment_scan_qr_code_placeholder.xml delete mode 100644 app/src/main/res/layout/fragment_scan_qr_code_wrapper.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/JoinCommunityFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/JoinCommunityFragment.kt index a968775ff1..3dc43ec2b3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/JoinCommunityFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/JoinCommunityFragment.kt @@ -37,6 +37,8 @@ class JoinCommunityFragment : Fragment() { lateinit var delegate: StartConversationDelegate + var lastUrl: String? = null + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -66,45 +68,71 @@ class JoinCommunityFragment : Fragment() { } fun joinCommunityIfPossible(url: String) { - val openGroup = try { - OpenGroupUrlParser.parseUrl(url) - } catch (e: OpenGroupUrlParser.Error) { - when (e) { - is OpenGroupUrlParser.Error.MalformedURL, OpenGroupUrlParser.Error.NoRoom -> { - return Toast.makeText(activity, context?.resources?.getString(R.string.communityJoinError), Toast.LENGTH_SHORT).show() - } - is OpenGroupUrlParser.Error.InvalidPublicKey, OpenGroupUrlParser.Error.NoPublicKey -> { - return Toast.makeText(activity, R.string.communityEnterUrlErrorInvalidDescription, Toast.LENGTH_SHORT).show() + if(lastUrl == url) return + lastUrl = url + + lifecycleScope.launch(Dispatchers.Main) { + val openGroup = try { + OpenGroupUrlParser.parseUrl(url) + } catch (e: OpenGroupUrlParser.Error) { + when (e) { + is OpenGroupUrlParser.Error.MalformedURL, OpenGroupUrlParser.Error.NoRoom -> { + return@launch Toast.makeText( + activity, + context?.resources?.getString(R.string.communityJoinError), + Toast.LENGTH_SHORT + ).show() + } + + is OpenGroupUrlParser.Error.InvalidPublicKey, OpenGroupUrlParser.Error.NoPublicKey -> { + return@launch Toast.makeText( + activity, + R.string.communityEnterUrlErrorInvalidDescription, + Toast.LENGTH_SHORT + ).show() + } } } - } - showLoader() + showLoader() - lifecycleScope.launch(Dispatchers.IO) { - try { - val sanitizedServer = openGroup.server.removeSuffix("/") - val openGroupID = "$sanitizedServer.${openGroup.room}" - OpenGroupManager.add(sanitizedServer, openGroup.room, openGroup.serverPublicKey, requireContext()) - val storage = MessagingModuleConfiguration.shared.storage - storage.onOpenGroupAdded(sanitizedServer, openGroup.room) - val threadID = GroupManager.getOpenGroupThreadID(openGroupID, requireContext()) - val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray()) + withContext(Dispatchers.IO) { + try { + val sanitizedServer = openGroup.server.removeSuffix("/") + val openGroupID = "$sanitizedServer.${openGroup.room}" + OpenGroupManager.add( + sanitizedServer, + openGroup.room, + openGroup.serverPublicKey, + requireContext() + ) + val storage = MessagingModuleConfiguration.shared.storage + storage.onOpenGroupAdded(sanitizedServer, openGroup.room) + val threadID = + GroupManager.getOpenGroupThreadID(openGroupID, requireContext()) + val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray()) - ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(requireContext()) - withContext(Dispatchers.Main) { - val recipient = Recipient.from(requireContext(), Address.fromSerialized(groupID), false) - openConversationActivity(requireContext(), threadID, recipient) - delegate.onDialogClosePressed() + ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded( + requireContext() + ) + withContext(Dispatchers.Main) { + val recipient = Recipient.from( + requireContext(), + Address.fromSerialized(groupID), + false + ) + openConversationActivity(requireContext(), threadID, recipient) + delegate.onDialogClosePressed() + } + } catch (e: Exception) { + Log.e("Loki", "Couldn't join community.", e) + withContext(Dispatchers.Main) { + hideLoader() + val txt = Phrase.from(context, R.string.groupErrorJoin) + .put(GROUP_NAME_KEY, url).format().toString() + Toast.makeText(activity, txt, Toast.LENGTH_SHORT).show() + } } - } catch (e: Exception) { - Log.e("Loki", "Couldn't join community.", e) - withContext(Dispatchers.Main) { - hideLoader() - val txt = Phrase.from(context, R.string.groupErrorJoin).put(GROUP_NAME_KEY, url).format().toString() - Toast.makeText(activity, txt, Toast.LENGTH_SHORT).show() - } - return@launch } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/qr/ScanListener.java b/app/src/main/java/org/thoughtcrime/securesms/qr/ScanListener.java deleted file mode 100644 index 83faae9907..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/qr/ScanListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.thoughtcrime.securesms.qr; - -public interface ScanListener { - public void onQrDataFound(String data); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/qr/ScanningThread.java b/app/src/main/java/org/thoughtcrime/securesms/qr/ScanningThread.java deleted file mode 100644 index 4e86941c5b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/qr/ScanningThread.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.thoughtcrime.securesms.qr; - -import android.content.res.Configuration; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.google.zxing.BinaryBitmap; -import com.google.zxing.ChecksumException; -import com.google.zxing.DecodeHintType; -import com.google.zxing.FormatException; -import com.google.zxing.NotFoundException; -import com.google.zxing.PlanarYUVLuminanceSource; -import com.google.zxing.Result; -import com.google.zxing.common.HybridBinarizer; -import com.google.zxing.qrcode.QRCodeReader; - -import org.thoughtcrime.securesms.components.camera.CameraView; -import org.thoughtcrime.securesms.components.camera.CameraView.PreviewFrame; -import org.session.libsignal.utilities.Log; -import org.session.libsession.utilities.Util; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -public class ScanningThread extends Thread implements CameraView.PreviewCallback { - - private static final String TAG = ScanningThread.class.getSimpleName(); - - private final QRCodeReader reader = new QRCodeReader(); - private final AtomicReference scanListener = new AtomicReference<>(); - private final Map hints = new HashMap<>(); - - private boolean scanning = true; - private PreviewFrame previewFrame; - - public void setCharacterSet(String characterSet) { - hints.put(DecodeHintType.CHARACTER_SET, characterSet); - } - - public void setScanListener(ScanListener scanListener) { - this.scanListener.set(scanListener); - } - - @Override - public void onPreviewFrame(@NonNull PreviewFrame previewFrame) { - try { - synchronized (this) { - this.previewFrame = previewFrame; - this.notify(); - } - } catch (RuntimeException e) { - Log.w(TAG, e); - } - } - - - @Override - public void run() { - while (true) { - PreviewFrame ourFrame; - - synchronized (this) { - while (scanning && previewFrame == null) { - Util.wait(this, 0); - } - - if (!scanning) return; - else ourFrame = previewFrame; - - previewFrame = null; - } - - String data = getScannedData(ourFrame.getData(), ourFrame.getWidth(), ourFrame.getHeight(), ourFrame.getOrientation()); - ScanListener scanListener = this.scanListener.get(); - - if (data != null && scanListener != null) { - scanListener.onQrDataFound(data); - return; - } - } - } - - public void stopScanning() { - synchronized (this) { - scanning = false; - notify(); - } - } - - private @Nullable String getScannedData(byte[] data, int width, int height, int orientation) { - try { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - byte[] rotatedData = new byte[data.length]; - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - rotatedData[x * height + height - y - 1] = data[x + y * width]; - } - } - - int tmp = width; - width = height; - height = tmp; - data = rotatedData; - } - - PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, - 0, 0, width, height, - false); - - BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); - Result result = reader.decode(bitmap, hints); - - if (result != null) return result.getText(); - - } catch (NullPointerException | ChecksumException | FormatException | IndexOutOfBoundsException e) { - Log.w(TAG, e); - } catch (NotFoundException e) { - // Thanks ZXing... - } - - return null; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeFragment.kt deleted file mode 100644 index 3b551427a1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeFragment.kt +++ /dev/null @@ -1,65 +0,0 @@ -package org.thoughtcrime.securesms.util - -import android.content.res.Configuration -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.LinearLayout -import androidx.core.view.isVisible -import androidx.fragment.app.Fragment -import network.loki.messenger.databinding.FragmentScanQrCodeBinding -import org.thoughtcrime.securesms.qr.ScanListener -import org.thoughtcrime.securesms.qr.ScanningThread - -class ScanQRCodeFragment : Fragment() { - private lateinit var binding: FragmentScanQrCodeBinding - private val scanningThread = ScanningThread() - var scanListener: ScanListener? = null - set(value) { field = value; scanningThread.setScanListener(scanListener) } - var message: CharSequence = "" - - override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View { - binding = FragmentScanQrCodeBinding.inflate(layoutInflater, viewGroup, false) - return binding.root - } - - override fun onViewCreated(view: View, bundle: Bundle?) { - super.onViewCreated(view, bundle) - when (resources.configuration.orientation) { - Configuration.ORIENTATION_LANDSCAPE -> binding.overlayView.orientation = LinearLayout.HORIZONTAL - else -> binding.overlayView.orientation = LinearLayout.VERTICAL - } - binding.messageTextView.text = message - binding.messageTextView.isVisible = message.isNotEmpty() - } - - override fun onResume() { - super.onResume() - binding.cameraView.onResume() - binding.cameraView.setPreviewCallback(scanningThread) - try { - scanningThread.start() - } catch (exception: Exception) { - // Do nothing - } - scanningThread.setScanListener(scanListener) - } - - override fun onConfigurationChanged(newConfiguration: Configuration) { - super.onConfigurationChanged(newConfiguration) - binding.cameraView.onPause() - when (newConfiguration.orientation) { - Configuration.ORIENTATION_LANDSCAPE -> binding.overlayView.orientation = LinearLayout.HORIZONTAL - else -> binding.overlayView.orientation = LinearLayout.VERTICAL - } - binding.cameraView.onResume() - binding.cameraView.setPreviewCallback(scanningThread) - } - - override fun onPause() { - super.onPause() - this.binding.cameraView.onPause() - this.scanningThread.stopScanning() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodePlaceholderFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodePlaceholderFragment.kt deleted file mode 100644 index a0528ad432..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodePlaceholderFragment.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.thoughtcrime.securesms.util - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.squareup.phrase.Phrase -import network.loki.messenger.R -import network.loki.messenger.databinding.FragmentScanQrCodePlaceholderBinding -import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY - -class ScanQRCodePlaceholderFragment: Fragment() { - private lateinit var binding: FragmentScanQrCodePlaceholderBinding - var delegate: ScanQRCodePlaceholderFragmentDelegate? = null - - override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View { - binding = FragmentScanQrCodePlaceholderBinding.inflate(layoutInflater, viewGroup, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.grantCameraAccessButton.setOnClickListener { delegate?.requestCameraAccess() } - - binding.needCameraPermissionsTV.text = Phrase.from(context, R.string.cameraGrantAccessQr) - .put(APP_NAME_KEY, getString(R.string.app_name)) - .format() - } -} - -interface ScanQRCodePlaceholderFragmentDelegate { - fun requestCameraAccess() -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeWrapperFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeWrapperFragment.kt index e5de4c36d9..b17356618b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeWrapperFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ScanQRCodeWrapperFragment.kt @@ -1,89 +1,27 @@ package org.thoughtcrime.securesms.util -import android.Manifest -import android.content.pm.PackageManager import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment -import com.tbruyelle.rxpermissions2.RxPermissions -import network.loki.messenger.R -import org.thoughtcrime.securesms.qr.ScanListener +import kotlinx.coroutines.flow.emptyFlow +import org.thoughtcrime.securesms.ui.components.QRScannerScreen +import org.thoughtcrime.securesms.ui.createThemedComposeView -class ScanQRCodeWrapperFragment : Fragment(), ScanQRCodePlaceholderFragmentDelegate, ScanListener { +class ScanQRCodeWrapperFragment : Fragment() { companion object { const val FRAGMENT_TAG = "ScanQRCodeWrapperFragment_FRAGMENT_TAG" } var delegate: ScanQRCodeWrapperFragmentDelegate? = null - var message: CharSequence = "" - var enabled: Boolean = true - set(value) { - val shouldUpdate = field != value // update if value changes (view appears or disappears) - field = value - if (shouldUpdate) { - update() - } - } - @Deprecated("Deprecated in Java") - override fun setUserVisibleHint(isVisibleToUser: Boolean) { - super.setUserVisibleHint(isVisibleToUser) - enabled = isVisibleToUser - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_scan_qr_code_wrapper, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - update() - } - - private fun update() { - if (!this.isAdded) return - - val fragment: Fragment - if (!enabled) { - val manager = childFragmentManager - manager.findFragmentByTag(FRAGMENT_TAG)?.let { existingFragment -> - // remove existing camera fragment (if switching back to other page) - manager.beginTransaction().remove(existingFragment).commit() - } - return - } - if (ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { - val scanQRCodeFragment = ScanQRCodeFragment() - scanQRCodeFragment.scanListener = this - scanQRCodeFragment.message = message - fragment = scanQRCodeFragment - } else { - val scanQRCodePlaceholderFragment = ScanQRCodePlaceholderFragment() - scanQRCodePlaceholderFragment.delegate = this - fragment = scanQRCodePlaceholderFragment - } - val transaction = childFragmentManager.beginTransaction() - transaction.replace(R.id.fragmentContainer, fragment, FRAGMENT_TAG) - transaction.commit() - } - - override fun requestCameraAccess() { - @SuppressWarnings("unused") - val unused = RxPermissions(this).request(Manifest.permission.CAMERA).subscribe { isGranted -> - if (isGranted) { - update() - } - } - } - - override fun onQrDataFound(data: String) { - activity?.runOnUiThread { - delegate?.handleQRCodeScanned(data) - } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + createThemedComposeView { + QRScannerScreen(emptyFlow(), onScan = { + delegate?.handleQRCodeScanned(it) + }) } } diff --git a/app/src/main/res/layout/fragment_scan_qr_code.xml b/app/src/main/res/layout/fragment_scan_qr_code.xml deleted file mode 100644 index ea8e1c5fca..0000000000 --- a/app/src/main/res/layout/fragment_scan_qr_code.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_scan_qr_code_placeholder.xml b/app/src/main/res/layout/fragment_scan_qr_code_placeholder.xml deleted file mode 100644 index f88b66800b..0000000000 --- a/app/src/main/res/layout/fragment_scan_qr_code_placeholder.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - -