mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 00:37:47 +00:00
Merge branch 'dev' of https://github.com/oxen-io/session-android into fix-open-group-spam
This commit is contained in:
commit
25df4330be
10
.tx/config
10
.tx/config
@ -1,10 +0,0 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = da_DK:da-rDK,he:iw,id:in,kn_IN:kn-rIN,pt_BR:pt-rBR,pt_PT:pt,qu_EC:qu-rEC,sv_SE:sv-rSE,zh_CN:zh-rCN,zh_HK:zh-rHK,zh_TW:zh-rTW
|
||||
|
||||
[signal-android.master]
|
||||
file_filter = app/src/main/res/values-<lang>/strings.xml
|
||||
source_file = app/src/main/res/values/strings.xml
|
||||
source_lang = en
|
||||
type = ANDROID
|
||||
|
26
BUILDING.md
26
BUILDING.md
@ -15,11 +15,11 @@ You will need Java 8 set up on your machine.
|
||||
Ensure that the following packages are installed from the Android SDK manager:
|
||||
|
||||
* Android SDK Build Tools (see buildToolsVersion in build.gradle)
|
||||
* SDK Platform (All API levels)
|
||||
* SDK Platform (all API levels)
|
||||
* Android Support Repository
|
||||
* Google Repository
|
||||
|
||||
In Android studio, this can be done from the Quickstart panel, choose "Configure" then "SDK Manager". In the SDK Tools tab of the SDK Manager, make sure that the "Android Support Repository" is installed, and that the latest "Android SDK build-tools" are installed. Click "OK" to return to the Quickstart panel. You may also need to install API version 28 in the SDK platforms tab.
|
||||
In Android studio, this can be done from the Quickstart panel. Just choose "Configure", then "SDK Manager". In the SDK Tools tab of the SDK Manager, make sure that "Android Support Repository" is installed, and that the latest "Android SDK build-tools" are installed. Click "OK" to return to the Quickstart panel. You may also need to install API version 28 in the SDK platforms tab.
|
||||
|
||||
Setting up a development environment and building from Android Studio
|
||||
------------------------------------
|
||||
@ -33,27 +33,7 @@ Setting up a development environment and building from Android Studio
|
||||
5. Default config options should be good enough.
|
||||
6. Project initialization and building should proceed.
|
||||
|
||||
Building Session from the command line
|
||||
---------------
|
||||
|
||||
The following steps should help you (re)build Session from the command line once all dependencies have been acquired.
|
||||
|
||||
1. Checkout the session-android project source with the command:
|
||||
|
||||
git clone https://github.com/oxen-io/session-android.git
|
||||
|
||||
2. Make sure you have the [Android SDK](https://developer.android.com/sdk/index.html) installed.
|
||||
3. Create a local.properties file at the root of your source checkout and add an sdk.dir entry to it. For example:
|
||||
|
||||
sdk.dir=/Application/android-sdk-macosx
|
||||
|
||||
4. Execute Gradle:
|
||||
|
||||
./gradlew :app:build
|
||||
|
||||
Contributing code
|
||||
-----------------
|
||||
|
||||
The bulk of the Session code can be found under src/org/thoughtcrime/securesms/loki on this repo and java/main/java/org/whispersystems/signalservice/loki on the session-android-service repo.
|
||||
|
||||
Code contributions should be sent via github as pull requests, from feature branches [as explained here](https://help.github.com/articles/using-pull-requests).
|
||||
Code contributions should be sent via Github as pull requests, from feature branches [as explained here](https://help.github.com/articles/using-pull-requests).
|
||||
|
34
NOTICE
34
NOTICE
@ -1,34 +0,0 @@
|
||||
TextSecure provides encrypted text messages for Android.
|
||||
Copyright 2011 Whisper Systems
|
||||
|
||||
This software has the follow third party dependencies:
|
||||
|
||||
Bouncy Castle 1.42
|
||||
http://www.bouncycastle.org/
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
ZXing
|
||||
http://code.google.com/p/zxing/
|
||||
Apache License 2.0
|
||||
|
||||
Copyright 2009 ZXing authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
45
README.md
45
README.md
@ -10,7 +10,7 @@ Add the [F-Droid repo](https://fdroid.getsession.org/)
|
||||
|
||||
Session integrates directly with [Oxen Service Nodes](https://docs.oxen.io/about-the-oxen-blockchain/oxen-service-nodes), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users' IP addresses. For a full understanding of how Session works, read the [Session Whitepaper](https://getsession.org/whitepaper).
|
||||
|
||||
![AndroidSession](https://i.imgur.com/0YC9TyI.png)
|
||||
<img src="https://i.imgur.com/RSMrR1F.png" width="320" />
|
||||
|
||||
## Want to contribute? Found a bug or have a feature request?
|
||||
|
||||
@ -20,12 +20,53 @@ Please search for any [existing issues](https://github.com/oxen-io/session-andro
|
||||
|
||||
Build instructions can be found in [BUILDING.md](BUILDING.md).
|
||||
|
||||
## Translations
|
||||
|
||||
Want to help us translate Session into your language? You can do so at https://crowdin.com/project/session-android!
|
||||
|
||||
## Verifying signatures
|
||||
|
||||
**Step 1:**
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/oxen-io/oxen-core/master/utils/gpg_keys/KeeJef.asc
|
||||
gpg --import KeeJef.asc
|
||||
```
|
||||
|
||||
**Step 2:**
|
||||
|
||||
Get the signed hash for this release. `SESSION_VERSION` needs to be updated for the release you want to verify.
|
||||
|
||||
```
|
||||
export SESSION_VERSION=1.10.4
|
||||
wget https://github.com/oxen-io/session-android/releases/download/$SESSION_VERSION/signatures.asc
|
||||
```
|
||||
|
||||
**Step 3:**
|
||||
|
||||
Verify the signature of the hashes of the files.
|
||||
|
||||
```
|
||||
gpg --verify signatures.asc 2>&1 |grep "Good signature from"
|
||||
```
|
||||
|
||||
The command above should print "`Good signature from "Kee Jefferys...`". If it does, the hashes are valid but we still have to make the sure the signed hashes matches the downloaded files.
|
||||
|
||||
**Step 4:**
|
||||
|
||||
Make sure the two commands below returns the same hash. If they do, files are valid.
|
||||
|
||||
```
|
||||
sha256sum session-$SESSION_VERSION-universal.apk
|
||||
grep universal.apk signatures.asc
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2011 Whisper Systems
|
||||
|
||||
Copyright 2013-2017 Open Whisper Systems
|
||||
|
||||
Copyright 2019-2020 The Loki Project
|
||||
Copyright 2019-2021 The Loki Project
|
||||
|
||||
Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
@ -1,54 +0,0 @@
|
||||
## How to translate Session into new languages quickly and easily
|
||||
|
||||
There are people all around the world who can benefit from access to Session — and that means we need to make Session available in as many languages as possible. We’ve had a number of requests from community members wanting to help out by translating Session into currently unsupported (or only partially supported) languages. If you speak multiple languages and you want to help us make Session available in another language you speak, this guide will show you how to translate Session’s iOS and Android apps quickly and easily.
|
||||
|
||||
### Translating Session for iOS:
|
||||
|
||||
Translating Session iOS into a new language is easy! You’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience.
|
||||
|
||||
#### Step 1: Retrieving English strings
|
||||
- Go to [Session’s iOS GitHub page](https://github.com/loki-project/session-ios)
|
||||
- In the list of folders and files, click **Session**
|
||||
- Click **Meta**
|
||||
- Click **Translations**
|
||||
- Click **en.lproj**
|
||||
- Click **localizable.strings**
|
||||
- Scroll down to Line #2557 (using the line numbers on the left-hand side of the text). This line should contain the text `// MARK: - Session` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text)
|
||||
- Select and copy all text from that line down to the end of the file
|
||||
- Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file
|
||||
- Paste the text you copied earlier into this blank file
|
||||
|
||||
#### Step 2: Translate!
|
||||
This file will now have a large number of lines of code. Each line contains 2 sets of information, both in quotation marks, like this:
|
||||
|
||||
`"continue_2" = "Continue";`
|
||||
|
||||
For each line of code, translate the word or sentence to the **right** of the equals sign into the language you are translating into. Do **not** edit the text to the **left** of the equals sign.
|
||||
|
||||
Once you are finished translating, save the file with a filename that specifies which language you have translated the app into, and email the file to us at support@getsession.org along with information about the language you have translated the app into. Be sure to specify in your email that you have translated the iOS app (for information on translating the Android app, see below). Our developers will then take your translation and apply it to the Session iOS app. Thank you for helping make Session more accessible for everyone!
|
||||
|
||||
|
||||
### Translating for Android:
|
||||
|
||||
It’s just as easy to add new translations on Session Android! Once again, you’ll need a web browser, a plaintext editor (TextEdit on macOS or Notepad on Windows will do), and a little bit of time and patience.
|
||||
|
||||
#### Step 1: Retrieving English strings
|
||||
- Go to [Session’s Android GitHub page](https://github.com/loki-project/session-android)
|
||||
- In the list of files and folders, click **res**
|
||||
- Click **values** (you will need to scroll down to find this folder; make sure you click the folder named **values** and not any of the folders named **values-xx** or with other suffixes)
|
||||
- Click **strings.xml**
|
||||
- Scroll down to Line #1657 (using the line numbers on the left-hand side of the text). This line should contain the text `<!-- Session -->` (note: if this line does not contain that text, use Ctrl+F, Cmd+F, or your browser’s Find on Page function to find the line which contains that text)
|
||||
- Select and copy all text from that line down to the end of the file
|
||||
- Open a plaintext editor (TextEdit on macOS, Notepad on Windows, or your preferred plaintext editor) and create a new file
|
||||
- Paste the text you copied earlier into this blank file
|
||||
|
||||
#### Step 2: Translate!
|
||||
This file will now have a large number of lines of code. Each line will contain `<string name=”xxx”>` and `</string>` tags. To translate Session Android, translate the text between these tags. For example:
|
||||
|
||||
`<string name="continue_2">Continue</string>`
|
||||
|
||||
In this line, translate the word **Continue** into the language you are translating into. Do not translate any other text. Do **not** translate the text inside either pair of angled brackets <>.
|
||||
|
||||
Translate the word or sentence between each pair of `<string></string>` tags, on each line.
|
||||
|
||||
Once you are finished translating, save the file with a filename that specifies which language you have translated the app into, and email the file to us at support@getsession.org along with information about the language you have translated the app into. Be sure to specify in your email that you have translated the Android app (for information on translating the iOS app, see above). Our developers will then take your translation and apply it to the Session Android app. Thank you for helping make Session more accessible for everyone!
|
@ -143,7 +143,7 @@ dependencies {
|
||||
testImplementation 'org.robolectric:shadows-multidex:4.2'
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 171
|
||||
def canonicalVersionCode = 172
|
||||
def canonicalVersionName = "1.10.8"
|
||||
|
||||
def postFixSize = 10
|
||||
|
@ -172,9 +172,6 @@
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.activities.ChatSettingsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.loki.activities.LinkedDevicesActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<!-- Session -->
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.ShareActivity"
|
||||
@ -224,24 +221,6 @@
|
||||
android:resource="@mipmap/ic_launcher" />
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.stickers.StickerPackPreviewActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/Theme.TextSecure.DayNight.NoActionBar"
|
||||
android:windowSoftInputMode="stateHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="addstickers"
|
||||
android:scheme="sgnl" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.conversation.ConversationActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
@ -282,23 +261,11 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.PassphraseCreateActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:label="@string/AndroidManifest__create_passphrase"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/Theme.Session.DayNight.NoActionBar"
|
||||
android:windowSoftInputMode="stateUnchanged" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.PassphrasePromptActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/Theme.Session.DayNight.NoActionBar"/>
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.PushContactSelectionActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:label="@string/AndroidManifest__select_contacts"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.giph.ui.GiphyActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
|
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Open Whisper Systems
|
||||
/* Copyright (C) 2013 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -30,26 +29,25 @@ import androidx.multidex.MultiDexApplication;
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.session.libsession.avatars.AvatarHelper;
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration;
|
||||
import org.session.libsession.messaging.mentions.MentionsManager;
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPollerV2;
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.Poller;
|
||||
import org.session.libsession.snode.SnodeModule;
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsession.utilities.IdentityKeyUtil;
|
||||
import org.session.libsession.utilities.ProfileKeyUtil;
|
||||
import org.session.libsession.utilities.ProfilePictureUtilities;
|
||||
import org.session.libsession.utilities.SSKEnvironment;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWrapper;
|
||||
import org.session.libsession.utilities.dynamiclanguage.LocaleParser;
|
||||
import org.session.libsignal.database.LokiAPIDatabaseProtocol;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
import org.session.libsignal.utilities.ThreadUtils;
|
||||
import org.signal.aesgcmprovider.AesGcmProvider;
|
||||
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||
import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
|
||||
@ -65,9 +63,10 @@ import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager;
|
||||
import org.thoughtcrime.securesms.loki.api.OpenGroupManager;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
||||
import org.thoughtcrime.securesms.loki.utilities.ContactUtilities;
|
||||
import org.thoughtcrime.securesms.loki.utilities.FcmUtils;
|
||||
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities;
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
||||
@ -85,14 +84,12 @@ import org.webrtc.PeerConnectionFactory;
|
||||
import org.webrtc.PeerConnectionFactory.InitializationOptions;
|
||||
import org.webrtc.voiceengine.WebRtcAudioManager;
|
||||
import org.webrtc.voiceengine.WebRtcAudioUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.Security;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import dagger.ObjectGraph;
|
||||
import kotlin.Unit;
|
||||
import kotlinx.coroutines.Job;
|
||||
@ -153,30 +150,21 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
initializeDependencyInjection();
|
||||
NotificationChannels.create(this);
|
||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||
// Loki
|
||||
// ========
|
||||
AppContext.INSTANCE.configureKovenant();
|
||||
messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier());
|
||||
broadcaster = new Broadcaster(this);
|
||||
threadNotificationHandler = new Handler(Looper.getMainLooper());
|
||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
||||
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||
MessagingModuleConfiguration.Companion.configure(this,
|
||||
DatabaseFactory.getStorage(this),
|
||||
DatabaseFactory.getAttachmentProvider(this));
|
||||
DatabaseFactory.getStorage(this),
|
||||
DatabaseFactory.getAttachmentProvider(this));
|
||||
SnodeModule.Companion.configure(apiDB, broadcaster);
|
||||
if (userPublicKey != null) {
|
||||
MentionsManager.Companion.configureIfNeeded(userPublicKey, userDB);
|
||||
}
|
||||
resubmitProfilePictureIfNeeded();
|
||||
if (userPublicKey != null) {
|
||||
registerForFCMIfNeeded(false);
|
||||
}
|
||||
// Set application UI mode (day/night theme) to the user selected one.
|
||||
UiModeUtilities.setupUiModeToUserSelected(this);
|
||||
// ========
|
||||
initializeExpiringMessageManager();
|
||||
initializeTypingStatusRepository();
|
||||
initializeTypingStatusSender();
|
||||
@ -194,7 +182,28 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
isAppVisible = true;
|
||||
Log.i(TAG, "App is now visible.");
|
||||
KeyCachingService.onAppForegrounded(this);
|
||||
// Loki
|
||||
|
||||
boolean hasPerformedContactMigration = TextSecurePreferences.INSTANCE.hasPerformedContactMigration(this);
|
||||
if (!hasPerformedContactMigration) {
|
||||
TextSecurePreferences.INSTANCE.setPerformedContactMigration(this);
|
||||
Set<Recipient> allContacts = ContactUtilities.getAllContacts(this);
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(this);
|
||||
LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this);
|
||||
for (Recipient recipient : allContacts) {
|
||||
if (recipient.isGroupRecipient()) { continue; }
|
||||
String sessionID = recipient.getAddress().serialize();
|
||||
Contact contact = contactDB.getContactWithSessionID(sessionID);
|
||||
if (contact == null) {
|
||||
contact = new Contact(sessionID);
|
||||
String name = userDB.getDisplayName(sessionID);
|
||||
contact.setName(name);
|
||||
contact.setProfilePictureURL(recipient.getProfileAvatar());
|
||||
contact.setProfilePictureEncryptionKey(recipient.getProfileKey());
|
||||
contact.setTrusted(true);
|
||||
}
|
||||
contactDB.setContact(contact);
|
||||
}
|
||||
}
|
||||
if (poller != null) {
|
||||
poller.setCaughtUp(false);
|
||||
}
|
||||
@ -209,7 +218,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
Log.i(TAG, "App is no longer visible.");
|
||||
KeyCachingService.onAppBackgrounded(this);
|
||||
messageNotifier.setVisibleThread(-1);
|
||||
// Loki
|
||||
if (poller != null) {
|
||||
poller.stopIfNeeded();
|
||||
}
|
||||
|
@ -18,8 +18,11 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.annimon.stream.Stream;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
import org.thoughtcrime.securesms.loki.utilities.UiModeUtilities;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
@ -197,7 +200,14 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener
|
||||
if (senderHexEncodedPublicKey.equalsIgnoreCase(TextSecurePreferences.getLocalNumber(getContext()))) {
|
||||
quoteeDisplayName = TextSecurePreferences.getProfileName(getContext());
|
||||
} else {
|
||||
quoteeDisplayName = DatabaseFactory.getLokiUserDatabase(getContext()).getDisplayName(senderHexEncodedPublicKey);
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(getContext());
|
||||
Contact contact = contactDB.getContactWithSessionID(senderHexEncodedPublicKey);
|
||||
if (contact != null) {
|
||||
Contact.ContactContext context = (this.conversationRecipient.isOpenGroupRecipient()) ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR;
|
||||
quoteeDisplayName = contact.displayName(context);
|
||||
} else {
|
||||
quoteeDisplayName = senderHexEncodedPublicKey;
|
||||
}
|
||||
}
|
||||
|
||||
authorView.setText(isOwnNumber ? getContext().getString(R.string.QuoteView_you) : quoteeDisplayName);
|
||||
|
@ -62,7 +62,6 @@ import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -103,6 +102,7 @@ import org.session.libsession.utilities.recipients.RecipientModifiedListener;
|
||||
import org.session.libsession.utilities.ExpirationUtil;
|
||||
import org.session.libsession.utilities.GroupUtil;
|
||||
import org.session.libsession.utilities.MediaTypes;
|
||||
import org.session.libsession.utilities.SSKEnvironment;
|
||||
import org.session.libsession.utilities.ServiceUtil;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
@ -157,8 +157,6 @@ import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity;
|
||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||
import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity;
|
||||
import org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||
import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
|
||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
|
||||
@ -212,14 +210,14 @@ import network.loki.messenger.R;
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
implements ConversationFragment.ConversationFragmentListener,
|
||||
AttachmentManager.AttachmentListener,
|
||||
RecipientModifiedListener,
|
||||
OnKeyboardShownListener,
|
||||
InputPanel.Listener,
|
||||
InputPanel.MediaListener,
|
||||
ComposeText.CursorPositionChangedListener,
|
||||
ConversationSearchBottomBar.EventListener
|
||||
implements ConversationFragment.ConversationFragmentListener,
|
||||
AttachmentManager.AttachmentListener,
|
||||
RecipientModifiedListener,
|
||||
OnKeyboardShownListener,
|
||||
InputPanel.Listener,
|
||||
InputPanel.MediaListener,
|
||||
ComposeText.CursorPositionChangedListener,
|
||||
ConversationSearchBottomBar.EventListener
|
||||
{
|
||||
private static final String TAG = ConversationActivity.class.getSimpleName();
|
||||
|
||||
@ -234,11 +232,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
public static final String LAST_SEEN_EXTRA = "last_seen";
|
||||
public static final String STARTING_POSITION_EXTRA = "starting_position";
|
||||
|
||||
// private static final int PICK_GALLERY = 1;
|
||||
// private static final int PICK_GALLERY = 1;
|
||||
private static final int PICK_DOCUMENT = 2;
|
||||
private static final int PICK_AUDIO = 3;
|
||||
private static final int PICK_CONTACT = 4;
|
||||
// private static final int GET_CONTACT_DETAILS = 5;
|
||||
// private static final int GET_CONTACT_DETAILS = 5;
|
||||
// private static final int GROUP_EDIT = 6;
|
||||
private static final int TAKE_PHOTO = 7;
|
||||
private static final int ADD_CONTACT = 8;
|
||||
@ -418,7 +416,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
Log.i(TAG, "onNewIntent()");
|
||||
|
||||
|
||||
if (isFinishing()) {
|
||||
Log.w(TAG, "Activity is finishing...");
|
||||
return;
|
||||
@ -513,90 +511,89 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
super.onActivityResult(reqCode, resultCode, data);
|
||||
|
||||
if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) ||
|
||||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
|
||||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
|
||||
{
|
||||
updateLinkPreviewState();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reqCode) {
|
||||
case PICK_DOCUMENT:
|
||||
setMedia(data.getData(), MediaType.DOCUMENT);
|
||||
break;
|
||||
case PICK_AUDIO:
|
||||
setMedia(data.getData(), MediaType.AUDIO);
|
||||
break;
|
||||
case TAKE_PHOTO:
|
||||
if (attachmentManager.getCaptureUri() != null) {
|
||||
setMedia(attachmentManager.getCaptureUri(), MediaType.IMAGE);
|
||||
}
|
||||
break;
|
||||
case ADD_CONTACT:
|
||||
recipient = Recipient.from(this, recipient.getAddress(), true);
|
||||
recipient.addListener(this);
|
||||
fragment.reloadList();
|
||||
break;
|
||||
case PICK_DOCUMENT:
|
||||
setMedia(data.getData(), MediaType.DOCUMENT);
|
||||
break;
|
||||
case PICK_AUDIO:
|
||||
setMedia(data.getData(), MediaType.AUDIO);
|
||||
break;
|
||||
case TAKE_PHOTO:
|
||||
if (attachmentManager.getCaptureUri() != null) {
|
||||
setMedia(attachmentManager.getCaptureUri(), MediaType.IMAGE);
|
||||
}
|
||||
break;
|
||||
case ADD_CONTACT:
|
||||
recipient = Recipient.from(this, recipient.getAddress(), true);
|
||||
recipient.addListener(this);
|
||||
fragment.reloadList();
|
||||
break;
|
||||
/*
|
||||
case PICK_LOCATION:
|
||||
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
|
||||
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
||||
break;
|
||||
*/
|
||||
case PICK_GIF:
|
||||
setMedia(data.getData(),
|
||||
MediaType.GIF,
|
||||
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
|
||||
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
|
||||
break;
|
||||
case SMS_DEFAULT:
|
||||
initializeSecurity(true, isDefaultSms);
|
||||
break;
|
||||
case MEDIA_SENDER:
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
int subscriptionId = -1;
|
||||
boolean initiating = threadId == -1;
|
||||
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
case PICK_GIF:
|
||||
setMedia(data.getData(),
|
||||
MediaType.GIF,
|
||||
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
|
||||
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
|
||||
break;
|
||||
case SMS_DEFAULT:
|
||||
initializeSecurity(true, isDefaultSms);
|
||||
break;
|
||||
case MEDIA_SENDER:
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
int subscriptionId = -1;
|
||||
boolean initiating = threadId == -1;
|
||||
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
|
||||
List<Media> mediaList = data.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA);
|
||||
List<Media> mediaList = data.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA);
|
||||
|
||||
for (Media mediaItem : mediaList) {
|
||||
if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new VideoSlide(this, mediaItem.getUri(), 0, mediaItem.getCaption().orNull()));
|
||||
} else if (MediaUtil.isGif(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
|
||||
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
|
||||
} else {
|
||||
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
|
||||
for (Media mediaItem : mediaList) {
|
||||
if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new VideoSlide(this, mediaItem.getUri(), 0, mediaItem.getCaption().orNull()));
|
||||
} else if (MediaUtil.isGif(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
|
||||
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
|
||||
slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
|
||||
} else {
|
||||
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Context context = ConversationActivity.this.getApplicationContext();
|
||||
final Context context = ConversationActivity.this.getApplicationContext();
|
||||
|
||||
sendMediaMessage(message,
|
||||
slideDeck,
|
||||
inputPanel.getQuote().orNull(),
|
||||
Optional.absent(),
|
||||
initiating).addListener(new AssertedSuccessListener<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
Stream.of(slideDeck.getSlides())
|
||||
.map(Slide::getUri)
|
||||
.withoutNulls()
|
||||
.filter(BlobProvider::isAuthority)
|
||||
.forEach(uri -> BlobProvider.getInstance().delete(context, uri));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case INVITE_CONTACTS:
|
||||
if (data.getExtras() == null || !data.hasExtra(SelectContactsActivity.Companion.getSelectedContactsKey())) return;
|
||||
String[] selectedContacts = data.getExtras().getStringArray(SelectContactsActivity.Companion.getSelectedContactsKey());
|
||||
sendOpenGroupInvitations(selectedContacts);
|
||||
break;
|
||||
sendMediaMessage(message,
|
||||
slideDeck,
|
||||
inputPanel.getQuote().orNull(),
|
||||
Optional.absent(),
|
||||
initiating).addListener(new AssertedSuccessListener<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
Stream.of(slideDeck.getSlides())
|
||||
.map(Slide::getUri)
|
||||
.withoutNulls()
|
||||
.filter(BlobProvider::isAuthority)
|
||||
.forEach(uri -> BlobProvider.getInstance().delete(context, uri));
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case INVITE_CONTACTS:
|
||||
if (data.getExtras() == null || !data.hasExtra(SelectContactsActivity.Companion.getSelectedContactsKey())) return;
|
||||
String[] selectedContacts = data.getExtras().getStringArray(SelectContactsActivity.Companion.getSelectedContactsKey());
|
||||
sendOpenGroupInvitations(selectedContacts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,14 +673,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (isSingleConversation() && getRecipient().getContactUri() == null) {
|
||||
inflater.inflate(R.menu.conversation_add_to_contacts, menu);
|
||||
}
|
||||
|
||||
|
||||
if (recipient != null && recipient.isLocalNumber()) {
|
||||
if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false);
|
||||
else menu.findItem(R.id.menu_call_insecure).setVisible(false);
|
||||
|
||||
MenuItem muteItem = menu.findItem(R.id.menu_mute_notifications);
|
||||
|
||||
if (muteItem != null) {
|
||||
muteItem.setVisible(false);
|
||||
}
|
||||
@ -751,26 +744,26 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
switch (item.getItemId()) {
|
||||
// case R.id.menu_call_secure: handleDial(getRecipient(), true); return true;
|
||||
// case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true;
|
||||
case R.id.menu_unblock: handleUnblock(); return true;
|
||||
case R.id.menu_block: handleBlock(); return true;
|
||||
case R.id.menu_copy_session_id: handleCopySessionID(); return true;
|
||||
case R.id.menu_view_media: handleViewMedia(); return true;
|
||||
case R.id.menu_add_shortcut: handleAddShortcut(); return true;
|
||||
case R.id.menu_search: handleSearch(); return true;
|
||||
case R.id.menu_unblock: handleUnblock(); return true;
|
||||
case R.id.menu_block: handleBlock(); return true;
|
||||
case R.id.menu_copy_session_id: handleCopySessionID(); return true;
|
||||
case R.id.menu_view_media: handleViewMedia(); return true;
|
||||
case R.id.menu_add_shortcut: handleAddShortcut(); return true;
|
||||
case R.id.menu_search: handleSearch(); return true;
|
||||
// case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
|
||||
// case R.id.menu_reset_secure_session: handleResetSecureSession(); return true;
|
||||
// case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
|
||||
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
|
||||
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
|
||||
case R.id.menu_edit_group: handleEditPushGroup(); return true;
|
||||
case R.id.menu_leave: handleLeavePushGroup(); return true;
|
||||
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
|
||||
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
|
||||
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
|
||||
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
|
||||
case R.id.menu_edit_group: handleEditPushGroup(); return true;
|
||||
case R.id.menu_leave: handleLeavePushGroup(); return true;
|
||||
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
|
||||
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
|
||||
// case R.id.menu_conversation_settings: handleConversationSettings(); return true;
|
||||
case R.id.menu_expiring_messages_off:
|
||||
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
|
||||
case R.id.menu_invite_to_open_group: handleInviteToOpenGroup(); return true;
|
||||
case android.R.id.home: handleReturnToConversationList(); return true;
|
||||
case R.id.menu_expiring_messages_off:
|
||||
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
|
||||
case R.id.menu_invite_to_open_group: handleInviteToOpenGroup(); return true;
|
||||
case android.R.id.home: handleReturnToConversationList(); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -841,7 +834,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setMuted(recipient, until);
|
||||
.setMuted(recipient, until);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -856,7 +849,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setMuted(recipient, 0);
|
||||
.setMuted(recipient, 0);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -868,20 +861,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(titleRes)
|
||||
.setMessage(bodyRes)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setBlocked(recipient, false);
|
||||
.setTitle(titleRes)
|
||||
.setMessage(bodyRes)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
|
||||
.setBlocked(recipient, false);
|
||||
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}).show();
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}).show();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||
@ -951,7 +944,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
if (icon == null) {
|
||||
icon = IconCompat.createWithResource(context, recipient.isGroupRecipient() ? R.mipmap.ic_group_shortcut
|
||||
: R.mipmap.ic_person_shortcut);
|
||||
: R.mipmap.ic_person_shortcut);
|
||||
}
|
||||
|
||||
return icon;
|
||||
@ -961,14 +954,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
protected void onPostExecute(IconCompat icon) {
|
||||
Context context = getApplicationContext();
|
||||
String name = Optional.fromNullable(recipient.getName())
|
||||
.or(Optional.fromNullable(recipient.getProfileName()))
|
||||
.or(recipient.toShortString());
|
||||
.or(Optional.fromNullable(recipient.getProfileName()))
|
||||
.or(recipient.toShortString());
|
||||
|
||||
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.getAddress().serialize() + '-' + System.currentTimeMillis())
|
||||
.setShortLabel(name)
|
||||
.setIcon(icon)
|
||||
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress()))
|
||||
.build();
|
||||
.setShortLabel(name)
|
||||
.setIcon(icon)
|
||||
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress()))
|
||||
.build();
|
||||
|
||||
if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null)) {
|
||||
Toast.makeText(context, getString(R.string.ConversationActivity_added_to_home_screen), Toast.LENGTH_LONG).show();
|
||||
@ -984,7 +977,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private void handleLeavePushGroup() {
|
||||
if (getRecipient() == null) {
|
||||
Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1052,7 +1045,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getThreadDatabase(ConversationActivity.this)
|
||||
.setDistributionType(threadId, DistributionTypes.BROADCAST);
|
||||
.setDistributionType(threadId, DistributionTypes.BROADCAST);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
@ -1068,7 +1061,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getThreadDatabase(ConversationActivity.this)
|
||||
.setDistributionType(threadId, DistributionTypes.CONVERSATION);
|
||||
.setDistributionType(threadId, DistributionTypes.CONVERSATION);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
@ -1100,7 +1093,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
/* Loki - We don't support SMS
|
||||
if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE);
|
||||
if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
|
||||
|
||||
if (!recipient.isPushGroupRecipient() && recipient.isForceSmsSelection()) {
|
||||
sendButton.setDefaultTransport(Type.SMS);
|
||||
} else {
|
||||
@ -1425,35 +1417,35 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
Log.i(TAG, "Selected: " + type);
|
||||
switch (type) {
|
||||
case AttachmentTypeSelector.ADD_GALLERY:
|
||||
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed()); break;
|
||||
case AttachmentTypeSelector.ADD_DOCUMENT:
|
||||
AttachmentManager.selectDocument(this, PICK_DOCUMENT); break;
|
||||
case AttachmentTypeSelector.ADD_SOUND:
|
||||
AttachmentManager.selectAudio(this, PICK_AUDIO); break;
|
||||
case AttachmentTypeSelector.ADD_CONTACT_INFO:
|
||||
AttachmentManager.selectContactInfo(this, PICK_CONTACT); break;
|
||||
case AttachmentTypeSelector.ADD_LOCATION:
|
||||
AttachmentManager.selectLocation(this, PICK_LOCATION); break;
|
||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||
case AttachmentTypeSelector.ADD_GIF:
|
||||
boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
|
||||
if (!hasSeenGIFMetaDataWarning) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Search GIFs?");
|
||||
builder.setMessage("You will not have full metadata protection when sending GIFs.");
|
||||
builder.setPositiveButton("OK", (dialog, which) -> {
|
||||
case AttachmentTypeSelector.ADD_GALLERY:
|
||||
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed()); break;
|
||||
case AttachmentTypeSelector.ADD_DOCUMENT:
|
||||
AttachmentManager.selectDocument(this, PICK_DOCUMENT); break;
|
||||
case AttachmentTypeSelector.ADD_SOUND:
|
||||
AttachmentManager.selectAudio(this, PICK_AUDIO); break;
|
||||
case AttachmentTypeSelector.ADD_CONTACT_INFO:
|
||||
AttachmentManager.selectContactInfo(this, PICK_CONTACT); break;
|
||||
case AttachmentTypeSelector.ADD_LOCATION:
|
||||
AttachmentManager.selectLocation(this, PICK_LOCATION); break;
|
||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||
case AttachmentTypeSelector.ADD_GIF:
|
||||
boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
|
||||
if (!hasSeenGIFMetaDataWarning) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Search GIFs?");
|
||||
builder.setMessage("You will not have full metadata protection when sending GIFs.");
|
||||
builder.setPositiveButton("OK", (dialog, which) -> {
|
||||
AttachmentManager.selectGif(this, PICK_GIF);
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
|
||||
builder.create().show();
|
||||
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
|
||||
} else {
|
||||
AttachmentManager.selectGif(this, PICK_GIF);
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
|
||||
builder.create().show();
|
||||
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
|
||||
} else {
|
||||
AttachmentManager.selectGif(this, PICK_GIF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1548,8 +1540,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
draftDatabase.insertDrafts(threadId, drafts);
|
||||
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
|
||||
drafts.getUriSnippet(),
|
||||
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
|
||||
drafts.getUriSnippet(),
|
||||
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
|
||||
} else if (threadId > 0) {
|
||||
threadDatabase.update(threadId, false);
|
||||
}
|
||||
@ -1652,10 +1644,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.US).format(new Date());
|
||||
String filename = String.format("signal-%s.txt", timestamp);
|
||||
Uri textUri = BlobProvider.getInstance()
|
||||
.forData(textData)
|
||||
.withMimeType(MediaTypes.LONG_TEXT)
|
||||
.withFileName(filename)
|
||||
.createForSingleSessionInMemory();
|
||||
.forData(textData)
|
||||
.withMimeType(MediaTypes.LONG_TEXT)
|
||||
.withFileName(filename)
|
||||
.createForSingleSessionInMemory();
|
||||
|
||||
textSlide = Optional.of(new TextSlide(this, textUri, filename, textData.length));
|
||||
}
|
||||
@ -1733,10 +1725,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize;
|
||||
boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
|
||||
// recipient.isGroupRecipient() ||
|
||||
inputPanel.getQuote().isPresent() ||
|
||||
linkPreviewViewModel.hasLinkPreview() ||
|
||||
LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
|
||||
needsSplit;
|
||||
inputPanel.getQuote().isPresent() ||
|
||||
linkPreviewViewModel.hasLinkPreview() ||
|
||||
LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
|
||||
needsSplit;
|
||||
|
||||
if (isMediaMessage) {
|
||||
sendMediaMessage(initiating);
|
||||
@ -1757,7 +1749,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private void sendMediaMessage(boolean initiating)
|
||||
throws InvalidMessageException
|
||||
throws InvalidMessageException
|
||||
{
|
||||
Log.i(TAG, "Sending media message...");
|
||||
sendMediaMessage(getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), linkPreviewViewModel.getActiveLinkPreview(), initiating);
|
||||
@ -1817,7 +1809,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private void sendTextMessage(final boolean initiating)
|
||||
throws InvalidMessageException
|
||||
throws InvalidMessageException
|
||||
{
|
||||
final Context context = getApplicationContext();
|
||||
final String messageBody = getMessage();
|
||||
@ -1895,10 +1887,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public void onRecorderPermissionRequired() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.RECORD_AUDIO)
|
||||
.withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48)
|
||||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages))
|
||||
.execute();
|
||||
.request(Manifest.permission.RECORD_AUDIO)
|
||||
.withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48)
|
||||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2057,16 +2049,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Permissions.with(ConversationActivity.this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_baseline_photo_camera_48)
|
||||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
|
||||
.onAllGranted(() -> {
|
||||
composeText.clearFocus();
|
||||
startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient), MEDIA_SENDER);
|
||||
overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
|
||||
})
|
||||
.onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
|
||||
.execute();
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_baseline_photo_camera_48)
|
||||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
|
||||
.onAllGranted(() -> {
|
||||
composeText.clearFocus();
|
||||
startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient), MEDIA_SENDER);
|
||||
overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
|
||||
})
|
||||
.onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2176,7 +2168,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
if (text.length() > 0) {
|
||||
if (currentMentionStartIndex > text.length()) {
|
||||
resetMentions(); // Should never occur
|
||||
resetMentions(); // Should never occur
|
||||
}
|
||||
int lastCharacterIndex = text.length() - 1;
|
||||
char lastCharacter = text.charAt(lastCharacterIndex);
|
||||
@ -2184,11 +2176,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (lastCharacterIndex > 0) {
|
||||
secondToLastCharacter = text.charAt(lastCharacterIndex - 1);
|
||||
}
|
||||
String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(ConversationActivity.this);
|
||||
LokiThreadDatabase threadDatabase = DatabaseFactory.getLokiThreadDatabase(ConversationActivity.this);
|
||||
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this);
|
||||
if (lastCharacter == '@' && Character.isWhitespace(secondToLastCharacter)) {
|
||||
List<Mention> mentionCandidates = MentionsManager.shared.getMentionCandidates("", threadId);
|
||||
List<Mention> mentionCandidates = MentionsManager.INSTANCE.getMentionCandidates("", threadId, recipient.isOpenGroupRecipient());
|
||||
currentMentionStartIndex = lastCharacterIndex;
|
||||
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
||||
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
||||
@ -2199,7 +2188,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
} else {
|
||||
if (currentMentionStartIndex != -1) {
|
||||
String query = text.substring(currentMentionStartIndex + 1); // + 1 to get rid of the @
|
||||
List<Mention> mentionCandidates = MentionsManager.shared.getMentionCandidates(query, threadId);
|
||||
List<Mention> mentionCandidates = MentionsManager.INSTANCE.getMentionCandidates(query, threadId, recipient.isOpenGroupRecipient());
|
||||
mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
|
||||
mentionCandidateSelectionView.show(mentionCandidates, threadId);
|
||||
}
|
||||
@ -2243,12 +2232,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
body,
|
||||
slideDeck,
|
||||
recipient,
|
||||
threadId);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
body,
|
||||
slideDeck,
|
||||
recipient,
|
||||
threadId);
|
||||
|
||||
} else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
|
||||
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
|
||||
@ -2259,26 +2248,26 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
slideDeck,
|
||||
recipient,
|
||||
threadId);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
slideDeck,
|
||||
recipient,
|
||||
threadId);
|
||||
} else {
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
|
||||
recipient,
|
||||
threadId);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
|
||||
recipient,
|
||||
threadId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageActionToolbarOpened() {
|
||||
searchViewItem.collapseActionView();
|
||||
searchViewItem.collapseActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2340,12 +2329,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private void updateTitleTextView(Recipient recipient) {
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(this);
|
||||
if (recipient == null) {
|
||||
titleTextView.setText("Compose");
|
||||
titleTextView.setText(R.string.ConversationActivity_compose);
|
||||
} else if (recipient.getAddress().toString().toLowerCase().equals(userPublicKey)) {
|
||||
titleTextView.setText(getResources().getString(R.string.note_to_self));
|
||||
titleTextView.setText(R.string.note_to_self);
|
||||
} else {
|
||||
boolean hasName = (recipient.getName() != null && !recipient.getName().isEmpty());
|
||||
titleTextView.setText(hasName ? recipient.getName() : recipient.getAddress().toString());
|
||||
String displayName = recipient.getName(); // Uses the Contact API internally
|
||||
boolean hasName = (displayName != null);
|
||||
titleTextView.setText(hasName ? displayName : recipient.getAddress().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2363,13 +2353,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
subtitleTextView.setVisibility(View.VISIBLE);
|
||||
if (recipient.isMuted()) {
|
||||
muteIndicatorImageView.setVisibility(View.VISIBLE);
|
||||
subtitleTextView.setText("Muted until " + DateUtils.getFormattedDateTime(recipient.mutedUntil, "EEE, MMM d, yyyy HH:mm", Locale.getDefault()));
|
||||
subtitleTextView.setText(getString(R.string.ConversationActivity_muted_until_date,DateUtils.getFormattedDateTime(recipient.mutedUntil, "EEE, MMM d, yyyy HH:mm", Locale.getDefault())));
|
||||
} else if (recipient.isGroupRecipient() && recipient.getName() != null && !recipient.getName().equals("Session Updates") && !recipient.getName().equals("Loki News")) {
|
||||
OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadId);
|
||||
if (openGroup != null) {
|
||||
Integer userCount = DatabaseFactory.getLokiAPIDatabase(this).getUserCount(openGroup.getRoom(),openGroup.getServer());
|
||||
if (userCount == null) { userCount = 0; }
|
||||
subtitleTextView.setText(userCount + " members");
|
||||
subtitleTextView.setText(getString(R.string.ConversationActivity_member_count,userCount));
|
||||
} else if (PublicKeyValidation.isValid(recipient.getAddress().toString())) {
|
||||
subtitleTextView.setText(recipient.getAddress().toString());
|
||||
} else {
|
||||
@ -2391,7 +2381,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private void updateMessageStatusProgressBar() {
|
||||
if (messageStatus != null) {
|
||||
messageStatusProgressBar.setAlpha(1.0f);
|
||||
messageStatusProgressBar.setAlpha(1.0f);
|
||||
switch (messageStatus) {
|
||||
case "calculatingPoW": setMessageStatusProgressAnimatedIfPossible(25); break;
|
||||
case "contactingNetwork": setMessageStatusProgressAnimatedIfPossible(50); break;
|
||||
@ -2428,7 +2418,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
default: return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@ import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.session.libsession.messaging.jobs.AttachmentDownloadJob;
|
||||
import org.session.libsession.messaging.jobs.JobQueue;
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupAPIV2;
|
||||
@ -889,7 +891,15 @@ public class ConversationItem extends LinearLayout
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) {
|
||||
if (groupThread && !messageRecord.isOutgoing()) {
|
||||
String displayName = recipient.toShortString();
|
||||
String sessionID = recipient.getAddress().serialize();
|
||||
Contact contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(sessionID);
|
||||
String displayName;
|
||||
if (contact != null) {
|
||||
Contact.ContactContext context = (this.conversationRecipient.isOpenGroupRecipient()) ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR;
|
||||
displayName = contact.displayName(context);
|
||||
} else {
|
||||
displayName = sessionID;
|
||||
}
|
||||
|
||||
this.groupSender.setText(displayName);
|
||||
|
||||
|
@ -17,11 +17,8 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import net.sqlcipher.database.SQLiteDatabase;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachmentProvider;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
|
||||
@ -34,6 +31,7 @@ import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionJobDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
|
||||
public class DatabaseFactory {
|
||||
|
||||
@ -55,16 +53,13 @@ public class DatabaseFactory {
|
||||
private final GroupReceiptDatabase groupReceiptDatabase;
|
||||
private final SearchDatabase searchDatabase;
|
||||
private final JobDatabase jobDatabase;
|
||||
|
||||
// Loki
|
||||
private final LokiAPIDatabase lokiAPIDatabase;
|
||||
private final LokiMessageDatabase lokiMessageDatabase;
|
||||
private final LokiThreadDatabase lokiThreadDatabase;
|
||||
private final LokiUserDatabase lokiUserDatabase;
|
||||
private final LokiBackupFilesDatabase lokiBackupFilesDatabase;
|
||||
private final SessionJobDatabase sessionJobDatabase;
|
||||
|
||||
// Refactor
|
||||
private final SessionContactDatabase sessionContactDatabase;
|
||||
private final Storage storage;
|
||||
private final DatabaseAttachmentProvider attachmentProvider;
|
||||
|
||||
@ -157,6 +152,10 @@ public class DatabaseFactory {
|
||||
public static SessionJobDatabase getSessionJobDatabase(Context context) {
|
||||
return getInstance(context).sessionJobDatabase;
|
||||
}
|
||||
|
||||
public static SessionContactDatabase getSessionContactDatabase(Context context) {
|
||||
return getInstance(context).sessionContactDatabase;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Refactor
|
||||
@ -202,6 +201,7 @@ public class DatabaseFactory {
|
||||
this.storage = new Storage(context, databaseHelper);
|
||||
this.attachmentProvider = new DatabaseAttachmentProvider(context, databaseHelper);
|
||||
this.sessionJobDatabase = new SessionJobDatabase(context, databaseHelper);
|
||||
this.sessionContactDatabase = new SessionContactDatabase(context, databaseHelper);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ public class RecipientDatabase extends Database {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SYSTEM_DISPLAY_NAME, profileName);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setName(profileName);
|
||||
recipient.resolve().setProfileName(profileName);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.net.Uri
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.messaging.jobs.*
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.signal.*
|
||||
import org.session.libsession.messaging.messages.signal.IncomingTextMessage
|
||||
@ -76,23 +77,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, newValue))
|
||||
}
|
||||
|
||||
override fun getProfileKeyForRecipient(recipientPublicKey: String): ByteArray? {
|
||||
val address = Address.fromSerialized(recipientPublicKey)
|
||||
val recipient = Recipient.from(context, address, false)
|
||||
return recipient.profileKey
|
||||
}
|
||||
|
||||
override fun getDisplayNameForRecipient(recipientPublicKey: String): String? {
|
||||
val database = DatabaseFactory.getLokiUserDatabase(context)
|
||||
return database.getDisplayName(recipientPublicKey)
|
||||
}
|
||||
|
||||
override fun setProfileKeyForRecipient(recipientPublicKey: String, profileKey: ByteArray) {
|
||||
val address = Address.fromSerialized(recipientPublicKey)
|
||||
val recipient = Recipient.from(context, address, false)
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileKey(recipient, profileKey)
|
||||
}
|
||||
|
||||
override fun getOrGenerateRegistrationID(): Int {
|
||||
var registrationID = TextSecurePreferences.getLocalRegistrationId(context)
|
||||
if (registrationID == 0) {
|
||||
@ -508,16 +492,16 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
return threadId
|
||||
}
|
||||
|
||||
override fun getDisplayName(publicKey: String): String? {
|
||||
return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
override fun getContactWithSessionID(sessionID: String): Contact? {
|
||||
return DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(sessionID)
|
||||
}
|
||||
|
||||
override fun setDisplayName(publicKey: String, newName: String) {
|
||||
DatabaseFactory.getLokiUserDatabase(context).setDisplayName(publicKey, newName)
|
||||
override fun getAllContacts(): Set<Contact> {
|
||||
return DatabaseFactory.getSessionContactDatabase(context).getAllContacts()
|
||||
}
|
||||
|
||||
override fun getProfilePictureURL(publicKey: String): String? {
|
||||
return DatabaseFactory.getLokiUserDatabase(context).getProfilePictureURL(publicKey)
|
||||
override fun setContact(contact: Contact) {
|
||||
DatabaseFactory.getSessionContactDatabase(context).setContact(contact)
|
||||
}
|
||||
|
||||
override fun getRecipientSettings(address: Address): Recipient.RecipientSettings? {
|
||||
|
@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.loki.database.LokiBackupFilesDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionJobDatabase;
|
||||
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsMigration;
|
||||
|
||||
@ -57,9 +58,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
private static final int lokiV23 = 44;
|
||||
private static final int lokiV24 = 45;
|
||||
private static final int lokiV25 = 46;
|
||||
private static final int lokiV26 = 47;
|
||||
|
||||
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||
private static final int DATABASE_VERSION = lokiV25;
|
||||
private static final int DATABASE_VERSION = lokiV26;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
@ -124,11 +126,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand());
|
||||
db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand());
|
||||
db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand());
|
||||
db.execSQL(LokiUserDatabase.getCreateServerDisplayNameTableCommand());
|
||||
db.execSQL(LokiBackupFilesDatabase.getCreateTableCommand());
|
||||
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
|
||||
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
|
||||
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
|
||||
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
|
||||
|
||||
executeStatements(db, SmsDatabase.CREATE_INDEXS);
|
||||
executeStatements(db, MmsDatabase.CREATE_INDEXS);
|
||||
@ -298,6 +300,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
|
||||
}
|
||||
|
||||
if (oldVersion < lokiV26) {
|
||||
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -31,6 +31,7 @@ import org.greenrobot.eventbus.ThreadMode
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.mentions.MentionsManager
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV2
|
||||
import org.session.libsession.utilities.*
|
||||
import org.session.libsignal.utilities.toHexString
|
||||
import org.session.libsignal.utilities.ThreadUtils
|
||||
@ -132,12 +133,8 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
})
|
||||
// Set up remaining components if needed
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
val apiDB = DatabaseFactory.getLokiAPIDatabase(this)
|
||||
val threadDB = DatabaseFactory.getLokiThreadDatabase(this)
|
||||
val userDB = DatabaseFactory.getLokiUserDatabase(this)
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(this)
|
||||
if (userPublicKey != null) {
|
||||
MentionsManager.configureIfNeeded(userPublicKey, userDB)
|
||||
OpenGroupManager.startPolling()
|
||||
JobQueue.shared.resumePendingJobs()
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import org.session.libsession.utilities.DistributionTypes
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsignal.utilities.PublicKeyValidation
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity
|
||||
@ -37,7 +38,6 @@ import org.thoughtcrime.securesms.loki.api.OpenGroupManager
|
||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
|
||||
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||
import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol
|
||||
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
||||
import org.thoughtcrime.securesms.loki.viewmodel.DefaultGroupsViewModel
|
||||
import org.thoughtcrime.securesms.loki.viewmodel.State
|
||||
|
||||
@ -86,6 +86,9 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
|
||||
val room = url.pathSegments().firstOrNull()
|
||||
val publicKey = url.queryParameter("public_key")
|
||||
val isV2OpenGroup = !room.isNullOrEmpty()
|
||||
if (isV2OpenGroup && (publicKey == null || !PublicKeyValidation.isValid(publicKey, 64,false))) {
|
||||
return Toast.makeText(this, R.string.invalid_public_key, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
showLoader()
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
|
@ -72,7 +72,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
setContentView(R.layout.activity_settings)
|
||||
val displayName = DatabaseFactory.getLokiUserDatabase(this).getDisplayName(hexEncodedPublicKey)
|
||||
val displayName = TextSecurePreferences.getProfileName(this) ?: hexEncodedPublicKey
|
||||
glide = GlideApp.with(this)
|
||||
profilePictureView.glide = glide
|
||||
profilePictureView.publicKey = hexEncodedPublicKey
|
||||
|
@ -278,14 +278,6 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLastMessageServerID(group: Long, server: String): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val index = "$server.$group"
|
||||
return database.get(lastMessageServerIDTable, "$lastMessageServerIDTableIndex = ?", wrap(index)) { cursor ->
|
||||
cursor.getInt(lastMessageServerID)
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun getLastMessageServerID(room: String, server: String): Long? {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$room"
|
||||
@ -294,13 +286,6 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun setLastMessageServerID(group: Long, server: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$group"
|
||||
val row = wrap(mapOf( lastMessageServerIDTableIndex to index, lastMessageServerID to newValue.toString() ))
|
||||
database.insertOrUpdate(lastMessageServerIDTable, row, "$lastMessageServerIDTableIndex = ?", wrap(index))
|
||||
}
|
||||
|
||||
override fun setLastMessageServerID(room: String, server: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$room"
|
||||
@ -308,26 +293,12 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
database.insertOrUpdate(lastMessageServerIDTable, row, "$lastMessageServerIDTableIndex = ?", wrap(index))
|
||||
}
|
||||
|
||||
fun removeLastMessageServerID(group: Long, server: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$group"
|
||||
database.delete(lastMessageServerIDTable,"$lastMessageServerIDTableIndex = ?", wrap(index))
|
||||
}
|
||||
|
||||
fun removeLastMessageServerID(room: String, server:String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$room"
|
||||
database.delete(lastMessageServerIDTable, "$lastMessageServerIDTableIndex = ?", wrap(index))
|
||||
}
|
||||
|
||||
override fun getLastDeletionServerID(group: Long, server: String): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val index = "$server.$group"
|
||||
return database.get(lastDeletionServerIDTable, "$lastDeletionServerIDTableIndex = ?", wrap(index)) { cursor ->
|
||||
cursor.getInt(lastDeletionServerID)
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun getLastDeletionServerID(room: String, server: String): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val index = "$server.$room"
|
||||
@ -336,13 +307,6 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun setLastDeletionServerID(group: Long, server: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$group"
|
||||
val row = wrap(mapOf( lastDeletionServerIDTableIndex to index, lastDeletionServerID to newValue.toString() ))
|
||||
database.insertOrUpdate(lastDeletionServerIDTable, row, "$lastDeletionServerIDTableIndex = ?", wrap(index))
|
||||
}
|
||||
|
||||
override fun setLastDeletionServerID(room: String, server: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$room"
|
||||
@ -392,32 +356,6 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
database.insertOrUpdate(userCountTable, row, "$publicChatID = ?", wrap(index))
|
||||
}
|
||||
|
||||
override fun getSessionRequestSentTimestamp(publicKey: String): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(sessionRequestSentTimestampTable, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) { cursor ->
|
||||
cursor.getLong(LokiAPIDatabase.timestamp)
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun setSessionRequestSentTimestamp(publicKey: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val row = wrap(mapOf( LokiAPIDatabase.publicKey to publicKey, LokiAPIDatabase.timestamp to newValue.toString() ))
|
||||
database.insertOrUpdate(sessionRequestSentTimestampTable, row, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey))
|
||||
}
|
||||
|
||||
override fun getSessionRequestProcessedTimestamp(publicKey: String): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(sessionRequestProcessedTimestampTable, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) { cursor ->
|
||||
cursor.getInt(LokiAPIDatabase.timestamp)
|
||||
}?.toLong()
|
||||
}
|
||||
|
||||
override fun setSessionRequestProcessedTimestamp(publicKey: String, newValue: Long) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val row = wrap(mapOf(LokiAPIDatabase.publicKey to publicKey, LokiAPIDatabase.timestamp to newValue.toString()))
|
||||
database.insertOrUpdate(sessionRequestProcessedTimestampTable, row, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey))
|
||||
}
|
||||
|
||||
override fun getOpenGroupPublicKey(server: String): String? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(openGroupPublicKeyTable, "${LokiAPIDatabase.server} = ?", wrap(server)) { cursor ->
|
||||
@ -431,27 +369,6 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
||||
database.insertOrUpdate(openGroupPublicKeyTable, row, "${LokiAPIDatabase.server} = ?", wrap(server))
|
||||
}
|
||||
|
||||
override fun getOpenGroupProfilePictureURL(group: Long, server: String): String? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
val index = "$server.$group"
|
||||
return database.get(openGroupProfilePictureTable, "$publicChatID = ?", wrap(index)) { cursor ->
|
||||
cursor.getString(openGroupProfilePicture)
|
||||
}?.toString()
|
||||
}
|
||||
|
||||
override fun setOpenGroupProfilePictureURL(group: Long, server: String, newValue: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$group"
|
||||
val row = wrap(mapOf(publicChatID to index, openGroupProfilePicture to newValue))
|
||||
database.insertOrUpdate(openGroupProfilePictureTable, row, "$publicChatID = ?", wrap(index))
|
||||
}
|
||||
|
||||
fun clearOpenGroupProfilePictureURL(group: Long, server: String): Boolean {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val index = "$server.$group"
|
||||
return database.delete(openGroupProfilePictureTable, "$publicChatID = ?", arrayOf(index)) > 0
|
||||
}
|
||||
|
||||
override fun getLastSnodePoolRefreshDate(): Date? {
|
||||
val time = TextSecurePreferences.getLastSnodePoolRefreshDate(context)
|
||||
if (time <= 0) { return null }
|
||||
|
@ -37,11 +37,6 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab
|
||||
|
||||
}
|
||||
|
||||
override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? {
|
||||
val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, quoteePublicKey)
|
||||
return if (message != null) getServerID(message.getId(), !message.isMms) else null
|
||||
}
|
||||
|
||||
fun getServerID(messageID: Long): Long? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(messageIDTable, "${Companion.messageID} = ?", arrayOf(messageID.toString())) { cursor ->
|
||||
|
@ -1,19 +1,12 @@
|
||||
package org.thoughtcrime.securesms.loki.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.utilities.get
|
||||
import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.database.LokiUserDatabaseProtocol
|
||||
|
||||
class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiUserDatabaseProtocol {
|
||||
class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
|
||||
|
||||
companion object {
|
||||
// Shared
|
||||
@ -28,7 +21,7 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database
|
||||
@JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($publicKey TEXT, $serverID TEXT, $displayName TEXT, PRIMARY KEY ($publicKey, $serverID));"
|
||||
}
|
||||
|
||||
override fun getDisplayName(publicKey: String): String? {
|
||||
fun getDisplayName(publicKey: String): String? {
|
||||
if (publicKey == TextSecurePreferences.getLocalNumber(context)) {
|
||||
return TextSecurePreferences.getProfileName(context)
|
||||
} else {
|
||||
@ -44,21 +37,4 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setDisplayName(publicKey: String, displayName: String) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val row = ContentValues(2)
|
||||
row.put(Companion.publicKey, publicKey)
|
||||
row.put(Companion.displayName, displayName)
|
||||
database.insertOrUpdate(displayNameTable, row, "${Companion.publicKey} = ?", arrayOf( publicKey ))
|
||||
Recipient.from(context, Address.fromSerialized(publicKey), false).notifyListeners()
|
||||
}
|
||||
|
||||
override fun getProfilePictureURL(publicKey: String): String? {
|
||||
return if (publicKey == TextSecurePreferences.getLocalNumber(context)) {
|
||||
TextSecurePreferences.getProfilePictureURL(context)
|
||||
} else {
|
||||
Recipient.from(context, Address.fromSerialized(publicKey), false).resolve().profileAvatar
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package org.thoughtcrime.securesms.loki.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import net.sqlcipher.Cursor
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.thoughtcrime.securesms.database.Database
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.loki.utilities.*
|
||||
|
||||
class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
|
||||
|
||||
companion object {
|
||||
private const val sessionContactTable = "session_contact_database"
|
||||
const val sessionID = "session_id"
|
||||
const val name = "name"
|
||||
const val nickname = "nickname"
|
||||
const val profilePictureURL = "profile_picture_url"
|
||||
const val profilePictureFileName = "profile_picture_file_name"
|
||||
const val profilePictureEncryptionKey = "profile_picture_encryption_key"
|
||||
const val threadID = "thread_id"
|
||||
const val isTrusted = "is_trusted"
|
||||
@JvmStatic val createSessionContactTableCommand =
|
||||
"CREATE TABLE $sessionContactTable " +
|
||||
"($sessionID STRING PRIMARY KEY, " +
|
||||
"$name TEXT DEFAULT NULL, " +
|
||||
"$nickname TEXT DEFAULT NULL, " +
|
||||
"$profilePictureURL TEXT DEFAULT NULL, " +
|
||||
"$profilePictureFileName TEXT DEFAULT NULL, " +
|
||||
"$profilePictureEncryptionKey BLOB DEFAULT NULL, " +
|
||||
"$threadID INTEGER DEFAULT -1, " +
|
||||
"$isTrusted INTEGER DEFAULT 0);"
|
||||
}
|
||||
|
||||
fun getContactWithSessionID(sessionID: String): Contact? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(sessionContactTable, "${SessionContactDatabase.sessionID} = ?", arrayOf( sessionID )) { cursor ->
|
||||
contactFromCursor(cursor)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllContacts(): Set<Contact> {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.getAll(sessionContactTable, null, null) { cursor ->
|
||||
contactFromCursor(cursor)
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
fun setContact(contact: Contact) {
|
||||
val database = databaseHelper.writableDatabase
|
||||
val contentValues = ContentValues(8)
|
||||
contentValues.put(sessionID, contact.sessionID)
|
||||
contentValues.put(name, contact.name)
|
||||
contentValues.put(nickname, contact.nickname)
|
||||
contentValues.put(profilePictureURL, contact.profilePictureURL)
|
||||
contentValues.put(profilePictureFileName, contact.profilePictureFileName)
|
||||
contact.profilePictureEncryptionKey?.let {
|
||||
contentValues.put(profilePictureEncryptionKey, Base64.encodeBytes(it))
|
||||
}
|
||||
contentValues.put(threadID, threadID)
|
||||
contentValues.put(isTrusted, if (contact.isTrusted) 1 else 0)
|
||||
database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf( contact.sessionID ))
|
||||
notifyConversationListListeners()
|
||||
}
|
||||
|
||||
private fun contactFromCursor(cursor: Cursor): Contact {
|
||||
val sessionID = cursor.getString(sessionID)
|
||||
val contact = Contact(sessionID)
|
||||
contact.name = cursor.getStringOrNull(name)
|
||||
contact.nickname = cursor.getStringOrNull(nickname)
|
||||
contact.profilePictureURL = cursor.getStringOrNull(profilePictureURL)
|
||||
contact.profilePictureFileName = cursor.getStringOrNull(profilePictureFileName)
|
||||
cursor.getStringOrNull(profilePictureEncryptionKey)?.let {
|
||||
contact.profilePictureEncryptionKey = Base64.decode(it)
|
||||
}
|
||||
contact.threadID = cursor.getLong(threadID)
|
||||
contact.isTrusted = cursor.getInt(isTrusted) != 0
|
||||
return contact
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.fragment_key_pair_migration_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
|
||||
class KeyPairMigrationBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_key_pair_migration_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
upgradeNowButton.setOnClickListener { upgradeNow() }
|
||||
upgradeLaterButton.setOnClickListener { upgradeLater() }
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.setOnShowListener {
|
||||
val d = dialog as BottomSheetDialog
|
||||
val bottomSheet = d.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)!!
|
||||
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
|
||||
BottomSheetBehavior.from(bottomSheet).isHideable = false
|
||||
}
|
||||
isCancelable = false
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun upgradeNow() {
|
||||
val applicationContext = requireContext().applicationContext as ApplicationContext
|
||||
applicationContext.clearAllData(true)
|
||||
}
|
||||
|
||||
private fun upgradeLater() {
|
||||
val dialog = AlertDialog.Builder(requireContext())
|
||||
dialog.setMessage("You won't be able to send or receive messages until you upgrade.")
|
||||
dialog.setPositiveButton(R.string.ok) { _, _ ->
|
||||
dismiss()
|
||||
}
|
||||
dialog.create().show()
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.Toast
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.android.synthetic.main.fragment_key_pair_migration_success_bottom_sheet.*
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
|
||||
class KeyPairMigrationSuccessBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
private val sessionID by lazy {
|
||||
TextSecurePreferences.getLocalNumber(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_key_pair_migration_success_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sessionIDTextView.text = sessionID
|
||||
copyButton.setOnClickListener { copySessionID() }
|
||||
okButton.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
// Expand the bottom sheet by default
|
||||
dialog.setOnShowListener {
|
||||
val d = dialog as BottomSheetDialog
|
||||
val bottomSheet = d.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
|
||||
BottomSheetBehavior.from(bottomSheet!!).setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun copySessionID() {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("Session ID", sessionID)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.loki.dialogs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
@ -8,14 +9,19 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.*
|
||||
import kotlinx.android.synthetic.main.view_conversation.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
|
||||
public class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_user_details_bottom_sheet, container, false)
|
||||
@ -24,11 +30,38 @@ public class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val publicKey = arguments?.getString("publicKey") ?: return dismiss()
|
||||
val recipient = Recipient.from(requireContext(), Address.fromSerialized(publicKey), false)
|
||||
profilePictureView.publicKey = publicKey
|
||||
profilePictureView.glide = GlideApp.with(this)
|
||||
profilePictureView.isLarge = true
|
||||
profilePictureView.update()
|
||||
nameTextView.text = DatabaseFactory.getLokiUserDatabase(requireContext()).getDisplayName(publicKey) ?: "Anonymous"
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameTextViewContainer.setOnClickListener {
|
||||
nameTextViewContainer.visibility = View.INVISIBLE
|
||||
nameEditTextContainer.visibility = View.VISIBLE
|
||||
nicknameEditText.text = null
|
||||
nicknameEditText.requestFocus()
|
||||
showSoftKeyboard()
|
||||
}
|
||||
cancelNicknameEditingButton.setOnClickListener {
|
||||
nicknameEditText.clearFocus()
|
||||
hideSoftKeyboard()
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameEditTextContainer.visibility = View.INVISIBLE
|
||||
}
|
||||
saveNicknameButton.setOnClickListener {
|
||||
saveNickName(recipient)
|
||||
}
|
||||
nicknameEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
when (actionId) {
|
||||
EditorInfo.IME_ACTION_DONE -> {
|
||||
saveNickName(recipient)
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
else -> return@setOnEditorActionListener false
|
||||
}
|
||||
}
|
||||
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
|
||||
publicKeyTextView.text = publicKey
|
||||
copyButton.setOnClickListener {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
@ -37,4 +70,32 @@ public class UserDetailsBottomSheet : BottomSheetDialogFragment() {
|
||||
Toast.makeText(requireContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun saveNickName(recipient: Recipient) {
|
||||
nicknameEditText.clearFocus()
|
||||
hideSoftKeyboard()
|
||||
nameTextViewContainer.visibility = View.VISIBLE
|
||||
nameEditTextContainer.visibility = View.INVISIBLE
|
||||
var newNickName: String? = null
|
||||
if (nicknameEditText.text.isNotEmpty()) {
|
||||
newNickName = nicknameEditText.text.toString()
|
||||
}
|
||||
val publicKey = recipient.address.serialize()
|
||||
val contactDB = DatabaseFactory.getSessionContactDatabase(context)
|
||||
val contact = contactDB.getContactWithSessionID(publicKey) ?: Contact(publicKey)
|
||||
contact.nickname = newNickName
|
||||
contactDB.setContact(contact)
|
||||
nameTextView.text = recipient.name ?: publicKey // Uses the Contact API internally
|
||||
}
|
||||
|
||||
@SuppressLint("ServiceCast")
|
||||
fun showSoftKeyboard() {
|
||||
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.showSoftInput(nicknameEditText, 0)
|
||||
}
|
||||
|
||||
fun hideSoftKeyboard() {
|
||||
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.hideSoftInputFromWindow(nicknameEditText.windowToken, 0)
|
||||
}
|
||||
}
|
@ -1,15 +1,8 @@
|
||||
package org.thoughtcrime.securesms.loki.protocol
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.messages.SignalServiceContent
|
||||
import org.session.libsignal.messages.SignalServiceDataMessage
|
||||
import java.security.MessageDigest
|
||||
|
||||
object SessionMetaProtocol {
|
||||
|
||||
@ -39,19 +32,6 @@ object SessionMetaProtocol {
|
||||
return shouldIgnoreMessage
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun handleProfileUpdateIfNeeded(context: Context, content: SignalServiceContent) {
|
||||
val displayName = content.senderDisplayName.orNull() ?: return
|
||||
if (displayName.isBlank()) { return }
|
||||
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val sender = content.sender.toLowerCase()
|
||||
if (userPublicKey == sender) {
|
||||
// Update the user's local name if the message came from their master device
|
||||
TextSecurePreferences.setProfileName(context, displayName)
|
||||
}
|
||||
DatabaseFactory.getLokiUserDatabase(context).setDisplayName(sender, displayName)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun canUserReplyToNotification(recipient: Recipient): Boolean {
|
||||
// TODO return !recipient.address.isRSSFeed
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.loki.utilities
|
||||
|
||||
import android.content.ContentValues
|
||||
import androidx.core.database.getStringOrNull
|
||||
import net.sqlcipher.Cursor
|
||||
import net.sqlcipher.database.SQLiteDatabase
|
||||
import org.session.libsignal.utilities.Base64
|
||||
@ -56,4 +57,8 @@ fun Cursor.getLong(columnName: String): Long {
|
||||
|
||||
fun Cursor.getBase64EncodedData(columnName: String): ByteArray {
|
||||
return Base64.decode(getString(columnName))
|
||||
}
|
||||
|
||||
fun Cursor.getStringOrNull(columnName: String): String? {
|
||||
return getStringOrNull(getColumnIndexOrThrow(columnName))
|
||||
}
|
@ -15,7 +15,7 @@ object MentionManagerUtilities {
|
||||
val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.address.toGroupString(), false).map { it.address.serialize() }
|
||||
result.addAll(members)
|
||||
} else {
|
||||
if (MentionsManager.shared.userPublicKeyCache[threadID] != null) { return }
|
||||
if (MentionsManager.userPublicKeyCache[threadID] != null) { return }
|
||||
val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context)
|
||||
val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID))
|
||||
var record: MessageRecord? = reader.next
|
||||
@ -30,6 +30,6 @@ object MentionManagerUtilities {
|
||||
reader.close()
|
||||
result.add(TextSecurePreferences.getLocalNumber(context)!!)
|
||||
}
|
||||
MentionsManager.shared.userPublicKeyCache[threadID] = result
|
||||
MentionsManager.userPublicKeyCache[threadID] = result
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import android.text.style.StyleSpan
|
||||
import android.util.Range
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.combine.Tuple2
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import java.util.regex.Pattern
|
||||
@ -23,6 +24,8 @@ object MentionUtilities {
|
||||
@JvmStatic
|
||||
fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, threadID: Long, context: Context): SpannableString {
|
||||
var text = text
|
||||
val threadDB = DatabaseFactory.getThreadDatabase(context)
|
||||
val isOpenGroup = threadDB.getRecipientForThreadId(threadID)?.isOpenGroupRecipient ?: false
|
||||
val pattern = Pattern.compile("@[0-9a-fA-F]*")
|
||||
var matcher = pattern.matcher(text)
|
||||
val mentions = mutableListOf<Tuple2<Range<Int>, String>>()
|
||||
@ -31,10 +34,12 @@ object MentionUtilities {
|
||||
if (matcher.find(startIndex)) {
|
||||
while (true) {
|
||||
val publicKey = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @
|
||||
val userDisplayName: String? = if (publicKey.toLowerCase() == userPublicKey.toLowerCase()) {
|
||||
val userDisplayName: String? = if (publicKey.equals(userPublicKey, ignoreCase = true)) {
|
||||
TextSecurePreferences.getProfileName(context)
|
||||
} else {
|
||||
DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
val contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(publicKey)
|
||||
val context = if (isOpenGroup) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR
|
||||
contact?.displayName(context)
|
||||
}
|
||||
if (userDisplayName != null) {
|
||||
text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length)
|
||||
|
@ -1,13 +0,0 @@
|
||||
@file:JvmName("NotificationUtilities")
|
||||
package org.thoughtcrime.securesms.loki.utilities
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
|
||||
fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String {
|
||||
val publicKey = recipient.address.toString()
|
||||
val displayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
// FIXME: Add short ID here?
|
||||
return displayName ?: publicKey
|
||||
}
|
@ -2,13 +2,15 @@ package org.thoughtcrime.securesms.loki.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_conversation.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded
|
||||
@ -56,7 +58,7 @@ class ConversationView : LinearLayout {
|
||||
}
|
||||
profilePictureView.glide = glide
|
||||
profilePictureView.update(thread.recipient, thread.threadId)
|
||||
val senderDisplayName = if (thread.recipient.isLocalNumber) context.getString(R.string.note_to_self) else if (!thread.recipient.name.isNullOrEmpty()) thread.recipient.name else thread.recipient.address.toString()
|
||||
val senderDisplayName = getUserDisplayName(thread.recipient) ?: thread.recipient.address.toString()
|
||||
btnGroupNameDisplay.text = senderDisplayName
|
||||
timestampTextView.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), thread.date)
|
||||
muteIndicatorImageView.visibility = if (thread.recipient.isMuted) VISIBLE else GONE
|
||||
@ -85,9 +87,12 @@ class ConversationView : LinearLayout {
|
||||
profilePictureView.recycle()
|
||||
}
|
||||
|
||||
private fun getUserDisplayName(publicKey: String?): String? {
|
||||
if (TextUtils.isEmpty(publicKey)) return null
|
||||
return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey!!)
|
||||
private fun getUserDisplayName(recipient: Recipient): String? {
|
||||
if (recipient.isLocalNumber) {
|
||||
return context.getString(R.string.note_to_self)
|
||||
} else {
|
||||
return recipient.name // Internally uses the Contact API
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -11,6 +11,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import kotlinx.android.synthetic.main.view_profile_picture.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.avatars.ProfileContactPhoto
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.mentions.MentionsManager
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
@ -57,19 +58,15 @@ class ProfilePictureView : RelativeLayout {
|
||||
|
||||
// region Updating
|
||||
fun update(recipient: Recipient, threadID: Long) {
|
||||
fun getUserDisplayName(publicKey: String?): String? {
|
||||
if (publicKey == null || publicKey.isBlank()) {
|
||||
return null
|
||||
} else {
|
||||
val result = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
return result ?: publicKey
|
||||
}
|
||||
fun getUserDisplayName(publicKey: String): String {
|
||||
val contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(publicKey)
|
||||
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
|
||||
}
|
||||
fun isOpenGroupWithProfilePicture(recipient: Recipient): Boolean {
|
||||
return recipient.isOpenGroupRecipient && recipient.groupAvatarId != null
|
||||
}
|
||||
if (recipient.isGroupRecipient && !isOpenGroupWithProfilePicture(recipient)) {
|
||||
val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toMutableList() ?: mutableListOf()
|
||||
val users = MentionsManager.userPublicKeyCache[threadID]?.toMutableList() ?: mutableListOf()
|
||||
users.remove(TextSecurePreferences.getLocalNumber(context))
|
||||
val randomUsers = users.sorted().toMutableList() // Sort to provide a level of stability
|
||||
if (users.count() == 1) {
|
||||
@ -86,7 +83,8 @@ class ProfilePictureView : RelativeLayout {
|
||||
recipient.name == "Session Updates" ||
|
||||
recipient.name == "Session Public Chat"
|
||||
} else {
|
||||
publicKey = recipient.address.toString()
|
||||
val publicKey = recipient.address.toString()
|
||||
this.publicKey = publicKey
|
||||
displayName = getUserDisplayName(publicKey)
|
||||
additionalPublicKey = null
|
||||
isRSSFeed = false
|
||||
|
@ -8,6 +8,7 @@ import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.view_conversation.view.profilePictureView
|
||||
import kotlinx.android.synthetic.main.view_user.view.*
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@ -48,13 +49,9 @@ class UserView : LinearLayout {
|
||||
|
||||
// region Updating
|
||||
fun bind(user: Recipient, glide: GlideRequests, actionIndicator: ActionIndicator, isSelected: Boolean = false) {
|
||||
fun getUserDisplayName(publicKey: String?): String? {
|
||||
if (publicKey == null || publicKey.isBlank()) {
|
||||
return null
|
||||
} else {
|
||||
val result = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
return result ?: publicKey
|
||||
}
|
||||
fun getUserDisplayName(publicKey: String): String {
|
||||
val contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(publicKey)
|
||||
return contact?.displayName(Contact.ContactContext.REGULAR) ?: publicKey
|
||||
}
|
||||
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(user)
|
||||
MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded(threadID, context) // FIXME: This is a bad place to do this
|
||||
|
@ -8,14 +8,14 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||
import org.thoughtcrime.securesms.loki.utilities.NotificationUtilities;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
import org.session.libsession.utilities.NotificationPrivacyPreference;
|
||||
import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -49,8 +49,15 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu
|
||||
|
||||
public void setMostRecentSender(Recipient recipient, Recipient threadRecipient) {
|
||||
String displayName = recipient.toShortString();
|
||||
if (threadRecipient.isGroupRecipient()) {
|
||||
displayName = NotificationUtilities.getOpenGroupDisplayName(recipient, threadRecipient, context);
|
||||
if (threadRecipient.isOpenGroupRecipient()) {
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(context);
|
||||
String sessionID = recipient.getAddress().serialize();
|
||||
Contact contact = contactDB.getContactWithSessionID(sessionID);
|
||||
if (contact != null) {
|
||||
displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP);
|
||||
} else {
|
||||
displayName = sessionID;
|
||||
}
|
||||
}
|
||||
if (privacy.isDisplayContact()) {
|
||||
setContentText(context.getString(R.string.MessageNotifier_most_recent_from_s, displayName));
|
||||
@ -71,8 +78,15 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu
|
||||
|
||||
public void addMessageBody(@NonNull Recipient sender, Recipient threadRecipient, @Nullable CharSequence body) {
|
||||
String displayName = sender.toShortString();
|
||||
if (threadRecipient.isGroupRecipient()) {
|
||||
displayName = NotificationUtilities.getOpenGroupDisplayName(sender, threadRecipient, context);
|
||||
if (threadRecipient.isOpenGroupRecipient()) {
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(context);
|
||||
String sessionID = sender.getAddress().serialize();
|
||||
Contact contact = contactDB.getContactWithSessionID(sessionID);
|
||||
if (contact != null) {
|
||||
displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP);
|
||||
} else {
|
||||
displayName = sessionID;
|
||||
}
|
||||
}
|
||||
if (privacy.isDisplayMessage()) {
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
|
@ -15,22 +15,21 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.SpannableStringBuilder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationCompat.Action;
|
||||
import androidx.core.app.RemoteInput;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.session.libsession.avatars.ContactColors;
|
||||
import org.session.libsession.avatars.ContactPhoto;
|
||||
import org.session.libsession.avatars.GeneratedContactPhoto;
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.session.libsignal.utilities.Log;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
|
||||
import org.thoughtcrime.securesms.loki.utilities.AvatarPlaceholderGenerator;
|
||||
import org.thoughtcrime.securesms.loki.utilities.NotificationUtilities;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
@ -40,11 +39,9 @@ import org.session.libsession.utilities.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
||||
@ -121,8 +118,16 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
||||
{
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
|
||||
if (privacy.isDisplayContact() && threadRecipients.isGroupRecipient()) {
|
||||
String displayName = NotificationUtilities.getOpenGroupDisplayName(individualRecipient, threadRecipients, context);
|
||||
if (privacy.isDisplayContact() && threadRecipients.isOpenGroupRecipient()) {
|
||||
String displayName;
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(context);
|
||||
String sessionID = individualRecipient.getAddress().serialize();
|
||||
Contact contact = contactDB.getContactWithSessionID(sessionID);
|
||||
if (contact != null) {
|
||||
displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP);
|
||||
} else {
|
||||
displayName = sessionID;
|
||||
}
|
||||
if (displayName != null) {
|
||||
stringBuilder.append(Util.getBoldedString(displayName + ": "));
|
||||
}
|
||||
@ -209,8 +214,16 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
||||
{
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
|
||||
if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) {
|
||||
String displayName = NotificationUtilities.getOpenGroupDisplayName(individualRecipient, threadRecipient, context);
|
||||
if (privacy.isDisplayContact() && threadRecipient.isOpenGroupRecipient()) {
|
||||
String displayName;
|
||||
SessionContactDatabase contactDB = DatabaseFactory.getSessionContactDatabase(context);
|
||||
String sessionID = individualRecipient.getAddress().serialize();
|
||||
Contact contact = contactDB.getContactWithSessionID(sessionID);
|
||||
if (contact != null) {
|
||||
displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP);
|
||||
} else {
|
||||
displayName = sessionID;
|
||||
}
|
||||
if (displayName != null) {
|
||||
stringBuilder.append(Util.getBoldedString(displayName + ": "));
|
||||
}
|
||||
|
@ -1,22 +1,70 @@
|
||||
package org.thoughtcrime.securesms.sskenvironment
|
||||
|
||||
import android.content.Context
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||
|
||||
class ProfileManager: SSKEnvironment.ProfileManagerProtocol {
|
||||
override fun setDisplayName(context: Context, recipient: Recipient, displayName: String) {
|
||||
DatabaseFactory.getLokiUserDatabase(context).setDisplayName(recipient.address.serialize(), displayName)
|
||||
class ProfileManager : SSKEnvironment.ProfileManagerProtocol {
|
||||
|
||||
override fun setNickname(context: Context, recipient: Recipient, nickname: String?) {
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
if (contact == null) contact = Contact(sessionID)
|
||||
contact.threadID = DatabaseFactory.getStorage(context).getThreadId(recipient.address)
|
||||
if (contact.nickname != nickname) {
|
||||
contact.nickname = nickname
|
||||
contactDatabase.setContact(contact)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setName(context: Context, recipient: Recipient, name: String) {
|
||||
// New API
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
if (contact == null) contact = Contact(sessionID)
|
||||
contact.threadID = DatabaseFactory.getStorage(context).getThreadId(recipient.address)
|
||||
if (contact.name != name) {
|
||||
contact.name = name
|
||||
contactDatabase.setContact(contact)
|
||||
}
|
||||
// Old API
|
||||
val database = DatabaseFactory.getRecipientDatabase(context)
|
||||
database.setProfileName(recipient, name)
|
||||
recipient.notifyListeners()
|
||||
}
|
||||
|
||||
override fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String) {
|
||||
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(recipient, profilePictureURL))
|
||||
val job = RetrieveProfileAvatarJob(recipient, profilePictureURL)
|
||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
if (contact == null) contact = Contact(sessionID)
|
||||
contact.threadID = DatabaseFactory.getStorage(context).getThreadId(recipient.address)
|
||||
if (contact.profilePictureURL != profilePictureURL) {
|
||||
contact.profilePictureURL = profilePictureURL
|
||||
contactDatabase.setContact(contact)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray) {
|
||||
// New API
|
||||
val sessionID = recipient.address.serialize()
|
||||
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
|
||||
var contact = contactDatabase.getContactWithSessionID(sessionID)
|
||||
if (contact == null) contact = Contact(sessionID)
|
||||
contact.threadID = DatabaseFactory.getStorage(context).getThreadId(recipient.address)
|
||||
if (!contact.profilePictureEncryptionKey.contentEquals(profileKey)) {
|
||||
contact.profilePictureEncryptionKey = profileKey
|
||||
contactDatabase.setContact(contact)
|
||||
}
|
||||
// Old API
|
||||
val database = DatabaseFactory.getRecipientDatabase(context)
|
||||
database.setProfileKey(recipient, profileKey)
|
||||
}
|
||||
|
@ -59,6 +59,6 @@
|
||||
android:background="@color/transparent"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:text="Link a Device" />
|
||||
android:text="@string/activity_link_device_link_device" />
|
||||
|
||||
</LinearLayout>
|
@ -19,7 +19,7 @@
|
||||
android:textSize="@dimen/very_large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Message Notifications" />
|
||||
android:text="@string/activity_pn_mode_message_notifications" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -29,7 +29,7 @@
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="There are two ways Session can notify you of new messages." />
|
||||
android:text="@string/activity_pn_mode_explanation" />
|
||||
|
||||
<org.thoughtcrime.securesms.loki.views.PNModeView
|
||||
android:id="@+id/fcmOptionView"
|
||||
@ -48,7 +48,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="Fast Mode" />
|
||||
android:text="@string/activity_pn_mode_fast_mode" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -56,7 +56,7 @@
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="You’ll be notified of new messages reliably and immediately using Google’s notification servers." />
|
||||
android:text="@string/activity_pn_mode_fast_mode_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -86,7 +86,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="Slow Mode" />
|
||||
android:text="@string/activity_pn_mode_slow_mode" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -94,7 +94,7 @@
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="Session will occasionally check for new messages in the background." />
|
||||
android:text="@string/activity_pn_mode_slow_mode_explanation" />
|
||||
|
||||
</org.thoughtcrime.securesms.loki.views.PNModeView>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@ -69,6 +70,7 @@
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textColorLink="?colorAccent"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy" /> <!-- Intentionally not yet translated -->
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||
tools:ignore="HardcodedText" /> <!-- Intentionally not yet translated -->
|
||||
|
||||
</LinearLayout>
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@ -38,7 +39,7 @@
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
@ -74,6 +75,7 @@
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textColorLink="?colorAccent"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy" /> <!-- Intentionally not yet translated -->
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||
tools:ignore="HardcodedText" /> <!-- Intentionally not yet translated -->
|
||||
|
||||
</LinearLayout>
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:textAlignment="center"
|
||||
android:text="nautical novelty populate onion awkward bent etiquette plant submarine itches vipers september axis maximum populate" />
|
||||
tools:text="nautical novelty populate onion awkward bent etiquette plant submarine itches vipers september axis maximum populate" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/revealButton"
|
||||
|
@ -18,7 +18,7 @@
|
||||
android:textSize="@dimen/very_large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Recovery Phrase" />
|
||||
android:text="@string/fragment_recovery_phrase_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -28,7 +28,7 @@
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="To link your device, enter the recovery phrase that was given to you when you signed up." />
|
||||
android:text="@string/activity_restore_explanation" />
|
||||
|
||||
<EditText
|
||||
style="@style/SessionEditText"
|
||||
|
@ -36,7 +36,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textStyle="bold"
|
||||
android:text="You're almost finished! 80%" />
|
||||
android:text="@string/view_seed_reminder_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitleTextView"
|
||||
@ -47,7 +47,7 @@
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:lines="2"
|
||||
android:alpha="0.6"
|
||||
android:text="Secure your account by saving your recovery phrase" />
|
||||
android:text="@string/view_seed_reminder_subtitle_1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textStyle="normal"
|
||||
android:text="Continue" />
|
||||
android:text="@string/continue_2" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -99,7 +99,8 @@
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||
android:textColor="@color/text"
|
||||
android:textColorLink="@color/text"
|
||||
android:textSize="@dimen/very_small_font_size" /> <!-- Intentionally not yet translated -->
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
tools:ignore="HardcodedText" /> <!-- Intentionally not yet translated -->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="64dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:text="Session"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/very_large_font_size" />
|
||||
|
||||
|
@ -59,6 +59,6 @@
|
||||
android:background="@color/transparent"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:text="Link a Device" />
|
||||
android:text="@string/activity_link_device_link_device" />
|
||||
|
||||
</LinearLayout>
|
@ -18,7 +18,7 @@
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Community Guidelines" />
|
||||
android:text="@string/ConversationActivity_open_group_guidelines" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/communityGuidelinesTextView"
|
||||
|
@ -19,7 +19,7 @@
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Message Notifications" />
|
||||
android:text="@string/activity_pn_mode_message_notifications" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -29,7 +29,7 @@
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="There are two ways Session can notify you of new messages." />
|
||||
android:text="@string/activity_pn_mode_explanation" />
|
||||
|
||||
<org.thoughtcrime.securesms.loki.views.PNModeView
|
||||
android:id="@+id/fcmOptionView"
|
||||
@ -48,7 +48,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="Fast Mode" />
|
||||
android:text="@string/activity_pn_mode_fast_mode" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -56,7 +56,7 @@
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="You’ll be notified of new messages reliably and immediately using Google’s notification servers." />
|
||||
android:text="@string/activity_pn_mode_fast_mode_explanation" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -86,7 +86,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:text="Slow Mode" />
|
||||
android:text="@string/activity_pn_mode_slow_mode" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@ -94,7 +94,7 @@
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="Session will occasionally check for new messages in the background." />
|
||||
android:text="@string/activity_pn_mode_slow_mode_explanation" />
|
||||
|
||||
</org.thoughtcrime.securesms.loki.views.PNModeView>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@ -69,6 +70,7 @@
|
||||
android:textColorLink="@color/text"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy" /> <!-- Intentionally not yet translated -->
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||
tools:ignore="HardcodedText" /> <!-- Intentionally not yet translated -->
|
||||
|
||||
</LinearLayout>
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
@ -35,11 +36,11 @@
|
||||
android:id="@+id/publicKeyTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18dp"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginLeft="@dimen/very_large_spacing"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="@dimen/very_large_spacing"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
@ -75,6 +76,7 @@
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textColorLink="?colorAccent"
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy" /> <!-- Intentionally not yet translated -->
|
||||
android:text="By using this service, you agree to our Terms of Service and Privacy Policy"
|
||||
tools:ignore="HardcodedText" /> <!-- Intentionally not yet translated -->
|
||||
|
||||
</LinearLayout>
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
android:gravity="center"
|
||||
android:textSize="14sp"
|
||||
android:textAlignment="center"
|
||||
android:text="nautical novelty populate onion awkward bent etiquette plant submarine itches vipers september axis maximum populate" />
|
||||
tools:text="nautical novelty populate onion awkward bent etiquette plant submarine itches vipers september axis maximum populate" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/revealButton"
|
||||
|
@ -76,7 +76,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:fontFamily="@font/space_mono_regular"
|
||||
android:textAlignment="center"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -211,7 +211,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:text="Help us Translate Session" />
|
||||
android:text="@string/activity_settings_help_translate_session" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/versionTextView"
|
||||
|
@ -13,7 +13,7 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="You don't have any contacts yet"
|
||||
android:text="@string/fragment_contact_selection_empty_contacts"
|
||||
android:textSize="@dimen/medium_font_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -55,9 +55,10 @@
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:text="Conversation"
|
||||
tools:text="Conversation"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:fontFamily="sans-serif-medium" />
|
||||
@ -83,7 +84,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:text="26 members"
|
||||
tools:text="26 members"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size" />
|
||||
|
||||
@ -217,7 +218,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:paddingStart="5dip"
|
||||
android:text="160/160 (1)"
|
||||
tools:text="160/160 (1)"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ViewStub
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@drawable/default_dialog_background_inset"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
@ -27,7 +27,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:padding="@dimen/small_spacing"
|
||||
android:text="habitat kiwi amply iceberg dog nerves spiderman soft match partial awakened maximum degrees"
|
||||
tools:text="habitat kiwi amply iceberg dog nerves spiderman soft match partial awakened maximum degrees"
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/contentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -60,7 +60,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:fontFamily="@font/space_mono_regular"
|
||||
android:textAlignment="center"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:padding="@dimen/large_spacing"
|
||||
app:behavior_hideable="false"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_shield"
|
||||
android:tint="?android:textColorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="Session IDs Just Got Better"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/large_font_size" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="We’ve upgraded Session IDs to make them even more private and secure. To ensure your continued privacy you're now required to upgrade."
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="Your existing contacts and conversations will be lost, but you’ll be able to use Session knowing you have the best privacy and security possible."
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.UnimportantOutline"
|
||||
android:id="@+id/upgradeNowButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/very_large_spacing"
|
||||
android:text="Upgrade Now" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.UnimportantOutline"
|
||||
android:id="@+id/upgradeLaterButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="Upgrade Later" />
|
||||
|
||||
</LinearLayout>
|
@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:padding="@dimen/large_spacing"
|
||||
app:behavior_hideable="true"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_shield"
|
||||
android:tint="?android:textColorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="Upgrade Successful!"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/large_font_size" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:text="Your new and improved Session ID is:"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textAlignment="center" />
|
||||
|
||||
<TextView
|
||||
style="@style/SessionIDTextView"
|
||||
android:id="@+id/sessionIDTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18dp"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.UnimportantOutline"
|
||||
android:id="@+id/copyButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/very_large_spacing"
|
||||
android:text="Copy" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.UnimportantOutline"
|
||||
android:id="@+id/okButton"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:text="@string/ok" />
|
||||
|
||||
</LinearLayout>
|
@ -18,7 +18,7 @@
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Recovery Phrase" />
|
||||
android:text="@string/fragment_recovery_phrase_title" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
|
@ -30,7 +30,7 @@
|
||||
android:layout_weight="1"
|
||||
android:padding="@dimen/very_large_spacing"
|
||||
android:gravity="center"
|
||||
android:text="Scan a user’s QR code to start a session. QR codes can be found by tapping the QR code icon in account settings."
|
||||
android:text="@string/activity_create_private_chat_scan_qr_code_explanation"
|
||||
android:background="?android:windowBackground"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="?android:textColorTertiary" />
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingLeft="@dimen/large_spacing"
|
||||
@ -16,27 +16,97 @@
|
||||
android:id="@+id/profilePictureView"
|
||||
android:layout_width="@dimen/large_profile_picture_size"
|
||||
android:layout_height="@dimen/large_profile_picture_size"
|
||||
android:layout_marginTop="@dimen/large_spacing" />
|
||||
android:layout_marginTop="@dimen/large_spacing"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTextView"
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:textSize="@dimen/massive_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:text="Spiderman" />
|
||||
android:gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/nameTextViewContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="visible">
|
||||
|
||||
<View
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="@dimen/small_spacing"
|
||||
android:layout_marginEnd="@dimen/small_spacing"
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text"
|
||||
android:textAlignment="center"
|
||||
android:text="Spiderman" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="22dp"
|
||||
android:paddingTop="2dp"
|
||||
android:src="@drawable/ic_baseline_edit_24" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/nameEditTextContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="invisible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cancelNicknameEditingButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_baseline_clear_24" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/nicknameEditText"
|
||||
style="@style/SmallSessionEditText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="@dimen/small_spacing"
|
||||
android:layout_marginEnd="@dimen/small_spacing"
|
||||
android:textAlignment="center"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:inputType="text"
|
||||
android:singleLine="true"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="@string/fragment_user_details_bottom_sheet_edit_text_hint" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/saveNicknameButton"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_baseline_done_24" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
style="@style/SessionIDTextView"
|
||||
android:id="@+id/publicKeyTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:layout_marginTop="@dimen/large_spacing"
|
||||
android:layout_marginTop="@dimen/medium_spacing"
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textIsSelectable="true"
|
||||
android:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
||||
|
@ -32,7 +32,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:textStyle="bold"
|
||||
android:textAlignment="center"
|
||||
android:text="Scan Me" />
|
||||
android:text="@string/fragment_view_my_qr_code_title" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -59,7 +59,7 @@
|
||||
android:textSize="@dimen/medium_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:textAlignment="center"
|
||||
android:text="This is your QR code. Other users can scan it to start a session with you." />
|
||||
android:text="@string/fragment_view_my_qr_code_explanation" />
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Session.Button.Common.UnimportantOutline"
|
||||
@ -68,7 +68,7 @@
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_marginBottom="@dimen/medium_spacing"
|
||||
android:text="Share" />
|
||||
android:text="@string/share" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Session is Locked"
|
||||
android:text="@string/activity_prompt_passphrase_session_locked"
|
||||
android:textStyle="bold"
|
||||
android:textSize="@dimen/large_font_size"
|
||||
android:textAlignment="center"
|
||||
@ -73,7 +73,6 @@
|
||||
android:id="@+id/lock_screen_auth_container"
|
||||
android:layout_width="196dp"
|
||||
android:layout_height="@dimen/medium_button_height"
|
||||
android:text="Tap to Unlock"/>
|
||||
|
||||
android:text="@string/activity_prompt_passphrase_tap_to_unlock"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
@ -23,7 +23,7 @@
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Share"
|
||||
android:text="@string/share"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:textSize="@dimen/very_large_font_size"
|
||||
android:layout_alignParentStart="true"
|
||||
|
@ -63,7 +63,7 @@
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="@color/text"
|
||||
android:alpha="0.4"
|
||||
android:text="9:41 AM" />
|
||||
tools:text="9:41 AM" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textStyle="bold"
|
||||
android:text="Pinned message" />
|
||||
android:text="@string/open_group_guidelines_pinned_message" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
@ -42,7 +42,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:maxLines="2"
|
||||
android:text="Community guidelines" />
|
||||
android:text="@string/open_group_guidelines_community_guidelines" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
android:layout_marginRight="12dp"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textStyle="normal"
|
||||
android:text="Read" />
|
||||
android:text="@string/open_group_guidelines_read" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
android:textColor="@color/text"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textStyle="bold"
|
||||
android:text="You're almost finished! 80%" />
|
||||
android:text="@string/view_seed_reminder_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitleTextView"
|
||||
@ -47,7 +47,7 @@
|
||||
android:textSize="@dimen/very_small_font_size"
|
||||
android:lines="2"
|
||||
android:alpha="0.6"
|
||||
android:text="Secure your account by saving your recovery phrase" />
|
||||
android:text="@string/view_seed_reminder_subtitle_1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:textStyle="normal"
|
||||
android:text="Continue" />
|
||||
android:text="@string/continue_2" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_filter_search"
|
||||
android:title=" "
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="collapseActionView|always" />
|
||||
android:id="@+id/action_filter_search"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="collapseActionView|always"
|
||||
android:title="" />
|
||||
|
||||
</menu>
|
@ -3,7 +3,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:title="Learn More"
|
||||
android:title="@string/activity_path_learn_more_button_title"
|
||||
android:id="@+id/learnMoreButton"
|
||||
android:icon="@drawable/ic_info_outline_white_24dp"
|
||||
app:showAsAction="always" />
|
||||
|
@ -73,6 +73,10 @@
|
||||
<string name="ConversationActivity_select_contact_info">Select contact info</string>
|
||||
<string name="ConversationActivity_sorry_there_was_an_error_setting_your_attachment">Sorry, there was an error setting your attachment.</string>
|
||||
<string name="ConversationActivity_message">Message</string>
|
||||
<string name="ConversationActivity_compose">Compose</string>
|
||||
<string name="ConversationActivity_muted_until_date">Muted until %1$s</string>
|
||||
<string name="ConversationActivity_member_count">%1$d members</string>
|
||||
<string name="ConversationActivity_open_group_guidelines">Community Guidelines</string>
|
||||
|
||||
<string name="ConversationActivity_invalid_recipient">Invalid recipient!</string>
|
||||
<string name="ConversationActivity_added_to_home_screen">Added to home screen</string>
|
||||
@ -419,6 +423,9 @@
|
||||
<!-- open_group_invitation_view -->
|
||||
<string name="open_group_invitation_view__join_accessibility_description">Join</string>
|
||||
<string name="open_group_invitation_view__open_group_invitation">Open group invitation</string>
|
||||
<string name="open_group_guidelines_pinned_message">Pinned message</string>
|
||||
<string name="open_group_guidelines_community_guidelines">Community guidelines</string>
|
||||
<string name="open_group_guidelines_read">Read</string>
|
||||
|
||||
<!-- QuoteView -->
|
||||
<string name="QuoteView_audio">Audio</string>
|
||||
@ -694,6 +701,7 @@
|
||||
<string name="activity_seed_explanation">Your recovery phrase is the master key to your Session ID — you can use it to restore your Session ID if you lose access to your device. Store your recovery phrase in a safe place, and don\'t give it to anyone.</string>
|
||||
<string name="activity_seed_reveal_button_title">Hold to reveal</string>
|
||||
|
||||
<string name="view_seed_reminder_title">You\'re almost finished! 80%</string>
|
||||
<string name="view_seed_reminder_subtitle_1">Secure your account by saving your recovery phrase</string>
|
||||
<string name="view_seed_reminder_subtitle_2">Tap and hold the redacted words to reveal your recovery phrase, then store it safely to secure your Session ID.</string>
|
||||
<string name="view_seed_reminder_subtitle_3">Make sure to store your recovery phrase in a safe place</string>
|
||||
@ -745,6 +753,7 @@
|
||||
<string name="activity_settings_invite_button_title">Invite</string>
|
||||
<string name="activity_settings_recovery_phrase_button_title">Recovery Phrase</string>
|
||||
<string name="activity_settings_clear_all_data_button_title">Clear Data</string>
|
||||
<string name="activity_settings_help_translate_session">Help us Translate Session</string>
|
||||
|
||||
<string name="activity_notification_settings_title">Notifications</string>
|
||||
<string name="activity_notification_settings_style_section_title">Notification Style</string>
|
||||
@ -769,6 +778,7 @@
|
||||
<string name="activity_qr_code_view_my_qr_code_tab_title">View My QR Code</string>
|
||||
<string name="activity_qr_code_view_scan_qr_code_tab_title">Scan QR Code</string>
|
||||
<string name="activity_qr_code_view_scan_qr_code_explanation">Scan someone\'s QR code to start a conversation with them</string>
|
||||
<string name="fragment_view_my_qr_code_title">Scan Me</string>
|
||||
|
||||
<string name="fragment_view_my_qr_code_explanation">This is your QR code. Other users can scan it to start a session with you.</string>
|
||||
<string name="fragment_view_my_qr_code_share_title">Share QR Code</string>
|
||||
@ -776,6 +786,7 @@
|
||||
<string name="fragment_contact_selection_contacts_title">Contacts</string>
|
||||
<string name="fragment_contact_selection_closed_groups_title">Closed Groups</string>
|
||||
<string name="fragment_contact_selection_open_groups_title">Open Groups</string>
|
||||
<string name="fragment_contact_selection_empty_contacts">You don\'t have any contacts yet</string>
|
||||
|
||||
<!-- Next round of translation -->
|
||||
|
||||
@ -813,8 +824,24 @@
|
||||
<string name="activity_backup_restore_select_file">Select a file</string>
|
||||
<string name="activity_backup_restore_explanation_1">Select a backup file and enter the passphrase it was created with.</string>
|
||||
<string name="activity_backup_restore_passphrase">30-digit passphrase</string>
|
||||
<!-- LinkDeviceActivity -->
|
||||
|
||||
<string name="activity_link_device_skip_prompt">This is taking a while, would you like to skip?</string>
|
||||
<string name="activity_link_device_link_device">Link a Device</string>
|
||||
<string name="activity_join_public_chat_join_rooms">Or join one of these…</string>
|
||||
|
||||
<string name="activity_pn_mode_message_notifications">Message Notifications</string>
|
||||
<string name="activity_pn_mode_explanation">There are two ways Session can notify you of new messages.</string>
|
||||
<string name="activity_pn_mode_fast_mode">Fast Mode</string>
|
||||
<string name="activity_pn_mode_slow_mode">Slow Mode</string>
|
||||
<string name="activity_pn_mode_fast_mode_explanation">You’ll be notified of new messages reliably and immediately using Google’s notification servers.</string>
|
||||
<string name="activity_pn_mode_slow_mode_explanation">Session will occasionally check for new messages in the background.</string>
|
||||
|
||||
<string name="fragment_recovery_phrase_title">Recovery Phrase</string>
|
||||
|
||||
<string name="activity_prompt_passphrase_session_locked">Session is Locked</string>
|
||||
<string name="activity_prompt_passphrase_tap_to_unlock">Tap to Unlock</string>
|
||||
|
||||
<string name="fragment_user_details_bottom_sheet_edit_text_hint">Enter a nickname</string>
|
||||
<string name="invalid_public_key">Invalid public key</string>
|
||||
|
||||
</resources>
|
||||
|
@ -137,7 +137,7 @@
|
||||
<style name="SessionIDTextView">
|
||||
<item name="android:background">@drawable/session_id_text_view_background</item>
|
||||
<item name="android:padding">@dimen/medium_spacing</item>
|
||||
<item name="android:textSize">@dimen/large_font_size</item>
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:textColor">@color/text</item>
|
||||
<item name="android:fontFamily">@font/space_mono_regular</item>
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
|
@ -140,6 +140,8 @@
|
||||
</style>
|
||||
|
||||
<style name="Theme.Session.BottomSheet" parent="@style/Theme.AppCompat.DayNight.Dialog">
|
||||
<item name="colorControlNormal">?android:textColorPrimary</item>
|
||||
<item name="android:textColorPrimary">@color/text</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation.MaterialComponents.BottomSheetDialog</item>
|
||||
<item name="bottomSheetStyle">@style/Widget.Session.BottomSheetDialog</item>
|
||||
|
@ -1,20 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Play Icon -->
|
||||
<string name="play_icon_upper_path_data">M 44 32 L 44 64 L 100 64 L 100 64 Z</string>
|
||||
<string name="play_icon_bottom_path_data">M 44 96 L 44 64 L 100 64 L 100 64 Z</string>
|
||||
<string name="play_icon_upper_path_data" translatable="false">M 44 32 L 44 64 L 100 64 L 100 64 Z</string>
|
||||
<string name="play_icon_bottom_path_data" translatable="false">M 44 96 L 44 64 L 100 64 L 100 64 Z</string>
|
||||
|
||||
<!-- Pause Icon -->
|
||||
<string name="pause_icon_upper_path_data">M 32 40 L 32 56 L 96 56 L 96 40 Z</string>
|
||||
<string name="pause_icon_bottom_path_data">M 32 88 L 32 72 L 96 72 L 96 88 Z</string>
|
||||
<string name="pause_icon_upper_path_data" translatable="false">M 32 40 L 32 56 L 96 56 L 96 40 Z</string>
|
||||
<string name="pause_icon_bottom_path_data" translatable="false">M 32 88 L 32 72 L 96 72 L 96 88 Z</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="play_icon_group_top">upperpart</string>
|
||||
<string name="play_icon_group_bottom">bottompart</string>
|
||||
<string name="play_icon_group_parts">parts</string>
|
||||
<string name="play_icon_group_top" translatable="false">upperpart</string>
|
||||
<string name="play_icon_group_bottom" translatable="false">bottompart</string>
|
||||
<string name="play_icon_group_parts" translatable="false">parts</string>
|
||||
|
||||
<!-- Path Name -->
|
||||
<string name="play_icon_top_path_name">upper</string>
|
||||
<string name="play_icon_bottom_path_name">bottom</string>
|
||||
<string name="play_icon_top_path_name" translatable="false">upper</string>
|
||||
<string name="play_icon_bottom_path_name" translatable="false">bottom</string>
|
||||
|
||||
</resources>
|
@ -2,6 +2,7 @@ package org.session.libsession.database
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||
import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.MessageReceiveJob
|
||||
@ -32,11 +33,7 @@ interface StorageProtocol {
|
||||
fun getUserDisplayName(): String?
|
||||
fun getUserProfileKey(): ByteArray?
|
||||
fun getUserProfilePictureURL(): String?
|
||||
fun setUserProfilePictureURL(newValue: String)
|
||||
fun getProfileKeyForRecipient(recipientPublicKey: String): ByteArray?
|
||||
fun getDisplayNameForRecipient(recipientPublicKey: String): String?
|
||||
fun setProfileKeyForRecipient(recipientPublicKey: String, profileKey: ByteArray)
|
||||
|
||||
fun setUserProfilePictureURL(newProfilePicture: String)
|
||||
// Signal
|
||||
fun getOrGenerateRegistrationID(): Int
|
||||
|
||||
@ -135,9 +132,9 @@ interface StorageProtocol {
|
||||
fun getLastUpdated(threadID: Long): Long
|
||||
|
||||
// Contacts
|
||||
fun getDisplayName(publicKey: String): String?
|
||||
fun setDisplayName(publicKey: String, newName: String)
|
||||
fun getProfilePictureURL(publicKey: String): String?
|
||||
fun getContactWithSessionID(sessionID: String): Contact?
|
||||
fun getAllContacts(): Set<Contact>
|
||||
fun setContact(contact: Contact)
|
||||
fun getRecipientSettings(address: Address): RecipientSettings?
|
||||
fun addContacts(contacts: List<ConfigurationMessage.Contact>)
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
package org.session.libsession.messaging.contacts
|
||||
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
|
||||
class Contact(val sessionID: String) {
|
||||
/**
|
||||
* The URL from which to fetch the contact's profile picture.
|
||||
*/
|
||||
var profilePictureURL: String? = null
|
||||
/**
|
||||
* The file name of the contact's profile picture on local storage.
|
||||
*/
|
||||
var profilePictureFileName: String? = null
|
||||
/**
|
||||
* The key with which the profile picture is encrypted.
|
||||
*/
|
||||
var profilePictureEncryptionKey: ByteArray? = null
|
||||
/**
|
||||
* The ID of the thread associated with this contact.
|
||||
*/
|
||||
var threadID: Long? = null
|
||||
/**
|
||||
* This flag is used to determine whether we should auto-download files sent by this contact.
|
||||
*/
|
||||
var isTrusted = false
|
||||
|
||||
// region Name
|
||||
/**
|
||||
* The name of the contact. Use this whenever you need the "real", underlying name of a user (e.g. when sending a message).
|
||||
*/
|
||||
var name: String? = null
|
||||
/**
|
||||
* The contact's nickname, if the user set one.
|
||||
*/
|
||||
var nickname: String? = null
|
||||
/**
|
||||
* The name to display in the UI. For local use only.
|
||||
*/
|
||||
fun displayName(context: ContactContext): String? {
|
||||
nickname?.let { return it }
|
||||
return when (context) {
|
||||
ContactContext.REGULAR -> name
|
||||
ContactContext.OPEN_GROUP -> {
|
||||
// In open groups, where it's more likely that multiple users have the same name,
|
||||
// we display a bit of the Session ID after a user's display name for added context.
|
||||
name?.let {
|
||||
return "$name (...${sessionID.takeLast(8)})"
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
enum class ContactContext {
|
||||
REGULAR, OPEN_GROUP
|
||||
}
|
||||
|
||||
fun isValid(): Boolean {
|
||||
if (profilePictureURL != null) { return profilePictureEncryptionKey != null }
|
||||
if (profilePictureEncryptionKey != null) { return profilePictureURL != null}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this.sessionID == (other as? Contact)?.sessionID
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return sessionID.hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return nickname ?: name ?: sessionID
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun contextForRecipient(recipient: Recipient): ContactContext {
|
||||
return if (recipient.isOpenGroupRecipient) {
|
||||
ContactContext.OPEN_GROUP
|
||||
} else {
|
||||
ContactContext.REGULAR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,11 @@
|
||||
package org.session.libsession.messaging.mentions
|
||||
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
|
||||
import org.session.libsignal.database.LokiUserDatabaseProtocol
|
||||
|
||||
class MentionsManager(private val userPublicKey: String, private val userDatabase: LokiUserDatabaseProtocol) {
|
||||
object MentionsManager {
|
||||
var userPublicKeyCache = mutableMapOf<Long, Set<String>>() // Thread ID to set of user hex encoded public keys
|
||||
|
||||
companion object {
|
||||
|
||||
public lateinit var shared: MentionsManager
|
||||
|
||||
public fun configureIfNeeded(userPublicKey: String, userDatabase: LokiUserDatabaseProtocol) {
|
||||
if (::shared.isInitialized) { return; }
|
||||
shared = MentionsManager(userPublicKey, userDatabase)
|
||||
}
|
||||
}
|
||||
|
||||
fun cache(publicKey: String, threadID: Long) {
|
||||
val cache = userPublicKeyCache[threadID]
|
||||
if (cache != null) {
|
||||
@ -26,14 +15,16 @@ class MentionsManager(private val userPublicKey: String, private val userDatabas
|
||||
}
|
||||
}
|
||||
|
||||
fun getMentionCandidates(query: String, threadID: Long): List<Mention> {
|
||||
// Prepare
|
||||
fun getMentionCandidates(query: String, threadID: Long, isOpenGroup: Boolean): List<Mention> {
|
||||
val cache = userPublicKeyCache[threadID] ?: return listOf()
|
||||
// Prepare
|
||||
val context = if (isOpenGroup) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
// Gather candidates
|
||||
var candidates: List<Mention> = cache.mapNotNull { publicKey ->
|
||||
val displayName = userDatabase.getDisplayName(publicKey)
|
||||
if (displayName == null) { return@mapNotNull null }
|
||||
if (displayName.startsWith("Anonymous")) { return@mapNotNull null }
|
||||
val contact = storage.getContactWithSessionID(publicKey)
|
||||
val displayName = contact?.displayName(context) ?: return@mapNotNull null
|
||||
Mention(publicKey, displayName)
|
||||
}
|
||||
candidates = candidates.filter { it.publicKey != userPublicKey }
|
||||
|
@ -13,8 +13,10 @@ import okhttp3.HttpUrl
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPollerV2
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
import org.session.libsession.utilities.AESGCM
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.HTTP
|
||||
import org.session.libsignal.utilities.HTTP.Verb.*
|
||||
import org.session.libsignal.utilities.removing05PrefixIfNeeded
|
||||
@ -30,6 +32,15 @@ object OpenGroupAPIV2 {
|
||||
private val moderators: HashMap<String, Set<String>> = hashMapOf() // Server URL to (channel ID to set of moderator IDs)
|
||||
private val curve = Curve25519.getInstance(Curve25519.BEST)
|
||||
val defaultRooms = MutableSharedFlow<List<DefaultGroup>>(replay = 1)
|
||||
private val hasPerformedInitialPoll = mutableMapOf<String, Boolean>()
|
||||
private var hasUpdatedLastOpenDate = false
|
||||
|
||||
private val timeSinceLastOpen by lazy {
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val lastOpenDate = TextSecurePreferences.getLastOpenTimeDate(context)
|
||||
val now = System.currentTimeMillis()
|
||||
now - lastOpenDate
|
||||
}
|
||||
|
||||
private const val defaultServerPublicKey = "a03c383cf63c3c4efe67acc52112a6dd734b3a946b9545f488aaa93da7991238"
|
||||
const val defaultServer = "http://116.203.70.33"
|
||||
@ -65,14 +76,14 @@ object OpenGroupAPIV2 {
|
||||
}
|
||||
|
||||
data class Request(
|
||||
val verb: HTTP.Verb,
|
||||
val room: String?,
|
||||
val server: String,
|
||||
val endpoint: String,
|
||||
val queryParameters: Map<String, String> = mapOf(),
|
||||
val parameters: Any? = null,
|
||||
val headers: Map<String, String> = mapOf(),
|
||||
val isAuthRequired: Boolean = true,
|
||||
val verb: HTTP.Verb,
|
||||
val room: String?,
|
||||
val server: String,
|
||||
val endpoint: String,
|
||||
val queryParameters: Map<String, String> = mapOf(),
|
||||
val parameters: Any? = null,
|
||||
val headers: Map<String, String> = mapOf(),
|
||||
val isAuthRequired: Boolean = true,
|
||||
/**
|
||||
* Always `true` under normal circumstances. You might want to disable
|
||||
* this when running over Lokinet.
|
||||
@ -349,6 +360,15 @@ object OpenGroupAPIV2 {
|
||||
fun compactPoll(rooms: List<String>, server: String): Promise<Map<String, CompactPollResult>, Exception> {
|
||||
val authTokenRequests = rooms.associateWith { room -> getAuthToken(room, server) }
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
val timeSinceLastOpen = this.timeSinceLastOpen
|
||||
val useMessageLimit = (hasPerformedInitialPoll[server] != true
|
||||
&& timeSinceLastOpen > OpenGroupPollerV2.maxInactivityPeriod)
|
||||
hasPerformedInitialPoll[server] = true
|
||||
if (!hasUpdatedLastOpenDate) {
|
||||
hasUpdatedLastOpenDate = true
|
||||
TextSecurePreferences.setLastOpenDate(context)
|
||||
}
|
||||
val requests = rooms.mapNotNull { room ->
|
||||
val authToken = try {
|
||||
authTokenRequests[room]?.get()
|
||||
@ -359,8 +379,8 @@ object OpenGroupAPIV2 {
|
||||
CompactPollRequest(
|
||||
roomID = room,
|
||||
authToken = authToken,
|
||||
fromDeletionServerID = storage.getLastDeletionServerID(room, server),
|
||||
fromMessageServerID = storage.getLastMessageServerID(room, server)
|
||||
fromDeletionServerID = if (useMessageLimit) null else storage.getLastDeletionServerID(room, server),
|
||||
fromMessageServerID = if (useMessageLimit) null else storage.getLastMessageServerID(room, server)
|
||||
)
|
||||
}
|
||||
val request = Request(verb = POST, room = null, server = server, endpoint = "compact_poll", isAuthRequired = false, parameters = mapOf( "requests" to requests ))
|
||||
|
@ -128,16 +128,20 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
|
||||
if (allV2OpenGroups.contains(openGroup)) continue
|
||||
storage.addOpenGroup(openGroup)
|
||||
}
|
||||
val profileManager = SSKEnvironment.shared.profileManager
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(userPublicKey), false)
|
||||
if (message.displayName.isNotEmpty()) {
|
||||
TextSecurePreferences.setProfileName(context, message.displayName)
|
||||
storage.setDisplayName(userPublicKey, message.displayName)
|
||||
profileManager.setName(context, recipient, message.displayName)
|
||||
}
|
||||
if (message.profileKey.isNotEmpty() && !message.profilePicture.isNullOrEmpty()
|
||||
&& TextSecurePreferences.getProfilePictureURL(context) != message.profilePicture) {
|
||||
val profileKey = Base64.encodeBytes(message.profileKey)
|
||||
ProfileKeyUtil.setEncodedProfileKey(context, profileKey)
|
||||
storage.setProfileKeyForRecipient(userPublicKey, message.profileKey)
|
||||
storage.setUserProfilePictureURL(message.profilePicture!!)
|
||||
profileManager.setProfileKey(context, recipient, message.profileKey)
|
||||
if (!message.profilePicture.isNullOrEmpty() && TextSecurePreferences.getProfilePictureURL(context) != message.profilePicture) {
|
||||
storage.setUserProfilePictureURL(message.profilePicture!!)
|
||||
}
|
||||
}
|
||||
storage.addContacts(message.contacts)
|
||||
}
|
||||
@ -162,9 +166,9 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
||||
if (profile != null && userPublicKey != message.sender) {
|
||||
val profileManager = SSKEnvironment.shared.profileManager
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false)
|
||||
val displayName = profile.displayName!!
|
||||
if (displayName.isNotEmpty()) {
|
||||
profileManager.setDisplayName(context, recipient, displayName)
|
||||
val name = profile.displayName!!
|
||||
if (name.isNotEmpty()) {
|
||||
profileManager.setName(context, recipient, name)
|
||||
}
|
||||
if (profile.profileKey?.isNotEmpty() == true && profile.profilePictureURL?.isNotEmpty() == true
|
||||
&& (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, profile.profileKey))) {
|
||||
|
@ -24,6 +24,7 @@ class OpenGroupPollerV2(private val server: String, private val executorService:
|
||||
|
||||
companion object {
|
||||
private val pollInterval: Long = 4 * 1000
|
||||
const val maxInactivityPeriod = 14 * 24 * 60 * 60 * 1000
|
||||
}
|
||||
|
||||
fun startIfNeeded() {
|
||||
|
@ -3,6 +3,7 @@ package org.session.libsession.messaging.utilities
|
||||
import android.content.Context
|
||||
import org.session.libsession.R
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
|
||||
import org.session.libsession.utilities.ExpirationUtil
|
||||
|
||||
@ -12,8 +13,9 @@ object UpdateMessageBuilder {
|
||||
var message = ""
|
||||
val updateData = updateMessageData.kind ?: return message
|
||||
if (!isOutgoing && sender == null) return message
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val senderName: String = if (!isOutgoing) {
|
||||
MessagingModuleConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender
|
||||
storage.getContactWithSessionID(sender!!)?.displayName(Contact.ContactContext.REGULAR) ?: sender
|
||||
} else { context.getString(R.string.MessageRecord_you) }
|
||||
|
||||
when (updateData) {
|
||||
@ -33,7 +35,7 @@ object UpdateMessageBuilder {
|
||||
}
|
||||
is UpdateMessageData.Kind.GroupMemberAdded -> {
|
||||
val members = updateData.updatedMembers.joinToString(", ") {
|
||||
MessagingModuleConfiguration.shared.storage.getDisplayNameForRecipient(it) ?: it
|
||||
storage.getContactWithSessionID(it)?.displayName(Contact.ContactContext.REGULAR) ?: it
|
||||
}
|
||||
message = if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_added_s_to_the_group, members)
|
||||
@ -54,7 +56,7 @@ object UpdateMessageBuilder {
|
||||
} else {
|
||||
// 2nd case: you are not part of the removed members
|
||||
val members = updateData.updatedMembers.joinToString(", ") {
|
||||
storage.getDisplayNameForRecipient(it) ?: it
|
||||
storage.getContactWithSessionID(it)?.displayName(Contact.ContactContext.REGULAR) ?: it
|
||||
}
|
||||
if (isOutgoing) {
|
||||
context.getString(R.string.MessageRecord_you_removed_s_from_the_group, members)
|
||||
@ -76,8 +78,9 @@ object UpdateMessageBuilder {
|
||||
|
||||
fun buildExpirationTimerMessage(context: Context, duration: Long, sender: String? = null, isOutgoing: Boolean = false): String {
|
||||
if (!isOutgoing && sender == null) return ""
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val senderName: String? = if (!isOutgoing) {
|
||||
MessagingModuleConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender
|
||||
storage.getContactWithSessionID(sender!!)?.displayName(Contact.ContactContext.REGULAR) ?: sender
|
||||
} else { context.getString(R.string.MessageRecord_you) }
|
||||
return if (duration <= 0) {
|
||||
if (isOutgoing) context.getString(R.string.MessageRecord_you_disabled_disappearing_messages)
|
||||
@ -90,7 +93,8 @@ object UpdateMessageBuilder {
|
||||
}
|
||||
|
||||
fun buildDataExtractionMessage(context: Context, kind: DataExtractionNotificationInfoMessage.Kind, sender: String? = null): String {
|
||||
val senderName = MessagingModuleConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val senderName = storage.getContactWithSessionID(sender!!)?.displayName(Contact.ContactContext.REGULAR) ?: sender!!
|
||||
return when (kind) {
|
||||
DataExtractionNotificationInfoMessage.Kind.SCREENSHOT ->
|
||||
context.getString(R.string.MessageRecord_s_took_a_screenshot, senderName)
|
||||
|
@ -29,7 +29,8 @@ class SSKEnvironment(
|
||||
const val NAME_PADDED_LENGTH = 26
|
||||
}
|
||||
|
||||
fun setDisplayName(context: Context, recipient: Recipient, displayName: String)
|
||||
fun setNickname(context: Context, recipient: Recipient, nickname: String?)
|
||||
fun setName(context: Context, recipient: Recipient, name: String)
|
||||
fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String)
|
||||
fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray)
|
||||
fun setUnidentifiedAccessMode(context: Context, recipient: Recipient, unidentifiedAccessMode: Recipient.UnidentifiedAccessMode)
|
||||
|
@ -99,16 +99,16 @@ object TextSecurePreferences {
|
||||
|
||||
private const val GIF_GRID_LAYOUT = "pref_gif_grid_layout"
|
||||
|
||||
// region FCM
|
||||
const val IS_USING_FCM = "pref_is_using_fcm"
|
||||
private const val FCM_TOKEN = "pref_fcm_token"
|
||||
private const val LAST_FCM_TOKEN_UPLOAD_TIME = "pref_last_fcm_token_upload_time_2"
|
||||
|
||||
// region Multi Device
|
||||
private const val LAST_CONFIGURATION_SYNC_TIME = "pref_last_configuration_sync_time"
|
||||
const val CONFIGURATION_SYNCED = "pref_configuration_synced"
|
||||
private const val LAST_PROFILE_UPDATE_TIME = "pref_last_profile_update_time"
|
||||
|
||||
private const val LAST_OPEN_DATE = "pref_last_open_date"
|
||||
|
||||
@JvmStatic
|
||||
fun getLastConfigurationSyncTime(context: Context): Long {
|
||||
return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0)
|
||||
@ -764,12 +764,19 @@ object TextSecurePreferences {
|
||||
fun shouldUpdateProfile(context: Context, profileUpdateTime: Long) =
|
||||
profileUpdateTime > getLongPreference(context, LAST_PROFILE_UPDATE_TIME, 0)
|
||||
|
||||
fun hasSeenFileServerInstabilityNotification(context: Context): Boolean {
|
||||
return getBooleanPreference(context, "has_seen_file_server_instability_notification", false)
|
||||
fun hasPerformedContactMigration(context: Context): Boolean {
|
||||
return getBooleanPreference(context, "has_performed_contact_migration", false)
|
||||
}
|
||||
|
||||
fun setHasSeenFileServerInstabilityNotification(context: Context) {
|
||||
setBooleanPreference(context, "has_seen_file_server_instability_notification", true)
|
||||
fun setPerformedContactMigration(context: Context) {
|
||||
setBooleanPreference(context, "has_performed_contact_migration", true)
|
||||
}
|
||||
|
||||
fun getLastOpenTimeDate(context: Context): Long {
|
||||
return getLongPreference(context, LAST_OPEN_DATE, 0)
|
||||
}
|
||||
|
||||
fun setLastOpenDate(context: Context) {
|
||||
setLongPreference(context, LAST_OPEN_DATE, System.currentTimeMillis())
|
||||
}
|
||||
// endregion
|
||||
}
|
@ -26,10 +26,13 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.function.Consumer;
|
||||
import com.esotericsoftware.kryo.util.Null;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.session.libsession.database.StorageProtocol;
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration;
|
||||
import org.session.libsession.avatars.TransparentContactPhoto;
|
||||
import org.session.libsession.messaging.contacts.Contact;
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsession.utilities.GroupRecord;
|
||||
import org.session.libsession.utilities.recipients.RecipientProvider.RecipientDetails;
|
||||
@ -286,20 +289,23 @@ public class Recipient implements RecipientModifiedListener {
|
||||
}
|
||||
|
||||
public synchronized @Nullable String getName() {
|
||||
String displayName = MessagingModuleConfiguration.shared.getStorage().getDisplayName(this.address.toString());
|
||||
if (displayName != null) { return displayName; }
|
||||
|
||||
if (this.name == null && isGroupRecipient()) {
|
||||
List<String> names = new LinkedList<>();
|
||||
|
||||
for (Recipient recipient : participants) {
|
||||
names.add(recipient.toShortString());
|
||||
StorageProtocol storage = MessagingModuleConfiguration.shared.getStorage();
|
||||
String sessionID = this.address.toString();
|
||||
if (isGroupRecipient()) {
|
||||
if (this.name == null) {
|
||||
List<String> names = new LinkedList<>();
|
||||
for (Recipient recipient : participants) {
|
||||
names.add(recipient.toShortString());
|
||||
}
|
||||
return Util.join(names, ", ");
|
||||
} else {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
return Util.join(names, ", ");
|
||||
} else {
|
||||
Contact contact = storage.getContactWithSessionID(sessionID);
|
||||
if (contact == null) { return sessionID; }
|
||||
return contact.displayName(Contact.ContactContext.REGULAR);
|
||||
}
|
||||
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(@Nullable String name) {
|
||||
|
@ -1,441 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Session -->
|
||||
<style name="Widget.Session.ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid">
|
||||
<item name="android:background">?colorPrimary</item>
|
||||
<item name="elevation">1dp</item>
|
||||
<item name="titleTextStyle">@style/TextAppearance.Session.DarkActionBar.TitleTextStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.ActionBar.Flat">
|
||||
<item name="android:elevation">0dp</item>
|
||||
<item name="elevation">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Session.DarkActionBar.TitleTextStyle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:textSize">@dimen/very_large_font_size</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.SearchView" parent="@style/Widget.AppCompat.SearchView">
|
||||
<item name="closeIcon">@drawable/ic_clear</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.Session.AlertDialog" parent="ThemeOverlay.AppCompat.Dialog.Alert">
|
||||
<item name="buttonBarNegativeButtonStyle">@style/Widget.Session.AlertDialog.NegativeButtonStyle</item>
|
||||
<item name="buttonBarPositiveButtonStyle">@style/Widget.Session.AlertDialog.PositiveButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.BottomSheetDialog" parent="Widget.Design.BottomSheet.Modal">
|
||||
<item name="android:background">@drawable/default_bottom_sheet_background</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.AlertDialog.NegativeButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
|
||||
<item name="android:textColor">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.AlertDialog.PositiveButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
|
||||
<item name="android:textColor">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.AppBarLayout" parent="@style/Widget.Design.AppBarLayout">
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.TabBar" parent="Widget.AppCompat.ActionBar.TabBar">
|
||||
<item name="elevation">1dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.TabLayout" parent="Widget.Design.TabLayout">
|
||||
<item name="elevation">1dp</item>
|
||||
<item name="tabIndicatorColor">?colorAccent</item>
|
||||
<item name="tabSelectedTextColor">?colorAccent</item>>
|
||||
<item name="tabIndicatorHeight">@dimen/accent_line_thickness</item>
|
||||
<item name="tabRippleColor">@color/cell_selected</item>
|
||||
<item name="tabTextAppearance">@style/TextAppearance.Session.Tab</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Session.Tab" parent="TextAppearance.Design.Tab">
|
||||
<item name="android:textSize">@dimen/medium_font_size</item>
|
||||
<item name="textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<!-- TODO These button styles require proper background selectors for up/down visual state. -->
|
||||
<style name="Widget.Session.Button.Common" parent="">
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">@dimen/medium_font_size</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<!-- Helps to get rid of nasty elevation. We want a flat style here. -->
|
||||
<!-- https://stackoverflow.com/a/31003693/3802890 -->
|
||||
<item name ="android:stateListAnimator">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Common.ProminentFilled">
|
||||
<item name="android:background">@drawable/prominent_filled_button_medium_background</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:drawableTint" tools:ignore="NewApi">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Common.ProminentOutline">
|
||||
<item name="android:background">@drawable/prominent_outline_button_medium_background</item>
|
||||
<item name="android:textColor">@color/accent</item>
|
||||
<item name="android:drawableTint" tools:ignore="NewApi">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Common.UnimportantFilled">
|
||||
<item name="android:background">@drawable/unimportant_filled_button_medium_background</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:drawableTint" tools:ignore="NewApi">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Common.UnimportantOutline">
|
||||
<item name="android:background">@drawable/unimportant_outline_button_medium_background</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:drawableTint" tools:ignore="NewApi">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Dialog" parent="">
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">@dimen/small_font_size</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Dialog.Unimportant">
|
||||
<item name="android:background">@drawable/unimportant_dialog_button_background</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Dialog.Prominent">
|
||||
<item name="android:background">@drawable/prominent_dialog_button_background</item>
|
||||
<item name="android:textColor">#222</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.Button.Dialog.Destructive">
|
||||
<item name="android:background">@drawable/destructive_dialog_button_background</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Session.EditText.Compose" parent="@style/Signal.Text.Body">
|
||||
<item name="android:padding">2dp</item>
|
||||
<item name="android:background">@null</item>
|
||||
<item name="android:maxLines">4</item>
|
||||
<item name="android:maxLength">65536</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:capitalize">sentences</item>
|
||||
<item name="android:autoText">true</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:imeOptions">flagNoEnterAction</item>
|
||||
<item name="android:inputType">textAutoCorrect|textCapSentences|textMultiLine</item>
|
||||
<item name="android:contentDescription">@string/conversation_activity__compose_description</item>
|
||||
<item name="android:textColorHint">?android:textColorHint</item>
|
||||
<item name="android:textSize">@dimen/small_font_size</item>
|
||||
<item name="android:textCursorDrawable">@drawable/session_edit_text_cursor</item>
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.Session.Settings" parent="PreferenceThemeOverlay.v14.Material" >
|
||||
<item name="android:textColor">@color/text</item>
|
||||
<item name="android:textColorSecondary">#99FFFFFF</item>
|
||||
<item name="android:textSize">@dimen/medium_font_size</item>
|
||||
</style>
|
||||
|
||||
<style name="SessionIDTextView">
|
||||
<item name="android:background">@drawable/session_id_text_view_background</item>
|
||||
<item name="android:padding">@dimen/medium_spacing</item>
|
||||
<item name="android:textSize">@dimen/large_font_size</item>
|
||||
<item name="android:textColor">@color/text</item>
|
||||
<item name="android:fontFamily">@font/space_mono_regular</item>
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
</style>
|
||||
|
||||
<style name="SessionEditText">
|
||||
<item name="android:background">@drawable/session_id_text_view_background</item>
|
||||
<item name="android:paddingLeft">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingTop">30dp</item>
|
||||
<item name="android:paddingRight">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingBottom">30dp</item>
|
||||
<item name="android:textSize">@dimen/small_font_size</item>
|
||||
<item name="android:textColor">@color/text</item>
|
||||
<item name="android:textCursorDrawable">@drawable/session_edit_text_cursor</item>
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
</style>
|
||||
|
||||
<style name="SmallSessionEditText">
|
||||
<item name="android:background">@drawable/session_id_text_view_background</item>
|
||||
<item name="android:paddingLeft">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingTop">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingRight">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingBottom">@dimen/medium_spacing</item>
|
||||
<item name="android:textSize">@dimen/small_font_size</item>
|
||||
<item name="android:textColor">@color/text</item>
|
||||
<item name="android:textCursorDrawable">@drawable/session_edit_text_cursor</item>
|
||||
<item name="android:textAlignment">viewStart</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
</style>
|
||||
|
||||
<style name="FakeChatViewMessageBubble">
|
||||
<item name="android:paddingLeft">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingRight">@dimen/medium_spacing</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:fontFamily">sans-serif-medium</item>
|
||||
<item name="android:elevation">0dp</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="FakeChatViewMessageBubble.Incoming">
|
||||
<item name="android:background">@drawable/fake_chat_view_incoming_message_background</item>
|
||||
<item name="android:elevation">10dp</item>
|
||||
</style>
|
||||
|
||||
<style name="FakeChatViewMessageBubble.Outgoing">
|
||||
<item name="android:background">@drawable/fake_chat_view_outgoing_message_background</item>
|
||||
<item name="android:elevation">10dp</item>
|
||||
</style>
|
||||
<!-- Session -->
|
||||
|
||||
<style name="NoAnimation.Theme.BlackScreen" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
<item name="android:windowBackground">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="NoAnimation.Theme.AppCompat.Light.DarkActionBar" parent="@style/Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DialogActivity" parent="Theme.AppCompat.Light">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AppCompatAlertDialogStyleLight" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||
<item name="colorAccent">@color/signal_primary_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppCompatAlertDialogStyleDark" parent="Theme.AppCompat.Dialog.Alert">
|
||||
<item name="colorAccent">@color/signal_primary</item>
|
||||
<item name="android:textColor">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="AppCompatDialogStyleLight" parent="Theme.AppCompat.Light.Dialog">
|
||||
<item name="colorAccent">@color/signal_primary_dark</item>
|
||||
<item name="android:windowBackground">@drawable/dialog_background</item>
|
||||
</style>
|
||||
|
||||
<style name="AppCompatDialogStyleDark" parent="Theme.AppCompat.Dialog">
|
||||
<item name="colorAccent">@color/signal_primary</item>
|
||||
<item name="android:windowBackground">@drawable/dialog_background</item>
|
||||
<item name="android:textColor">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- ActionBar styles -->
|
||||
<style name="TextSecure.DarkActionBar"
|
||||
parent="@style/Widget.AppCompat.ActionBar">
|
||||
<item name="background">@color/core_grey_90</item>
|
||||
<item name="android:popupTheme" tools:ignore="NewApi">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
<item name="elevation">1dp</item>
|
||||
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
<item name="titleTextStyle">@style/TextSecure.TitleTextStyle</item>
|
||||
<item name="subtitleTextStyle">@style/TextSecure.SubtitleTextStyle</item>
|
||||
<item name="android:textColorSecondary">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightActionBar"
|
||||
parent="@style/Widget.AppCompat.ActionBar">
|
||||
<item name="background">@color/textsecure_primary</item>
|
||||
<item name="elevation">1dp</item>
|
||||
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Light</item>
|
||||
<item name="titleTextStyle">@style/TextSecure.TitleTextStyle</item>
|
||||
<item name="subtitleTextStyle">@style/TextSecure.SubtitleTextStyle</item>
|
||||
<item name="android:textColorPrimary">@color/white</item>
|
||||
<item name="android:textColorSecondary">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightActionBar.DarkText"
|
||||
parent="TextSecure.LightActionBar">
|
||||
<item name="android:textColorPrimary">@color/black</item>
|
||||
<item name="android:textColorSecondary">@color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.FlatLightActionBar"
|
||||
parent="@style/TextSecure.LightActionBar">
|
||||
<item name="elevation">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkActionBar.TabBar"
|
||||
parent="@style/Widget.AppCompat.ActionBar.TabBar">
|
||||
<item name="background">@color/gray95</item>
|
||||
<item name="android:background">@color/gray95</item>
|
||||
<item name="elevation">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightActionBar.TabBar"
|
||||
parent="@style/Widget.AppCompat.ActionBar.TabBar">
|
||||
<item name="android:background">@color/textsecure_primary</item>
|
||||
<item name="background">@color/textsecure_primary</item>
|
||||
<item name="android:textColorPrimary">@color/white</item>
|
||||
<item name="android:textColorSecondary">#BFffffff</item>
|
||||
<item name="elevation">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.TitleTextStyle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:textColorHint">#BFffffff</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.SubtitleTextStyle" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
|
||||
<item name="android:textColor">#BFffffff</item>
|
||||
</style>
|
||||
|
||||
<style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
<style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title">
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
</style>
|
||||
|
||||
<style name="Registration.Description" parent="@android:style/TextAppearance">
|
||||
<item name="android:textSize">16.0sp</item>
|
||||
<item name="android:typeface">sans</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:shadowColor">#ffffff</item>
|
||||
<item name="android:shadowDx">1.0</item>
|
||||
<item name="android:shadowDy">1.0</item>
|
||||
<item name="android:shadowRadius">0.0</item>
|
||||
<item name="android:lineSpacingMultiplier">1.25</item>
|
||||
</style>
|
||||
|
||||
<style name="Registration.Label" parent="@android:style/TextAppearance">
|
||||
<item name="android:textSize">12.0sp</item>
|
||||
<item name="android:typeface">sans</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#ff808080</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:layout_gravity">left</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:shadowColor">#ffffff</item>
|
||||
<item name="android:shadowDx">1.0</item>
|
||||
<item name="android:shadowDy">1.0</item>
|
||||
<item name="android:shadowRadius">0.0</item>
|
||||
<item name="android:lineSpacingMultiplier">1.25</item>
|
||||
</style>
|
||||
|
||||
<style name="Registration.BigLabel" parent="@style/Registration.Label">
|
||||
<item name="android:textSize">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="Registration.Constant" parent="@android:style/TextAppearance">
|
||||
<item name="android:typeface">sans</item>
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#ff808080</item>
|
||||
<item name="android:shadowColor">#ffffff</item>
|
||||
<item name="android:shadowDx">1.0</item>
|
||||
<item name="android:shadowDy">1.0</item>
|
||||
<item name="android:shadowRadius">0.0</item>
|
||||
<item name="android:lineSpacingMultiplier">1.25</item>
|
||||
</style>
|
||||
|
||||
<!-- For Holo Light Dialog Activity Styling Emulation -->
|
||||
|
||||
<style name="Widget.ProgressBar.Horizontal" parent="@android:style/Widget.Holo.ProgressBar.Horizontal">
|
||||
</style>
|
||||
|
||||
<style name="MaterialButton">
|
||||
<item name="android:elevation" tools:ignore="NewApi">1dp</item>
|
||||
<item name="android:translationZ" tools:ignore="NewApi">1dp</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
|
||||
<style name="InfoButton" parent="@style/MaterialButton">
|
||||
<item name="android:background">@drawable/info_round</item>
|
||||
</style>
|
||||
|
||||
<style name="ErrorButton" parent="@style/MaterialButton">
|
||||
<item name="android:background">@drawable/error_round</item>
|
||||
</style>
|
||||
|
||||
<style name="AttachmentTypeLabel">
|
||||
<item name="android:textColor">?android:textColorTertiary</item>
|
||||
<item name="android:textSize">@dimen/small_font_size</item>
|
||||
</style>
|
||||
|
||||
<style name="Button.Primary" parent="Base.Widget.AppCompat.Button.Colored">
|
||||
<item name="colorAccent">@color/signal_primary</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="Button.Borderless" parent="Base.Widget.AppCompat.Button.Borderless">
|
||||
<item name="android:textColor">@color/signal_primary</item>
|
||||
</style>
|
||||
|
||||
<style name="Button.Borderless.Registration" parent="Base.Widget.AppCompat.Button.Borderless">
|
||||
<item name="android:textColor">@color/core_grey_60</item>
|
||||
</style>
|
||||
|
||||
<!-- RedPhone -->
|
||||
|
||||
<!-- Buttons in the main "button row" of the in-call onscreen touch UI. -->
|
||||
|
||||
<!-- "Compound button" variation of InCallButton.
|
||||
These buttons have the concept of two states: checked and unchecked.
|
||||
(This style is just like "InCallButton" except that we also
|
||||
clear out android:textOn and android:textOff, to avoid the default
|
||||
text label behavior of the ToggleButton class.) -->
|
||||
|
||||
<style name="WebRtcCallCompoundButton">
|
||||
<item name="android:layout_height">31dp</item>
|
||||
<item name="android:layout_width">31dp</item>
|
||||
<item name="android:textOn">@null</item>
|
||||
<item name="android:textOff">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="IdentityKey">
|
||||
<item name="android:fontFamily">monospace</item>
|
||||
<item name="android:typeface">monospace</item>
|
||||
<item name="android:textSize">17sp</item>
|
||||
<item name="android:clickable">false</item>
|
||||
<item name="android:focusable">false</item>
|
||||
</style>
|
||||
|
||||
<style name="BackupPassphrase">
|
||||
<item name="android:fontFamily">monospace</item>
|
||||
<item name="android:typeface">monospace</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:clickable">false</item>
|
||||
<item name="android:focusable">false</item>
|
||||
</style>
|
||||
|
||||
<style name="PreferenceThemeOverlay.Fix" parent="PreferenceThemeOverlay.v14.Material">
|
||||
</style>
|
||||
|
||||
<style name="Color1SwitchStyle">
|
||||
<item name="colorControlActivated">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="BottomSheetActionItem">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">@dimen/action_item_height</item>
|
||||
<item name="android:textSize">@dimen/medium_font_size</item>
|
||||
<item name="android:drawablePadding">@dimen/drawable_padding</item>
|
||||
<item name="android:padding">@dimen/normal_padding</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:selectable">true</item>
|
||||
<item name="android:foreground">?attr/selectableItemBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="StickerPopupAnimation" parent="@android:style/Animation">
|
||||
<item name="android:windowEnterAnimation">@anim/fade_in</item>
|
||||
<item name="android:windowExitAnimation">@anim/fade_out</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -1,294 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Session -->
|
||||
|
||||
<!-- Due to historical reasons the base theme is dark and the light one
|
||||
is implemented using "notnight" type of resources. -->
|
||||
<style name="Base.Theme.Session" parent="@style/Theme.AppCompat.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/action_bar_background</item>
|
||||
<item name="colorPrimaryDark">@color/action_bar_background</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="colorControlNormal">?android:textColorPrimary</item>
|
||||
<item name="colorControlActivated">?colorAccent</item>
|
||||
<item name="colorControlHighlight">?colorAccent</item>
|
||||
<item name="android:textColorPrimary">@color/text</item>
|
||||
<item name="android:textColorSecondary">?android:textColorPrimary</item>
|
||||
<item name="android:textColorTertiary">@color/unimportant</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:textColorHint">@color/gray27</item>
|
||||
<item name="android:windowBackground">@drawable/default_session_background</item>
|
||||
<item name="android:colorBackground">@color/default_background_start</item>
|
||||
<item name="android:navigationBarColor">@color/compose_view_background</item>
|
||||
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
|
||||
<item name="actionBarWidgetTheme">@null</item>
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.DayNight.ActionBar</item>
|
||||
<item name="actionBarStyle">@style/Widget.Session.ActionBar</item>
|
||||
|
||||
<item name="alertDialogTheme">@style/ThemeOverlay.Session.AlertDialog</item>
|
||||
<item name="bottomSheetDialogTheme">@style/Theme.Session.BottomSheet</item>
|
||||
<item name="preferenceTheme">@style/ThemeOverlay.Session.Settings</item>
|
||||
<item name="appBarLayoutStyle">@style/Widget.Session.AppBarLayout</item>
|
||||
<item name="actionBarTabBarStyle">@style/Widget.Session.TabBar</item>
|
||||
|
||||
<item name="statusBarBackground">@color/accent</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="actionModeCloseDrawable">@drawable/ic_baseline_clear_24</item>
|
||||
<item name="actionModeBackground">@color/compose_view_background</item>
|
||||
|
||||
<item name="dividerVertical">@color/separator</item>
|
||||
<item name="dividerHorizontal">?dividerVertical</item>
|
||||
|
||||
<item name="searchViewStyle">@style/Widget.Session.SearchView</item>
|
||||
|
||||
<!-- App specific attributes -->
|
||||
<item name="ic_visibility_on">@drawable/ic_baseline_visibility_24</item>
|
||||
<item name="ic_visibility_off">@drawable/ic_baseline_visibility_off_24</item>
|
||||
<item name="ic_arrow_forward">@drawable/ic_baseline_arrow_forward_24</item>
|
||||
|
||||
<item name="dialog_background_color">@color/dialog_background</item>
|
||||
|
||||
<item name="media_overview_toolbar_background">@color/transparent</item>
|
||||
<item name="media_overview_header_foreground">@color/text</item>
|
||||
<item name="media_keyboard_button_color">@color/core_grey_25</item>\
|
||||
|
||||
<item name="attachment_type_selector_background">?android:windowBackground</item>
|
||||
<item name="attachment_type_selector_hide_button_background">@color/gray50</item>
|
||||
<item name="attachment_document_icon_small">@drawable/ic_document_small_dark</item>
|
||||
<item name="attachment_document_icon_large">@drawable/ic_document_large_dark</item>
|
||||
<item name="attachment_document_extension_text_color">#222</item>
|
||||
|
||||
<item name="home_gradient_start">#00000000</item>
|
||||
<item name="home_gradient_end">#FF000000</item>
|
||||
|
||||
<item name="message_received_background_color">#222325</item>
|
||||
<item name="message_sent_background_color">#3F4146</item>
|
||||
|
||||
<item name="menu_accept_icon">@drawable/ic_baseline_done_24</item>
|
||||
<item name="menu_trash_icon">@drawable/ic_baseline_delete_24</item>
|
||||
<item name="menu_block_icon">@drawable/ic_baseline_block_24</item>
|
||||
<item name="menu_forward_icon">@drawable/ic_baseline_forward_24</item>
|
||||
<item name="menu_save_icon">@drawable/ic_baseline_save_24</item>
|
||||
<item name="menu_photo_library_icon">@drawable/ic_baseline_photo_library_24</item>
|
||||
<item name="menu_delete_icon">@drawable/ic_baseline_delete_24</item>
|
||||
<item name="menu_copy_icon">@drawable/ic_baseline_file_copy_24</item>
|
||||
<item name="menu_reply_icon">@drawable/ic_baseline_reply_24</item>
|
||||
<item name="menu_selectall_icon">@drawable/ic_baseline_select_all_24</item>
|
||||
<item name="menu_split_icon">@drawable/ic_baseline_call_split_24</item>
|
||||
<item name="menu_popup_expand">@drawable/ic_baseline_launch_24</item>
|
||||
<item name="menu_info_icon">@drawable/ic_baseline_info_24</item>
|
||||
|
||||
<item name="conversation_emoji_toggle">@drawable/ic_emoji_filled_keyboard_24</item>
|
||||
<item name="conversation_sticker_toggle">@drawable/ic_sticker_filled_keyboard_24</item>
|
||||
<item name="conversation_keyboard_toggle">@drawable/ic_baseline_keyboard_24</item>
|
||||
<item name="conversation_input_background">@drawable/compose_background_dark</item>
|
||||
|
||||
<item name="quick_camera_icon">@drawable/ic_baseline_photo_camera_24</item>
|
||||
<item name="quick_mic_icon">@drawable/ic_baseline_mic_24</item>
|
||||
|
||||
<item name="conversation_item_audio_seek_bar_color_incoming">@color/accent</item>
|
||||
<item name="conversation_item_audio_seek_bar_color_outgoing">@color/accent</item>
|
||||
<item name="conversation_item_audio_seek_bar_background_color">@color/text</item>
|
||||
</style>
|
||||
|
||||
<!-- This should be the default theme for the application. -->
|
||||
<style name="Theme.Session.DayNight" parent="Base.Theme.Session">
|
||||
<!-- leave empty to allow overriding -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.Session.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Session.DayNight.FlatActionBar">
|
||||
<item name="actionBarStyle">@style/Widget.Session.ActionBar.Flat</item>
|
||||
</style>
|
||||
|
||||
<!--
|
||||
This is a temporary theme that is used by any activity
|
||||
which doesn't have support for light theme
|
||||
(like some old Signal screens or third-party libs with white only icons)
|
||||
-->
|
||||
<!-- TODO Refactor this to use color resources -->
|
||||
<style name="Base.Theme.Session.ForceDark" parent="Theme.Session.DayNight">
|
||||
<item name="colorPrimary">#171717</item>
|
||||
<item name="android:textColorPrimary">#FFFFFF</item>
|
||||
<item name="android:textColorSecondary">#DFFFFFFF</item>
|
||||
<item name="android:textColorTertiary">#90FFFFFF</item>
|
||||
<item name="colorControlNormal">?android:textColorPrimary</item>
|
||||
<item name="android:colorBackground">#121212</item>
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
<item name="android:navigationBarColor">?android:colorBackground</item>
|
||||
<item name="android:statusBarColor">@color/transparent</item>
|
||||
|
||||
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
<item name="actionBarWidgetTheme">@null</item>
|
||||
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
|
||||
<item name="actionBarStyle">@style/Widget.AppCompat.ActionBar</item>
|
||||
|
||||
<item name="conversation_emoji_toggle">@drawable/ic_emoji_filled_keyboard_24</item>
|
||||
<item name="conversation_sticker_toggle">@drawable/ic_sticker_filled_keyboard_24</item>
|
||||
<item name="conversation_keyboard_toggle">@drawable/ic_baseline_keyboard_24</item>
|
||||
<item name="conversation_input_background">@drawable/compose_background_dark</item>
|
||||
</style>
|
||||
<style name="Theme.Session.ForceDark" parent="Base.Theme.Session.ForceDark">
|
||||
<!-- leave empty to allow overriding -->
|
||||
</style>
|
||||
<style name="Theme.Session.ForceDark.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Session.BottomSheet" parent="@style/Theme.AppCompat.DayNight.Dialog">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation.MaterialComponents.BottomSheetDialog</item>
|
||||
<item name="bottomSheetStyle">@style/Widget.Session.BottomSheetDialog</item>
|
||||
</style>
|
||||
|
||||
<!-- Session -->
|
||||
|
||||
|
||||
|
||||
<!-- Original Signal dark theme -->
|
||||
<style name="Base.Theme.TextSecure" parent="@style/Theme.Session.DayNight">
|
||||
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
|
||||
<item name="colorPrimary">@color/action_bar_background</item>
|
||||
<item name="colorPrimaryDark">@color/action_bar_background</item>
|
||||
|
||||
<item name="media_overview_toolbar_background">@color/transparent</item>
|
||||
<item name="media_overview_header_foreground">@color/text</item>
|
||||
|
||||
<item name="theme_type">dark</item>
|
||||
<item name="android:navigationBarColor">@color/compose_view_background</item>
|
||||
|
||||
<item name="attachment_document_icon_small">@drawable/ic_document_small_dark</item>
|
||||
<item name="attachment_document_icon_large">@drawable/ic_document_large_dark</item>
|
||||
|
||||
<item name="conversation_list_item_background">@drawable/conversation_list_item_background_dark</item>
|
||||
<item name="conversation_list_item_contact_color">#ffdddddd</item>
|
||||
<item name="conversation_list_item_subject_color">#ffdddddd</item>
|
||||
<item name="conversation_list_item_delivery_icon_color">@color/core_grey_25</item>
|
||||
<item name="conversation_list_item_date_color">#ffdddddd</item>
|
||||
<item name="conversation_list_item_unread_color">@color/core_white</item>
|
||||
<item name="conversation_list_item_unread_background">@drawable/unread_count_background_dark</item>
|
||||
<item name="conversation_list_item_divider">@drawable/conversation_list_divider_shape_dark</item>
|
||||
<item name="conversation_list_toolbar_background">@color/action_bar_background</item>
|
||||
<item name="conversation_list_typing_tint">@color/core_white</item>
|
||||
|
||||
<item name="conversation_group_member_name">#99ffffff</item>
|
||||
|
||||
<item name="conversation_item_bubble_background">?message_sent_background_color</item>
|
||||
<item name="conversation_item_sent_text_primary_color">@color/core_grey_05</item>
|
||||
<item name="conversation_item_sent_text_secondary_color">@color/core_grey_25</item>
|
||||
<item name="conversation_item_sent_icon_color">@color/core_grey_25</item>
|
||||
<item name="conversation_item_sent_text_indicator_tab_color">#99ffffff</item>
|
||||
<item name="conversation_item_received_text_primary_color">@color/text</item>
|
||||
<item name="conversation_item_received_text_secondary_color">@color/text</item>
|
||||
<item name="conversation_item_sent_indicator_text_background">@drawable/conversation_item_sent_indicator_text_shape_dark</item>
|
||||
<item name="conversation_item_sticky_date_background">@drawable/sticky_date_header_background_dark</item>
|
||||
<item name="conversation_item_sticky_date_text_color">@color/core_grey_45</item>
|
||||
<item name="conversation_item_image_outline_color">@color/transparent_white_30</item>
|
||||
|
||||
<item name="verification_background">@color/core_grey_95</item>
|
||||
|
||||
<item name="dialog_info_icon">@drawable/ic_info_outline_dark</item>
|
||||
<item name="dialog_alert_icon">@drawable/ic_warning_dark</item>
|
||||
|
||||
<item name="device_link_item_card_background">@color/device_link_item_background_dark</item>
|
||||
|
||||
<item name="fab_color">@color/textsecure_primary_dark</item>
|
||||
<item name="lower_right_divet">@drawable/divet_lower_right_light</item>
|
||||
|
||||
<item name="conversation_background">@color/loki_darkest_gray</item>
|
||||
<item name="conversation_editor_background">#22ffffff</item>
|
||||
<item name="conversation_editor_text_color">#ffeeeeee</item>
|
||||
<item name="conversation_input_inline_attach_icon_tint">@color/core_grey_05</item>
|
||||
<item name="conversation_transport_sms_indicator">@drawable/ic_arrow_up_circle_24</item>
|
||||
<item name="conversation_transport_push_indicator">@drawable/ic_arrow_up_circle_24</item>
|
||||
<item name="conversation_transport_popup_background">@color/black</item>
|
||||
<item name="conversation_attach_camera">@drawable/ic_photo_camera_dark</item>
|
||||
<item name="conversation_attach_image">@drawable/ic_image_dark</item>
|
||||
<item name="conversation_attach_video">@drawable/ic_movie_creation_dark</item>
|
||||
<item name="conversation_attach_sound">@drawable/ic_volume_up_dark</item>
|
||||
<item name="conversation_attach_contact_info">@drawable/ic_account_box_dark</item>
|
||||
<item name="conversation_attach">@drawable/ic_attach_white_24dp</item>
|
||||
<item name="conversation_number_picker_text_color_normal">@color/gray13</item>
|
||||
<item name="conversation_number_picker_text_color_selected">@color/white</item>
|
||||
<item name="conversation_sticker_footer_text_color">@color/core_grey_25</item>
|
||||
<item name="conversation_sticker_footer_icon_color">@color/core_grey_25</item>
|
||||
<item name="conversation_sticker_author_color">@color/core_grey_05</item>
|
||||
|
||||
<item name="emoji_tab_strip_background">@color/compose_view_background</item>
|
||||
<item name="emoji_tab_indicator">@color/accent</item>
|
||||
<item name="emoji_tab_underline">@color/gray78</item>
|
||||
<item name="emoji_tab_seperator">@color/gray70</item>
|
||||
<item name="emoji_drawer_background">@color/compose_text_view_background</item>
|
||||
<item name="emoji_text_color">@color/white</item>
|
||||
|
||||
<item name="emoji_category_recent">@drawable/ic_recent_dark_20</item>
|
||||
<item name="emoji_category_people">@drawable/ic_emoji_people_dark_20</item>
|
||||
<item name="emoji_category_nature">@drawable/ic_emoji_animal_dark_20</item>
|
||||
<item name="emoji_category_foods">@drawable/ic_emoji_food_dark_20</item>
|
||||
<item name="emoji_category_activity">@drawable/ic_emoji_activity_dark_20</item>
|
||||
<item name="emoji_category_places">@drawable/ic_emoji_travel_dark_20</item>
|
||||
<item name="emoji_category_objects">@drawable/ic_emoji_object_dark_20</item>
|
||||
<item name="emoji_category_symbol">@drawable/ic_emoji_symbol_dark_20</item>
|
||||
<item name="emoji_category_flags">@drawable/ic_emoji_flag_dark_20</item>
|
||||
<item name="emoji_category_emoticons">@drawable/ic_emoji_emoticon_dark_20</item>
|
||||
<item name="emoji_variation_selector_background">@drawable/emoji_variation_selector_background_dark</item>
|
||||
|
||||
<item name="linkpreview_background_color">@color/black</item>
|
||||
<item name="linkpreview_primary_text_color">@color/text</item>
|
||||
<item name="linkpreview_secondary_text_color">@color/text</item>
|
||||
<item name="linkpreview_divider_color">@color/transparent</item>
|
||||
|
||||
<item name="conversation_icon_attach_audio">@drawable/ic_audio_dark</item>
|
||||
<item name="conversation_icon_attach_video">@drawable/ic_video_dark</item>
|
||||
|
||||
<item name="sticker_management_icon">@drawable/sticker_button_dark</item>
|
||||
<item name="sticker_management_divider_color">@color/core_grey_75</item>
|
||||
<item name="sticker_management_empty_background_color">@color/core_grey_85</item>
|
||||
<item name="sticker_management_action_button_color">@color/core_grey_25</item>
|
||||
<item name="sticker_popup_background">@color/transparent_black_90</item>
|
||||
<item name="sticker_preview_toolbar_background">@color/core_grey_95</item>
|
||||
<item name="sticker_preview_status_bar_color">@color/core_grey_85</item>
|
||||
<item name="sticker_view_missing_background">@drawable/sticker_missing_background_dark</item>
|
||||
|
||||
<item name="tooltip_default_color">@color/core_grey_75</item>
|
||||
|
||||
<item name="pref_icon_tint">#FFFFFF</item>
|
||||
|
||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.Fix</item>
|
||||
|
||||
<item name="shared_contact_details_header_background">@color/grey_800</item>
|
||||
<item name="shared_contact_details_titlebar">@color/grey_900</item>
|
||||
<item name="shared_contact_item_button_color">@color/core_grey_85</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.TextSecure.DayNight" parent="Base.Theme.TextSecure">
|
||||
<!-- leave empty to allow overriding -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.TextSecure.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.TextSecure.Dialog.Rationale" parent="Theme.AppCompat.DayNight.Dialog.Alert">
|
||||
<item name="android:windowBackground">@drawable/default_dialog_background</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.TextSecure.Dialog.MediaSendProgress" parent="@android:style/Theme.Dialog">
|
||||
<item name="android:background">@drawable/default_dialog_background</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@ -19,24 +19,14 @@ interface LokiAPIDatabaseProtocol {
|
||||
fun setReceivedMessageHashValues(publicKey: String, newValue: Set<String>)
|
||||
fun getAuthToken(server: String): String?
|
||||
fun setAuthToken(server: String, newValue: String?)
|
||||
fun getLastMessageServerID(group: Long, server: String): Long?
|
||||
fun setLastMessageServerID(group: Long, server: String, newValue: Long)
|
||||
fun getLastDeletionServerID(group: Long, server: String): Long?
|
||||
fun setLastDeletionServerID(group: Long, server: String, newValue: Long)
|
||||
fun setUserCount(group: Long, server: String, newValue: Int)
|
||||
fun setUserCount(room: String, server: String, newValue: Int)
|
||||
fun getLastMessageServerID(room: String, server: String): Long?
|
||||
fun setLastMessageServerID(room: String, server: String, newValue: Long)
|
||||
fun getLastDeletionServerID(room: String, server: String): Long?
|
||||
fun setLastDeletionServerID(room: String, server: String, newValue: Long)
|
||||
fun setUserCount(room: String, server: String, newValue: Int)
|
||||
fun getSessionRequestSentTimestamp(publicKey: String): Long?
|
||||
fun setSessionRequestSentTimestamp(publicKey: String, newValue: Long)
|
||||
fun getSessionRequestProcessedTimestamp(publicKey: String): Long?
|
||||
fun setSessionRequestProcessedTimestamp(publicKey: String, newValue: Long)
|
||||
fun getOpenGroupPublicKey(server: String): String?
|
||||
fun setOpenGroupPublicKey(server: String, newValue: String)
|
||||
fun setOpenGroupProfilePictureURL(group: Long, server: String, newValue: String)
|
||||
fun getOpenGroupProfilePictureURL(group: Long, server: String): String?
|
||||
fun getLastSnodePoolRefreshDate(): Date?
|
||||
fun setLastSnodePoolRefreshDate(newValue: Date)
|
||||
fun getUserX25519KeyPair(): ECKeyPair
|
||||
|
@ -2,6 +2,5 @@ package org.session.libsignal.database
|
||||
|
||||
interface LokiMessageDatabaseProtocol {
|
||||
|
||||
fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long?
|
||||
fun setServerID(messageID: Long, serverID: Long, isSms: Boolean)
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
package org.session.libsignal.database
|
||||
|
||||
interface LokiUserDatabaseProtocol {
|
||||
|
||||
fun getDisplayName(publicKey: String): String?
|
||||
fun getProfilePictureURL(publicKey: String): String?
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user