apply Material 3 theme to all activites

This commit is contained in:
Daniel Gultsch 2024-04-04 11:38:27 +02:00
parent 4968bde774
commit 6e43248135
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
1427 changed files with 5148 additions and 5856 deletions

View file

@ -74,7 +74,7 @@ dependencies {
implementation 'org.hsluv:hsluv:0.2'
implementation 'org.conscrypt:conscrypt-android:2.5.2'
implementation 'me.drakeet.support:toastcompat:1.1.0'
implementation "com.leinardi.android:speed-dial:3.2.0"
implementation "com.leinardi.android:speed-dial:3.3.0"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"

View file

@ -5,6 +5,7 @@
<activity
android:name=".ui.ManageAccountActivity"
android:label="@string/title_activity_manage_accounts"
android:theme="@style/Theme.Conversations3"
android:launchMode="singleTask" />
<activity
android:name=".ui.WelcomeActivity"

View file

@ -225,7 +225,7 @@ public class ImportBackupService extends Service {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.restoring_backup))
.setSmallIcon(R.drawable.ic_unarchive_white_24dp)
.setSmallIcon(R.drawable.ic_unarchive_24dp)
.setProgress(max, progress, max == 1 && progress == 0);
return mBuilder.build();
}
@ -415,7 +415,7 @@ public class ImportBackupService extends Service {
? PendingIntent.FLAG_IMMUTABLE
| PendingIntent.FLAG_UPDATE_CURRENT
: PendingIntent.FLAG_UPDATE_CURRENT))
.setSmallIcon(R.drawable.ic_unarchive_white_24dp);
.setSmallIcon(R.drawable.ic_unarchive_24dp);
notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}

View file

@ -2,6 +2,7 @@ package eu.siacs.conversations.ui;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Bundle;
@ -11,8 +12,10 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
import eu.siacs.conversations.Config;
@ -23,19 +26,20 @@ import eu.siacs.conversations.services.BarcodeProvider;
import eu.siacs.conversations.utils.EasyOnboardingInvite;
import eu.siacs.conversations.xmpp.Jid;
public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOnboardingInvite.OnInviteRequested {
public class EasyOnboardingInviteActivity extends XmppActivity
implements EasyOnboardingInvite.OnInviteRequested {
private ActivityEasyInviteBinding binding;
private EasyOnboardingInvite easyOnboardingInvite;
@Override
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_easy_invite);
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar(), true);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
this.binding.shareButton.setOnClickListener(v -> share());
if (bundle != null && bundle.containsKey("invite")) {
this.easyOnboardingInvite = bundle.getParcelable("invite");
@ -65,11 +69,11 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
}
private void share() {
final String shareText = getString(
R.string.easy_invite_share_text,
easyOnboardingInvite.getDomain(),
easyOnboardingInvite.getShareableLink()
);
final String shareText =
getString(
R.string.easy_invite_share_text,
easyOnboardingInvite.getDomain(),
easyOnboardingInvite.getShareableLink());
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, shareText);
@ -95,16 +99,47 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
private void showInvite(final EasyOnboardingInvite invite) {
this.binding.inProgress.setVisibility(View.GONE);
this.binding.invite.setVisibility(View.VISIBLE);
this.binding.tapToShare.setText(getString(R.string.tap_share_button_send_invite, invite.getDomain()));
this.binding.tapToShare.setText(
getString(R.string.tap_share_button_send_invite, invite.getDomain()));
final Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
final int width = Math.min(size.x, size.y);
final Bitmap bitmap = BarcodeProvider.create2dBarcodeBitmap(invite.getShareableLink(), width);
final boolean nightMode =
(this.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
final int black;
final int white;
if (nightMode) {
black =
MaterialColors.getColor(
this,
com.google.android.material.R.attr.colorSurface,
"No surface color configured");
white =
MaterialColors.getColor(
this,
com.google.android.material.R.attr.colorSurfaceInverse,
"No inverse surface color configured");
} else {
black =
MaterialColors.getColor(
this,
com.google.android.material.R.attr.colorSurfaceInverse,
"No inverse surface color configured");
white =
MaterialColors.getColor(
this,
com.google.android.material.R.attr.colorSurface,
"No surface color configured");
}
final Bitmap bitmap =
BarcodeProvider.create2dBarcodeBitmap(
invite.getShareableLink(), width, black, white);
binding.qrCode.setImageBitmap(bitmap);
}
@Override
public void onSaveInstanceState(Bundle bundle) {
public void onSaveInstanceState(@NonNull Bundle bundle) {
super.onSaveInstanceState(bundle);
if (easyOnboardingInvite != null) {
bundle.putParcelable("invite", easyOnboardingInvite);
@ -141,11 +176,12 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
@Override
public void inviteRequestFailed(final String message) {
runOnUiThread(() -> {
if (!Strings.isNullOrEmpty(message)) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
finish();
});
runOnUiThread(
() -> {
if (!Strings.isNullOrEmpty(message)) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
finish();
});
}
}

View file

@ -18,6 +18,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import java.io.IOException;
@ -31,7 +32,6 @@ import eu.siacs.conversations.services.ImportBackupService;
import eu.siacs.conversations.ui.adapter.BackupFileAdapter;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.utils.BackupFileHeader;
import eu.siacs.conversations.utils.ThemeHelper;
public class ImportBackupActivity extends ActionBarActivity implements ServiceConnection, ImportBackupService.OnBackupFilesLoaded, BackupFileAdapter.OnItemClickedListener, ImportBackupService.OnBackupProcessed {
@ -46,22 +46,15 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
@Override
protected void onCreate(final Bundle savedInstanceState) {
this.mTheme = ThemeHelper.find(this);
setTheme(this.mTheme);
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
setLoadingState(savedInstanceState != null && savedInstanceState.getBoolean("loading_state", false));
this.backupFileAdapter = new BackupFileAdapter();
this.binding.list.setAdapter(this.backupFileAdapter);
this.backupFileAdapter.setOnItemClickedListener(this);
}
@Override
protected void onResume(){
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
@ -80,12 +73,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
@Override
public void onStart() {
super.onStart();
final int theme = ThemeHelper.find(this);
if (this.mTheme != theme) {
recreate();
} else {
bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
}
bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
final Intent intent = getIntent();
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction()) && !this.mLoadingState) {
Uri uri = intent.getData();
@ -146,7 +134,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
final DialogEnterPasswordBinding enterPasswordBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.dialog_enter_password, null, false);
Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri());
enterPasswordBinding.explain.setText(getString(R.string.enter_password_to_restore, backupFile.getHeader().getJid().toString()));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setView(enterPasswordBinding.getRoot());
builder.setTitle(R.string.enter_password);
builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
@ -186,6 +174,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
binding.coordinator.setVisibility(loadingState ? View.GONE : View.VISIBLE);
binding.inProgress.setVisibility(loadingState ? View.VISIBLE : View.GONE);
setTitle(loadingState ? R.string.restoring_backup : R.string.restore_backup);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
configureActionBar(getSupportActionBar(), !loadingState);
this.mLoadingState = loadingState;
invalidateOptionsMenu();

View file

@ -10,45 +10,32 @@ import android.widget.Toast;
import androidx.databinding.DataBindingUtil;
import java.security.SecureRandom;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.MagicCreateBinding;
import eu.siacs.conversations.databinding.ActivityMagicCreateBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.InstallReferrerUtils;
import eu.siacs.conversations.xmpp.Jid;
import java.security.SecureRandom;
public class MagicCreateActivity extends XmppActivity implements TextWatcher {
public static final String EXTRA_DOMAIN = "domain";
public static final String EXTRA_PRE_AUTH = "pre_auth";
public static final String EXTRA_USERNAME = "username";
private MagicCreateBinding binding;
private ActivityMagicCreateBinding binding;
private String domain;
private String username;
private String preAuth;
@Override
protected void refreshUiReal() {
}
protected void refreshUiReal() {}
@Override
void onBackendConnected() {
}
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
void onBackendConnected() {}
@Override
protected void onCreate(final Bundle savedInstanceState) {
@ -60,7 +47,8 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.magic_create);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_magic_create);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(this.binding.toolbar);
configureActionBar(getSupportActionBar(), this.domain == null);
if (username != null && domain != null) {
@ -72,51 +60,64 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
} else if (domain != null) {
binding.instructions.setText(getString(R.string.magic_create_text_on_x, domain));
}
binding.createAccount.setOnClickListener(v -> {
try {
final String username = binding.username.getText().toString();
final Jid jid;
final boolean fixedUsername;
if (this.domain != null && this.username != null) {
fixedUsername = true;
jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
} else if (this.domain != null) {
fixedUsername = false;
jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
} else {
fixedUsername = false;
jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
}
if (!jid.getEscapedLocal().equals(jid.getLocal()) || (this.username == null && username.length() < 3)) {
binding.username.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
} else {
binding.username.setError(null);
Account account = xmppConnectionService.findAccountByJid(jid);
if (account == null) {
account = new Account(jid, CryptoHelper.createPassword(new SecureRandom()));
account.setOption(Account.OPTION_REGISTER, true);
account.setOption(Account.OPTION_DISABLED, true);
account.setOption(Account.OPTION_MAGIC_CREATE, true);
account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername);
if (this.preAuth != null) {
account.setKey(Account.KEY_PRE_AUTH_REGISTRATION_TOKEN, this.preAuth);
binding.createAccount.setOnClickListener(
v -> {
try {
final String username = binding.username.getText().toString();
final Jid jid;
final boolean fixedUsername;
if (this.domain != null && this.username != null) {
fixedUsername = true;
jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
} else if (this.domain != null) {
fixedUsername = false;
jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
} else {
fixedUsername = false;
jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
}
xmppConnectionService.createAccount(account);
if (!jid.getEscapedLocal().equals(jid.getLocal())
|| (this.username == null && username.length() < 3)) {
binding.usernameLayout.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
} else {
binding.usernameLayout.setError(null);
Account account = xmppConnectionService.findAccountByJid(jid);
if (account == null) {
account =
new Account(
jid,
CryptoHelper.createPassword(new SecureRandom()));
account.setOption(Account.OPTION_REGISTER, true);
account.setOption(Account.OPTION_DISABLED, true);
account.setOption(Account.OPTION_MAGIC_CREATE, true);
account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername);
if (this.preAuth != null) {
account.setKey(
Account.KEY_PRE_AUTH_REGISTRATION_TOKEN, this.preAuth);
}
xmppConnectionService.createAccount(account);
}
Intent intent =
new Intent(MagicCreateActivity.this, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
Toast.makeText(
MagicCreateActivity.this,
R.string.secure_password_generated,
Toast.LENGTH_SHORT)
.show();
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
}
} catch (final IllegalArgumentException e) {
binding.usernameLayout.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
}
Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class);
intent.putExtra("jid", account.getJid().asBareJid().toString());
intent.putExtra("init", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
StartConversationActivity.addInviteUri(intent, getIntent());
startActivity(intent);
}
} catch (IllegalArgumentException e) {
binding.username.setError(getString(R.string.invalid_username));
binding.username.requestFocus();
}
});
});
binding.username.addTextChangedListener(this);
}
@ -127,14 +128,10 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(final Editable s) {
@ -153,8 +150,10 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
} else {
jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
}
binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
} catch (IllegalArgumentException e) {
binding.fullJid.setText(
getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
binding.usernameLayout.setError(null);
} catch (final IllegalArgumentException e) {
binding.fullJid.setVisibility(View.INVISIBLE);
}
}

View file

@ -1,10 +1,14 @@
package eu.siacs.conversations.ui;
import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
import android.util.Log;
import android.util.Pair;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@ -12,23 +16,17 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.common.base.Strings;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
@ -37,10 +35,17 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.XmppConnection;
import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
import org.openintents.openpgp.util.OpenPgpApi;
public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated, AccountAdapter.OnTglAccountState {
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class ManageAccountActivity extends XmppActivity
implements OnAccountUpdate,
KeyChainAliasCallback,
XmppConnectionService.OnAccountCreated,
AccountAdapter.OnTglAccountState {
private final String STATE_SELECTED_ACCOUNT = "selected_account";
@ -50,7 +55,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
protected Jid selectedAccountJid = null;
protected final List<Account> accountList = new ArrayList<>();
protected ListView accountListView;
protected AccountAdapter mAccountAdapter;
protected AtomicBoolean mInvokedAddAccount = new AtomicBoolean(false);
@ -67,7 +71,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
accountList.clear();
accountList.addAll(xmppConnectionService.getAccounts());
}
ActionBar actionBar = getSupportActionBar();
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setHomeButtonEnabled(this.accountList.size() > 0);
actionBar.setDisplayHomeAsUpEnabled(this.accountList.size() > 0);
@ -81,8 +85,11 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
setSupportActionBar(findViewById(R.id.toolbar));
ActivityManageAccountsBinding binding =
DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
if (savedInstanceState != null) {
String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT);
@ -95,26 +102,19 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
}
accountListView = findViewById(R.id.account_list);
this.mAccountAdapter = new AccountAdapter(this, accountList);
accountListView.setAdapter(this.mAccountAdapter);
accountListView.setOnItemClickListener((arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
registerForContextMenu(accountListView);
binding.accountList.setAdapter(this.mAccountAdapter);
binding.accountList.setOnItemClickListener(
(arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
registerForContextMenu(binding.accountList);
}
@Override
protected void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override
public void onSaveInstanceState(final Bundle savedInstanceState) {
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
if (selectedAccount != null) {
savedInstanceState.putString(STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
savedInstanceState.putString(
STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
}
super.onSaveInstanceState(savedInstanceState);
}
@ -122,8 +122,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
ManageAccountActivity.this.getMenuInflater().inflate(
R.menu.manageaccounts_context, menu);
ManageAccountActivity.this.getMenuInflater().inflate(R.menu.manageaccounts_context, menu);
AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
this.selectedAccount = accountList.get(acmi.position);
if (this.selectedAccount.isEnabled()) {
@ -144,9 +143,10 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
refreshUiReal();
if (this.mPostponedActivityResult != null) {
this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
this.onActivityResult(
mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
}
if (Config.X509_VERIFICATION && this.accountList.size() == 0) {
if (Config.X509_VERIFICATION && this.accountList.isEmpty()) {
if (mInvokedAddAccount.compareAndSet(false, true)) {
addAccountFromKey();
}
@ -233,9 +233,9 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
return super.onOptionsItemSelected(item);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0) {
if (allGranted(grantResults)) {
@ -258,13 +258,14 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
@Override
public boolean onNavigateUp() {
if (xmppConnectionService.getConversations().size() == 0) {
Intent contactsIntent = new Intent(this,
StartConversationActivity.class);
Intent contactsIntent = new Intent(this, StartConversationActivity.class);
contactsIntent.setFlags(
// if activity exists in stack, pop the stack and go back to it
Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_CLEAR_TOP
|
// otherwise, make a new task for it
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_NEW_TASK
|
// don't use the new activity animation; finish
// animation runs instead
Intent.FLAG_ACTIVITY_NO_ANIMATION);
@ -286,16 +287,17 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
private void addAccountFromKey() {
Log.d(Config.LOGTAG, "add account from key");
try {
KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show();
} catch (final ActivityNotFoundException e) {
Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG)
.show();
}
}
private void publishAvatar(Account account) {
Intent intent = new Intent(getApplicationContext(),
PublishProfilePictureActivity.class);
Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
startActivity(intent);
}
@ -377,7 +379,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -385,7 +386,8 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
if (xmppConnectionServiceBound) {
if (requestCode == REQUEST_CHOOSE_PGP_ID) {
if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) {
selectedAccount.setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
selectedAccount.setPgpSignId(
data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
announcePgp(selectedAccount, null, null, onOpenPGPKeyPublished);
} else {
choosePgpSignId(selectedAccount);
@ -402,9 +404,17 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
@Override
public void alias(final String alias) {
if (alias != null) {
xmppConnectionService.createAccountFromKey(alias, this);
if (Strings.isNullOrEmpty(alias)) {
runOnUiThread(
() ->
Toast.makeText(
this,
R.string.no_certificate_selected,
Toast.LENGTH_LONG)
.show());
return;
}
xmppConnectionService.createAccountFromKey(alias, this);
}
@Override
@ -417,6 +427,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
@Override
public void informUser(final int r) {
runOnUiThread(() -> Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show());
runOnUiThread(
() -> Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show());
}
}

View file

@ -26,15 +26,6 @@ public class PickServerActivity extends XmppActivity {
}
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
@ -53,7 +44,8 @@ public class PickServerActivity extends XmppActivity {
}
@Override
public void onNewIntent(Intent intent) {
public void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
if (intent != null) {
setIntent(intent);
}
@ -66,6 +58,7 @@ public class PickServerActivity extends XmppActivity {
}
super.onCreate(savedInstanceState);
ActivityPickServerBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_pick_server);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
binding.useCim.setOnClickListener(v -> {
@ -81,7 +74,7 @@ public class PickServerActivity extends XmppActivity {
if (accounts.size() == 1) {
intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
intent.putExtra("init", true);
} else if (accounts.size() >= 1) {
} else if (!accounts.isEmpty()) {
intent = new Intent(this, ManageAccountActivity.class);
}
addInviteUri(intent);

View file

@ -56,15 +56,6 @@ public class ShareViaAccountActivity extends XmppActivity {
});
}
@Override
protected void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override
void onBackendConnected() {
final int numAccounts = xmppConnectionService.getAccounts().size();

View file

@ -34,7 +34,10 @@ import eu.siacs.conversations.xmpp.Jid;
import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
import com.google.common.base.Strings;
public class WelcomeActivity extends XmppActivity
implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
private static final int REQUEST_IMPORT_BACKUP = 0x63fb;
@ -66,7 +69,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
final Intent intent;
if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
intent = SignupUtils.getTokenRegistrationIntent(this, jid, preAuth);
} else if (xmppUri.isAction(XmppUri.ACTION_ROSTER) && "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) {
} else if (xmppUri.isAction(XmppUri.ACTION_ROSTER)
&& "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) {
intent = SignupUtils.getTokenRegistrationIntent(this, jid.getDomain(), preAuth);
intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
} else {
@ -81,22 +85,14 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
}
@Override
protected void refreshUiReal() {
}
protected void refreshUiReal() {}
@Override
void onBackendConnected() {
}
void onBackendConnected() {}
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
new InstallReferrerUtils(this);
}
@ -119,42 +115,44 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_welcome);
ActivityWelcomeBinding binding =
DataBindingUtil.setContentView(this, R.layout.activity_welcome);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar(), false);
binding.registerNewAccount.setOnClickListener(v -> {
final Intent intent = new Intent(this, PickServerActivity.class);
addInviteUri(intent);
startActivity(intent);
});
binding.useExisting.setOnClickListener(v -> {
final List<Account> accounts = xmppConnectionService.getAccounts();
Intent intent = new Intent(WelcomeActivity.this, EditAccountActivity.class);
intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
if (accounts.size() == 1) {
intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
intent.putExtra("init", true);
} else if (accounts.size() >= 1) {
intent = new Intent(WelcomeActivity.this, ManageAccountActivity.class);
}
addInviteUri(intent);
startActivity(intent);
});
setTitle(null);
binding.registerNewAccount.setOnClickListener(
v -> {
final Intent intent = new Intent(this, PickServerActivity.class);
addInviteUri(intent);
startActivity(intent);
});
binding.useExisting.setOnClickListener(
v -> {
final List<Account> accounts = xmppConnectionService.getAccounts();
Intent intent = new Intent(this, EditAccountActivity.class);
intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
if (accounts.size() == 1) {
intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
intent.putExtra("init", true);
} else if (!accounts.isEmpty()) {
intent = new Intent(this, ManageAccountActivity.class);
}
addInviteUri(intent);
startActivity(intent);
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.welcome_menu, menu);
final MenuItem scan = menu.findItem(R.id.action_scan_qr_code);
scan.setVisible(Compatibility.hasFeatureCamera(this));
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.action_import_backup:
if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) {
@ -174,16 +172,25 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
private void addAccountFromKey() {
try {
KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show();
} catch (final ActivityNotFoundException e) {
Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG)
.show();
}
}
@Override
public void alias(final String alias) {
if (alias != null) {
xmppConnectionService.createAccountFromKey(alias, this);
if (Strings.isNullOrEmpty(alias)) {
runOnUiThread(
() ->
Toast.makeText(
this,
R.string.no_certificate_selected,
Toast.LENGTH_LONG)
.show());
return;
}
xmppConnectionService.createAccountFromKey(alias, this);
}
@Override
@ -201,7 +208,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
if (grantResults.length > 0) {
@ -211,7 +219,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
startActivity(new Intent(this, ImportBackupActivity.class));
break;
}
} else if (Arrays.asList(permissions).contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else if (Arrays.asList(permissions)
.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
}
}
@ -232,5 +241,4 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, this.inviteUri.toString());
}
}
}

View file

@ -22,7 +22,7 @@ import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.AccountRowBinding;
import eu.siacs.conversations.databinding.ItemAccountBinding;
import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.ImportBackupService;
import eu.siacs.conversations.utils.BackupFileHeader;
@ -39,7 +39,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
@NonNull
@Override
public BackupFileViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.account_row, viewGroup, false));
return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_account, viewGroup, false));
}
@Override
@ -73,9 +73,9 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
}
static class BackupFileViewHolder extends RecyclerView.ViewHolder {
private final AccountRowBinding binding;
private final ItemAccountBinding binding;
BackupFileViewHolder(AccountRowBinding binding) {
BackupFileViewHolder(ItemAccountBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
@ -91,7 +91,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
private Jid jid = null;
private final int size;
BitmapWorkerTask(ImageView imageView) {
BitmapWorkerTask(final ImageView imageView) {
imageViewReference = new WeakReference<>(imageView);
DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics();
this.size = ((int) (48 * metrics.density));
@ -146,8 +146,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
if (drawable instanceof AsyncDrawable asyncDrawable) {
return asyncDrawable.getBitmapWorkerTask();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 B

View file

@ -1,17 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?attr/color_background_primary"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:id="@+id/in_progress"
@ -41,7 +47,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tap_share_button_send_invite"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
android:textAppearance="?textAppearanceBodyMedium" />
<TextView
android:id="@+id/scan_the_code"
@ -50,7 +56,7 @@
android:layout_below="@+id/tap_to_share"
android:layout_marginTop="24sp"
android:text="@string/if_contact_is_nearby_use_qr"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
android:textAppearance="?textAppearanceBodyMedium" />
<ImageView
android:id="@+id/qr_code"
@ -59,23 +65,19 @@
android:layout_above="@+id/share_button"
android:layout_below="@id/scan_the_code"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerHorizontal="true"
android:layout_margin="24sp"
android:scaleType="fitCenter" />
<Button
android:id="@+id/share_button"
style="@style/Widget.Conversations.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:minWidth="0dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="@string/share"
android:layout_centerHorizontal="true"
android:textColor="?attr/colorAccent" />
android:layout_marginHorizontal="16dp"
android:text="@string/share" />
</RelativeLayout>

View file

@ -2,22 +2,30 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?attr/color_background_primary"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:visibility="gone"
android:id="@+id/in_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
android:gravity="center"
android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -25,18 +33,15 @@
</LinearLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/color_background_primary">
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/color_background_primary"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -7,7 +7,18 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" android:id="@+id/toolbar"/>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
@ -16,15 +27,13 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/color_background_primary">
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:minHeight="256dp"
android:orientation="vertical"
@ -42,50 +51,53 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_your_username"
android:textAppearance="@style/TextAppearance.Conversations.Title" />
android:textAppearance="?textAppearanceTitleLarge" />
<TextView
android:id="@+id/instructions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginVertical="8dp"
android:text="@string/magic_create_text"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
android:textAppearance="?textAppearanceBodyMedium" />
<EditText
android:id="@+id/username"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/username_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:hint="@string/username_hint"
android:textColor="?attr/edit_text_color"
android:inputType="textNoSuggestions" />
android:hint="@string/username_hint">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/full_jid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginVertical="8dp"
android:text="@string/your_full_jid_will_be"
android:textAppearance="@style/TextAppearance.Conversations.Caption"
android:textAppearance="?textAppearanceLabelSmall"
android:visibility="invisible" />
<Button
android:id="@+id/create_account"
style="@style/Widget.Conversations.Button.Borderless"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/next"
android:textColor="?colorAccent" />
android:layout_gravity="end"
android:text="@string/next" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true">
android:layout_alignParentStart="true">
<ImageView
android:layout_width="wrap_content"

View file

@ -7,7 +7,17 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include android:id="@+id/toolbar" layout="@layout/toolbar" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
@ -16,15 +26,13 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/color_background_primary">
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:minHeight="256dp"
android:orientation="vertical"
@ -41,40 +49,38 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pick_a_server"
android:textAppearance="@style/TextAppearance.Conversations.Title" />
android:textAppearance="?textAppearanceTitleLarge" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:text="@string/server_select_text"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
android:textAppearance="?textAppearanceBodyMedium" />
<Button
android:id="@+id/use_cim"
style="@style/Widget.Conversations.Button.Borderless"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/use_conversations.im"
android:textColor="?colorAccent" />
android:layout_gravity="end"
android:text="@string/use_conversations.im" />
<Button
android:id="@+id/use_own_provider"
style="@style/Widget.Conversations.Button.Borderless"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/use_own_provider"
android:textColor="?android:textColorSecondary" />
android:layout_gravity="end"
android:text="@string/use_own_provider" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true">
android:layout_alignParentStart="true">
<ImageView
android:layout_width="wrap_content"

View file

@ -6,9 +6,18 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
@ -17,15 +26,13 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/color_background_primary">
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:minHeight="256dp"
android:orientation="vertical"
@ -42,40 +49,38 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome_header"
android:textAppearance="@style/TextAppearance.Conversations.Title" />
android:textAppearance="?textAppearanceTitleLarge" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:text="@string/do_you_have_an_account"
android:textAppearance="@style/TextAppearance.Conversations.Body1" />
android:textAppearance="?textAppearanceBodyMedium" />
<Button
android:id="@+id/register_new_account"
style="@style/Widget.Conversations.Button.Borderless"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/create_new_account"
android:textColor="?colorAccent" />
android:layout_gravity="end"
android:text="@string/create_new_account" />
<Button
android:id="@+id/use_existing"
style="@style/Widget.Conversations.Button.Borderless"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="@string/i_already_have_an_account"
android:textColor="?android:textColorSecondary" />
android:layout_gravity="end"
android:text="@string/i_already_have_an_account" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true">
android:layout_alignParentStart="true">
<ImageView
android:layout_width="wrap_content"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<LinearLayout
android:layout_width="match_parent"
@ -13,41 +13,35 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/enter_password_to_restore"
android:textAppearance="@style/TextAppearance.Conversations.Body2"/>
android:textAppearance="?textAppearanceBodyMedium" />
<TextView
android:layout_marginTop="?TextSizeBody1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18sp"
android:text="@string/restore_warning"
android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
android:textAppearance="?textAppearanceBodyMedium" />
<TextView
android:layout_marginTop="?TextSizeBody1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18sp"
android:text="@string/restore_warning_continued"
android:textAppearance="@style/TextAppearance.Conversations.Subhead.Bold"/>
android:textAppearance="?textAppearanceBodyMedium" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/account_password_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:passwordToggleDrawable="@drawable/visibility_toggle_drawable"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?android:textColorSecondary"
app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint"
app:errorTextAppearance="@style/TextAppearance.Conversations.Design.Error">
app:endIconMode="password_toggle">
<eu.siacs.conversations.ui.widget.TextInputEditText
android:id="@+id/account_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:inputType="textPassword"
android:textColor="?attr/edit_text_color"
style="@style/Widget.Conversations.EditText"/>
<eu.siacs.conversations.ui.widget.TextInputEditText
android:id="@+id/account_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View file

@ -4,7 +4,7 @@
<item
android:id="@+id/action_share"
android:icon="?attr/icon_share"
android:icon="@drawable/ic_share_24dp"
android:title="@string/invite"
app:showAsAction="always" />
</menu>

View file

@ -1,32 +1,31 @@
<?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">
<item
android:id="@+id/action_add_account"
android:icon="?attr/icon_add_person"
app:showAsAction="always"
android:title="@string/action_add_account"/>
<item
android:id="@+id/action_import_backup"
app:showAsAction="never"
android:title="@string/restore_backup"/>
<item
android:id="@+id/action_add_account_with_cert"
app:showAsAction="never"
android:icon="?attr/icon_add_person"
android:title="@string/action_add_account_with_certificate"
android:visible="true"/>
<item
android:id="@+id/action_enable_all"
android:title="@string/enable_all_accounts"/>
<item
android:id="@+id/action_disable_all"
android:title="@string/disable_all_accounts"/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
app:showAsAction="never"
android:title="@string/action_settings"/>
<item
android:id="@+id/action_add_account"
android:icon="@drawable/ic_person_add_24dp"
android:title="@string/action_add_account"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_import_backup"
android:title="@string/restore_backup"
app:showAsAction="never" />
<item
android:id="@+id/action_add_account_with_cert"
android:title="@string/action_add_account_with_certificate"
android:visible="true"
app:showAsAction="never" />
<item
android:id="@+id/action_enable_all"
android:title="@string/enable_all_accounts" />
<item
android:id="@+id/action_disable_all"
android:title="@string/disable_all_accounts" />
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

View file

@ -3,7 +3,7 @@
<item
android:id="@+id/action_scan_qr_code"
android:icon="?attr/icon_scan_qr_code"
android:icon="@drawable/ic_qr_code_scanner_24dp"
android:orderInCategory="10"
android:title="@string/scan_qr_code"
android:visible="@bool/show_qr_code_scan"

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="md_theme_light_primary">#006E1C</color>
<color name="md_theme_light_onPrimary">#FFFFFF</color>
<color name="md_theme_light_primaryContainer">#98F994</color>
<color name="md_theme_light_onPrimaryContainer">#002204</color>
<color name="md_theme_light_secondary">#52634F</color>
<color name="md_theme_light_onSecondary">#FFFFFF</color>
<color name="md_theme_light_secondaryContainer">#D5E8CF</color>
<color name="md_theme_light_onSecondaryContainer">#111F0F</color>
<color name="md_theme_light_tertiary">#38656A</color>
<color name="md_theme_light_onTertiary">#FFFFFF</color>
<color name="md_theme_light_tertiaryContainer">#BCEBF0</color>
<color name="md_theme_light_onTertiaryContainer">#002023</color>
<color name="md_theme_light_error">#BA1A1A</color>
<color name="md_theme_light_errorContainer">#FFDAD6</color>
<color name="md_theme_light_onError">#FFFFFF</color>
<color name="md_theme_light_onErrorContainer">#410002</color>
<color name="md_theme_light_background">#FCFDF6</color>
<color name="md_theme_light_onBackground">#1A1C19</color>
<color name="md_theme_light_surface">#FCFDF6</color>
<color name="md_theme_light_onSurface">#1A1C19</color>
<color name="md_theme_light_surfaceVariant">#DEE5D8</color>
<color name="md_theme_light_onSurfaceVariant">#424940</color>
<color name="md_theme_light_outline">#72796F</color>
<color name="md_theme_light_inverseOnSurface">#F0F1EB</color>
<color name="md_theme_light_inverseSurface">#2F312D</color>
<color name="md_theme_light_inversePrimary">#7DDC7A</color>
<color name="md_theme_light_shadow">#000000</color>
<color name="md_theme_light_surfaceTint">#006E1C</color>
<color name="md_theme_light_outlineVariant">#C2C9BD</color>
<color name="md_theme_light_scrim">#000000</color>
<color name="md_theme_dark_primary">#7DDC7A</color>
<color name="md_theme_dark_onPrimary">#00390A</color>
<color name="md_theme_dark_primaryContainer">#005313</color>
<color name="md_theme_dark_onPrimaryContainer">#98F994</color>
<color name="md_theme_dark_secondary">#BACCB3</color>
<color name="md_theme_dark_onSecondary">#253423</color>
<color name="md_theme_dark_secondaryContainer">#3B4B38</color>
<color name="md_theme_dark_onSecondaryContainer">#D5E8CF</color>
<color name="md_theme_dark_tertiary">#A0CFD4</color>
<color name="md_theme_dark_onTertiary">#00363B</color>
<color name="md_theme_dark_tertiaryContainer">#1F4D52</color>
<color name="md_theme_dark_onTertiaryContainer">#BCEBF0</color>
<color name="md_theme_dark_error">#FFB4AB</color>
<color name="md_theme_dark_errorContainer">#93000A</color>
<color name="md_theme_dark_onError">#690005</color>
<color name="md_theme_dark_onErrorContainer">#FFDAD6</color>
<color name="md_theme_dark_background">#1A1C19</color>
<color name="md_theme_dark_onBackground">#E2E3DD</color>
<color name="md_theme_dark_surface">#1A1C19</color>
<color name="md_theme_dark_onSurface">#E2E3DD</color>
<color name="md_theme_dark_surfaceVariant">#424940</color>
<color name="md_theme_dark_onSurfaceVariant">#C2C9BD</color>
<color name="md_theme_dark_outline">#8C9388</color>
<color name="md_theme_dark_inverseOnSurface">#1A1C19</color>
<color name="md_theme_dark_inverseSurface">#E2E3DD</color>
<color name="md_theme_dark_inversePrimary">#006E1C</color>
<color name="md_theme_dark_shadow">#000000</color>
<color name="md_theme_dark_surfaceTint">#7DDC7A</color>
<color name="md_theme_dark_outlineVariant">#424940</color>
<color name="md_theme_dark_scrim">#000000</color>
</resources>

View file

@ -47,7 +47,7 @@
<!-- this foreground service type permission is exclusively used for import and export backup -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-feature
android:name="android.hardware.camera"
@ -84,6 +84,7 @@
<application
android:name=".Conversations"
android:allowBackup="true"
android:appCategory="social"
android:dataExtractionRules="@xml/data_extraction_rules"
@ -96,7 +97,7 @@
android:networkSecurityConfig="@xml/network_security_configuration"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/ConversationsTheme"
android:theme="@style/Theme.Conversations3"
tools:targetApi="tiramisu">
<meta-data
@ -132,9 +133,10 @@
</intent-filter>
</service>
<service android:name=".services.CallIntegrationConnectionService"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
android:exported="true">
<service
android:name=".services.CallIntegrationConnectionService"
android:exported="true"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
@ -180,14 +182,14 @@
<activity
android:name=".ui.RecordingActivity"
android:configChanges="orientation|screenSize"
android:theme="@style/ConversationsTheme.Dialog" />
android:theme="@style/Theme.Conversations3.Dialog" />
<activity
android:name=".ui.ShowLocationActivity"
android:label="@string/title_activity_show_location" />
<activity
android:name=".ui.ConversationActivity"
android:exported="true"
android:theme="@style/SplashTheme">
android:theme="@style/Theme.Conversations3.SplashScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -202,7 +204,7 @@
<activity
android:name=".ui.ScanActivity"
android:screenOrientation="portrait"
android:theme="@style/ConversationsTheme.FullScreen"
android:theme="@style/Theme.Conversations3.FullScreen"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".ui.UriHandlerActivity"
@ -263,10 +265,10 @@
</activity>
<activity
android:name=".ui.ChooseContactActivity"
android:label="@string/title_activity_choose_contact" />
android:label="@string/title_activity_choose_contact"/>
<activity
android:name=".ui.BlocklistActivity"
android:label="@string/title_activity_block_list" />
android:label="@string/title_activity_block_list"/>
<activity
android:name=".ui.ChangePasswordActivity"
android:label="@string/change_password_on_server" />
@ -351,7 +353,7 @@
<activity
android:name=".ui.MediaBrowserActivity"
android:label="@string/media_browser" />
android:label="@string/media_browser"/>
<provider
android:name="androidx.core.content.FileProvider"
@ -378,10 +380,10 @@
</activity>
<activity
android:name=".ui.MucUsersActivity"
android:label="@string/group_chat_members" />
android:label="@string/group_chat_members"/>
<activity
android:name=".ui.ChannelDiscoveryActivity"
android:label="@string/discover_channels" />
android:label="@string/discover_channels"/>
<activity
android:name=".ui.RtpSessionActivity"
android:autoRemoveFromRecents="true"

View file

@ -45,8 +45,6 @@ public final class Config {
public static final Jid BUG_REPORTS = Jid.of("bugs@conversations.im");
public static final Uri HELP = Uri.parse("https://help.conversations.im");
public static final String DOMAIN_LOCK = null; // only allow account creation for this domain
public static final String MAGIC_CREATE_DOMAIN = "conversations.im";
public static final Jid QUICKSY_DOMAIN = Jid.of("quicksy.im");

View file

@ -0,0 +1,67 @@
package eu.siacs.conversations;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AppCompatDelegate;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.color.DynamicColorsOptions;
public class Conversations extends Application {
@Override
public void onCreate() {
super.onCreate();
applyThemeSettings();
}
public void applyThemeSettings() {
final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences == null) {
return;
}
applyThemeSettings(sharedPreferences);
}
private void applyThemeSettings(final SharedPreferences sharedPreferences) {
AppCompatDelegate.setDefaultNightMode(getDesiredNightMode(this, sharedPreferences));
var dynamicColorsOptions =
new DynamicColorsOptions.Builder()
.setPrecondition((activity, t) -> isDynamicColorsDesired(activity))
.build();
DynamicColors.applyToActivitiesIfAvailable(this, dynamicColorsOptions);
}
public static int getDesiredNightMode(final Context context) {
final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
if (sharedPreferences == null) {
return AppCompatDelegate.getDefaultNightMode();
}
return getDesiredNightMode(context, sharedPreferences);
}
public static boolean isDynamicColorsDesired(final Context context) {
final var preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getBoolean("dynamic_colors", false);
}
private static int getDesiredNightMode(
final Context context, final SharedPreferences sharedPreferences) {
final String theme =
sharedPreferences.getString("theme", context.getString(R.string.theme));
return getDesiredNightMode(theme);
}
public static int getDesiredNightMode(final String theme) {
if ("automatic".equals(theme)) {
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
} else if ("light".equals(theme)) {
return AppCompatDelegate.MODE_NIGHT_NO;
} else {
return AppCompatDelegate.MODE_NIGHT_YES;
}
}
}

View file

@ -41,18 +41,18 @@ public class RtpSessionStatus {
return new RtpSessionStatus(made, duration);
}
public static @DrawableRes int getDrawable(final boolean received, final boolean successful, final boolean darkTheme) {
public static @DrawableRes int getDrawable(final boolean received, final boolean successful) {
if (received) {
if (successful) {
return darkTheme ? R.drawable.ic_call_received_white_18dp : R.drawable.ic_call_received_black_18dp;
return R.drawable.ic_call_received_24dp;
} else {
return darkTheme ? R.drawable.ic_call_missed_white_18dp : R.drawable.ic_call_missed_black_18dp;
return R.drawable.ic_call_missed_24db;
}
} else {
if (successful) {
return darkTheme ? R.drawable.ic_call_made_white_18dp : R.drawable.ic_call_made_black_18dp;
return R.drawable.ic_call_made_24dp;
} else {
return darkTheme ? R.drawable.ic_call_missed_outgoing_white_18dp : R.drawable.ic_call_missed_outgoing_black_18dp;
return R.drawable.ic_call_missed_outgoing_24dp;
}
}
}

View file

@ -48,7 +48,11 @@ public class BarcodeProvider extends ContentProvider implements ServiceConnectio
return Uri.parse("content://" + packageId + AUTHORITY + "/" + account.getJid().asBareJid() + ".png");
}
public static Bitmap create2dBarcodeBitmap(String input, int size) {
public static Bitmap create2dBarcodeBitmap(final String input, final int size) {
return create2dBarcodeBitmap(input, size, Color.BLACK, Color.WHITE);
}
public static Bitmap create2dBarcodeBitmap(final String input, final int size, final int black, final int white) {
try {
final QRCodeWriter barcodeWriter = new QRCodeWriter();
final Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
@ -61,14 +65,14 @@ public class BarcodeProvider extends ContentProvider implements ServiceConnectio
for (int y = 0; y < height; y++) {
final int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
pixels[offset + x] = result.get(x, y) ? black : white;
}
}
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (final Exception e) {
e.printStackTrace();
Log.e(Config.LOGTAG,"could not generate QR code image",e);
return null;
}
}

View file

@ -266,7 +266,7 @@ public class ExportBackupService extends Service {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.notification_create_backup_title))
.setSmallIcon(R.drawable.ic_archive_white_24dp)
.setSmallIcon(R.drawable.ic_archive_24dp)
.setProgress(1, 0, false);
startForeground(NOTIFICATION_ID, mBuilder.build());
int count = 0;
@ -420,11 +420,11 @@ public class ExportBackupService extends Service {
.getAbsolutePath())))
.setAutoCancel(true)
.setContentIntent(openFolderIntent)
.setSmallIcon(R.drawable.ic_archive_white_24dp);
.setSmallIcon(R.drawable.ic_archive_24dp);
if (shareFilesIntent != null) {
mBuilder.addAction(
R.drawable.ic_share_white_24dp,
R.drawable.ic_share_24dp,
getString(R.string.share_backup_files),
shareFilesIntent);
}

View file

@ -475,7 +475,7 @@ public class NotificationService {
new Builder(mXmppConnectionService, "delivery_failed")
.setContentTitle(conversation.getName())
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_error_white_24dp)
.setSmallIcon(R.drawable.ic_error_24dp)
.setContentText(
mXmppConnectionService
.getResources()
@ -495,7 +495,7 @@ public class NotificationService {
.getQuantityText(
R.plurals.some_messages_could_not_be_delivered,
1024))
.setSmallIcon(R.drawable.ic_error_white_24dp)
.setSmallIcon(R.drawable.ic_error_24dp)
.setGroup("delivery_failed")
.setGroupSummary(true)
.setAutoCancel(true)
@ -569,11 +569,11 @@ public class NotificationService {
new NotificationCompat.Builder(
mXmppConnectionService, INCOMING_CALLS_NOTIFICATION_CHANNEL);
if (media.contains(Media.VIDEO)) {
builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
builder.setSmallIcon(R.drawable.ic_videocam_24dp);
builder.setContentTitle(
mXmppConnectionService.getString(R.string.rtp_state_incoming_video_call));
} else {
builder.setSmallIcon(R.drawable.ic_call_white_24dp);
builder.setSmallIcon(R.drawable.ic_call_24dp);
builder.setContentTitle(
mXmppConnectionService.getString(R.string.rtp_state_incoming_call));
}
@ -596,7 +596,7 @@ public class NotificationService {
builder.setOngoing(true);
builder.addAction(
new NotificationCompat.Action.Builder(
R.drawable.ic_call_end_white_48dp,
R.drawable.ic_call_end_24dp,
mXmppConnectionService.getString(R.string.dismiss_call),
createCallAction(
id.sessionId,
@ -605,7 +605,7 @@ public class NotificationService {
.build());
builder.addAction(
new NotificationCompat.Action.Builder(
R.drawable.ic_call_white_24dp,
R.drawable.ic_call_24dp,
mXmppConnectionService.getString(R.string.answer_call),
createPendingRtpSession(
id, RtpSessionActivity.ACTION_ACCEPT_CALL, 103))
@ -622,7 +622,7 @@ public class NotificationService {
final NotificationCompat.Builder builder =
new NotificationCompat.Builder(mXmppConnectionService, "ongoing_calls");
if (ongoingCall.media.contains(Media.VIDEO)) {
builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
builder.setSmallIcon(R.drawable.ic_videocam_24dp);
if (ongoingCall.reconnecting) {
builder.setContentTitle(
mXmppConnectionService.getString(R.string.reconnecting_video_call));
@ -631,7 +631,7 @@ public class NotificationService {
mXmppConnectionService.getString(R.string.ongoing_video_call));
}
} else {
builder.setSmallIcon(R.drawable.ic_call_white_24dp);
builder.setSmallIcon(R.drawable.ic_call_24dp);
if (ongoingCall.reconnecting) {
builder.setContentTitle(
mXmppConnectionService.getString(R.string.reconnecting_call));
@ -647,7 +647,7 @@ public class NotificationService {
builder.setOngoing(true);
builder.addAction(
new NotificationCompat.Action.Builder(
R.drawable.ic_call_end_white_48dp,
R.drawable.ic_call_end_24dp,
mXmppConnectionService.getString(R.string.hang_up),
createCallAction(
id.sessionId, XmppConnectionService.ACTION_END_CALL, 104))
@ -826,7 +826,7 @@ public class NotificationService {
}
private void markAsReadIfHasDirectReply(final ArrayList<Message> messages) {
if (messages != null && messages.size() > 0) {
if (messages != null && !messages.isEmpty()) {
Message last = messages.get(messages.size() - 1);
if (last.getStatus() != Message.STATUS_RECEIVED) {
if (mXmppConnectionService.markRead((Conversation) last.getConversation(), false)) {
@ -837,7 +837,8 @@ public class NotificationService {
}
private void setNotificationColor(final Builder mBuilder) {
mBuilder.setColor(ContextCompat.getColor(mXmppConnectionService, R.color.green600));
// TODO can we use themed colors?
mBuilder.setColor(ContextCompat.getColor(mXmppConnectionService, R.color.md_theme_light_primary));
}
public void updateNotification() {
@ -1035,7 +1036,7 @@ public class NotificationService {
if (!publicVersion) {
builder.setContentText(Joiner.on(", ").join(names));
}
builder.setSmallIcon(R.drawable.ic_call_missed_white_24db);
builder.setSmallIcon(R.drawable.ic_call_missed_24db);
builder.setGroupSummary(true);
builder.setGroup(MISSED_CALLS_GROUP);
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN);
@ -1085,7 +1086,7 @@ public class NotificationService {
name));
builder.setContentText(name);
}
builder.setSmallIcon(R.drawable.ic_call_missed_white_24db);
builder.setSmallIcon(R.drawable.ic_call_missed_24db);
builder.setGroup(MISSED_CALLS_GROUP);
builder.setCategory(NotificationCompat.CATEGORY_CALL);
builder.setWhen(info.getLastTime());
@ -1221,7 +1222,7 @@ public class NotificationService {
PendingIntent markAsReadPendingIntent = createReadPendingIntent(conversation);
NotificationCompat.Action markReadAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_drafts_white_24dp,
R.drawable.ic_mark_chat_read_24dp,
mXmppConnectionService.getString(R.string.mark_as_read),
markAsReadPendingIntent)
.setSemanticAction(
@ -1232,7 +1233,7 @@ public class NotificationService {
final String lastMessageUuid = Iterables.getLast(messages).getUuid();
final NotificationCompat.Action replyAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_send_text_offline,
R.drawable.ic_send_24dp,
replyLabel,
createReplyIntent(conversation, lastMessageUuid, false))
.setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
@ -1241,7 +1242,7 @@ public class NotificationService {
.build();
final NotificationCompat.Action wearReplyAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_wear_reply,
R.drawable.ic_reply_24dp,
replyLabel,
createReplyIntent(conversation, lastMessageUuid, true))
.addRemoteInput(remoteInput)
@ -1260,7 +1261,7 @@ public class NotificationService {
PendingIntent pendingSnoozeIntent = createSnoozeIntent(conversation);
NotificationCompat.Action snoozeAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_notifications_paused_white_24dp,
R.drawable.ic_notifications_paused_24dp,
label,
pendingSnoozeIntent)
.build();
@ -1279,7 +1280,7 @@ public class NotificationService {
.getString(R.string.show_location);
NotificationCompat.Action locationAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_room_white_24dp,
R.drawable.ic_location_pin_24dp,
label,
pendingShowLocationIntent)
.build();
@ -1303,7 +1304,7 @@ public class NotificationService {
createDownloadIntent(firstDownloadableMessage);
NotificationCompat.Action downloadAction =
new NotificationCompat.Action.Builder(
R.drawable.ic_file_download_white_24dp,
R.drawable.ic_download_24dp,
label,
pendingDownloadIntent)
.build();
@ -1761,21 +1762,21 @@ public class NotificationService {
.setPriority(Notification.PRIORITY_MIN)
.setSmallIcon(
connected > 0
? R.drawable.ic_link_white_24dp
: R.drawable.ic_link_off_white_24dp)
? R.drawable.ic_link_24dp
: R.drawable.ic_link_off_24dp)
.setLocalOnly(true);
if (Compatibility.runsTwentySix()) {
mBuilder.setChannelId("foreground");
mBuilder.addAction(
R.drawable.ic_logout_white_24dp,
R.drawable.ic_logout_24dp,
mXmppConnectionService.getString(R.string.log_out),
pendingServiceIntent(
mXmppConnectionService,
XmppConnectionService.ACTION_TEMPORARILY_DISABLE,
87));
mBuilder.addAction(
R.drawable.ic_notifications_off_white_24dp,
R.drawable.ic_notifications_off_24dp,
mXmppConnectionService.getString(R.string.hide_notification),
pendingNotificationSettingsIntent(mXmppConnectionService));
}
@ -1853,7 +1854,7 @@ public class NotificationService {
}
try {
mBuilder.addAction(
R.drawable.ic_autorenew_white_24dp,
R.drawable.ic_autorenew_24dp,
mXmppConnectionService.getString(R.string.try_again),
pendingServiceIntent(
mXmppConnectionService, XmppConnectionService.ACTION_TRY_AGAIN, 45));
@ -1871,7 +1872,7 @@ public class NotificationService {
if (torNotAvailable) {
if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) {
mBuilder.addAction(
R.drawable.ic_play_circle_filled_white_48dp,
R.drawable.ic_play_circle_24dp,
mXmppConnectionService.getString(R.string.start_orbot),
PendingIntent.getActivity(
mXmppConnectionService,
@ -1883,7 +1884,7 @@ public class NotificationService {
: PendingIntent.FLAG_UPDATE_CURRENT));
} else {
mBuilder.addAction(
R.drawable.ic_file_download_white_24dp,
R.drawable.ic_download_24dp,
mXmppConnectionService.getString(R.string.install_orbot),
PendingIntent.getActivity(
mXmppConnectionService,
@ -1896,7 +1897,7 @@ public class NotificationService {
}
}
mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE);
mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
mBuilder.setSmallIcon(R.drawable.ic_warning_24dp);
mBuilder.setLocalOnly(true);
mBuilder.setPriority(Notification.PRIORITY_LOW);
final Intent intent;
@ -1935,7 +1936,7 @@ public class NotificationService {
} else {
builder.setProgress(100, 0, true);
}
builder.setSmallIcon(R.drawable.ic_hourglass_empty_white_24dp);
builder.setSmallIcon(R.drawable.ic_hourglass_top_24dp);
if (message != null) {
builder.setContentIntent(createContentIntent(message.getConversation()));
}

View file

@ -4760,9 +4760,6 @@ public class XmppConnectionService extends Service {
if (Config.QUICKSY_DOMAIN != null) {
hosts.remove(Config.QUICKSY_DOMAIN.toEscapedString()); //we only want to show this when we type a e164 number
}
if (Config.DOMAIN_LOCK != null) {
hosts.add(Config.DOMAIN_LOCK);
}
if (Config.MAGIC_CREATE_DOMAIN != null) {
hosts.add(Config.MAGIC_CREATE_DOMAIN);
}

View file

@ -1,31 +1,25 @@
package eu.siacs.conversations.ui;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import eu.siacs.conversations.R;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.utils.ThemeHelper;
import static eu.siacs.conversations.ui.XmppActivity.configureActionBar;
public class AboutActivity extends AppCompatActivity {
import android.os.Bundle;
import androidx.databinding.DataBindingUtil;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityAboutBinding;
public class AboutActivity extends BaseActivity {
@Override
protected void onResume(){
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(ThemeHelper.find(this));
final ActivityAboutBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_about);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setContentView(R.layout.activity_about);
setSupportActionBar(findViewById(R.id.toolbar));
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
setTitle(getString(R.string.title_activity_about_x, getString(R.string.app_name)));
}

View file

@ -14,6 +14,7 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import java.util.ArrayList;
@ -34,7 +35,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(final MenuItem item) {
public boolean onMenuItemActionExpand(@NonNull final MenuItem item) {
mSearchEditText.post(() -> {
mSearchEditText.requestFocus();
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@ -45,7 +46,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
}
@Override
public boolean onMenuItemActionCollapse(final MenuItem item) {
public boolean onMenuItemActionCollapse(@NonNull final MenuItem item) {
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
mSearchEditText.setText("");
@ -92,6 +93,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_choose_contact);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
this.binding.chooseContactList.setFastScrollEnabled(true);

View file

@ -8,7 +8,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
public abstract class ActionBarActivity extends AppCompatActivity {
public abstract class ActionBarActivity extends BaseActivity {
public static void configureActionBar(ActionBar actionBar) {
configureActionBar(actionBar, true);
}

View file

@ -0,0 +1,47 @@
package eu.siacs.conversations.ui;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.view.View;
import com.google.android.material.elevation.SurfaceColors;
public final class Activities {
private Activities() {}
public static void setStatusAndNavigationBarColors(final Activity activity, final View view) {
setStatusAndNavigationBarColors(activity, view, false);
}
public static void setStatusAndNavigationBarColors(
final Activity activity, final View view, final boolean raisedStatusBar) {
final var isLightMode = isLightMode(activity);
final var window = activity.getWindow();
final var flags = view.getSystemUiVisibility();
// an elevation of 4 matches the MaterialToolbar elevation
if (raisedStatusBar) {
window.setStatusBarColor(SurfaceColors.SURFACE_5.getColor(activity));
} else {
window.setStatusBarColor(SurfaceColors.SURFACE_0.getColor(activity));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.setNavigationBarColor(SurfaceColors.SURFACE_1.getColor(activity));
if (isLightMode) {
view.setSystemUiVisibility(
flags
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
| View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}
} else if (isLightMode) {
view.setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
private static boolean isLightMode(final Context context) {
final int nightModeFlags =
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
return nightModeFlags != Configuration.UI_MODE_NIGHT_YES;
}
}

View file

@ -0,0 +1,53 @@
package eu.siacs.conversations.ui;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import eu.siacs.conversations.Conversations;
import eu.siacs.conversations.ui.util.SettingsUtils;
public abstract class BaseActivity extends AppCompatActivity {
private Boolean isDynamicColors;
@Override
public void onStart() {
super.onStart();
final int desiredNightMode = Conversations.getDesiredNightMode(this);
if (setDesiredNightMode(desiredNightMode)) {
return;
}
final boolean isDynamicColors = Conversations.isDynamicColorsDesired(this);
setDynamicColors(isDynamicColors);
}
@Override
protected void onResume(){
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
}
public void setDynamicColors(final boolean isDynamicColors) {
if (this.isDynamicColors == null) {
this.isDynamicColors = isDynamicColors;
} else {
if (this.isDynamicColors != isDynamicColors) {
Log.i(
"Recreating {} because dynamic color setting has changed",
getClass().getSimpleName());
recreate();
}
}
}
public boolean setDesiredNightMode(final int desiredNightMode) {
if (desiredNightMode == AppCompatDelegate.getDefaultNightMode()) {
return false;
}
AppCompatDelegate.setDefaultNightMode(desiredNightMode);
Log.i("Recreating {} because desired night mode has changed", getClass().getSimpleName());
recreate();
return true;
}
}

View file

@ -7,6 +7,8 @@ import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.DialogBlockContactBinding;
import eu.siacs.conversations.entities.Blockable;
@ -19,7 +21,7 @@ public final class BlockContactDialog {
show(xmppActivity, blockable, null);
}
public static void show(final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) {
final AlertDialog.Builder builder = new AlertDialog.Builder(xmppActivity);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(xmppActivity);
final boolean isBlocked = blockable.isBlocked();
builder.setNegativeButton(R.string.cancel, null);
DialogBlockContactBinding binding = DataBindingUtil.inflate(xmppActivity.getLayoutInflater(), R.layout.dialog_block_contact, null, false);

View file

@ -3,86 +3,84 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.textfield.TextInputLayout;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityChangePasswordBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.widget.DisabledActionModeCallback;
public class ChangePasswordActivity extends XmppActivity implements XmppConnectionService.OnAccountPasswordChanged {
private Button mChangePasswordButton;
private ActivityChangePasswordBinding binding;
private final View.OnClickListener mOnChangePasswordButtonClicked = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mAccount != null) {
final String currentPassword = mCurrentPassword.getText().toString();
final String newPassword = mNewPassword.getText().toString();
if (!mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(mAccount.getPassword())) {
mCurrentPassword.requestFocus();
mCurrentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
removeErrorsOnAllBut(mCurrentPasswordLayout);
} else if (newPassword.trim().isEmpty()) {
mNewPassword.requestFocus();
mNewPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
removeErrorsOnAllBut(mNewPasswordLayout);
} else {
mCurrentPasswordLayout.setError(null);
mNewPasswordLayout.setError(null);
xmppConnectionService.updateAccountPasswordOnServer(mAccount, newPassword, ChangePasswordActivity.this);
mChangePasswordButton.setEnabled(false);
mChangePasswordButton.setText(R.string.updating);
}
public void onClick(final View view) {
final var account = mAccount;
if (account == null) {
return;
}
final String currentPassword = binding.currentPassword.getText().toString();
final String newPassword = binding.newPassword.getText().toString();
if (!account.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(account.getPassword())) {
binding.currentPassword.requestFocus();
binding.currentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
removeErrorsOnAllBut(binding.currentPasswordLayout);
} else if (newPassword.trim().isEmpty()) {
binding.newPassword.requestFocus();
binding.newPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
removeErrorsOnAllBut(binding.newPasswordLayout);
} else {
binding.currentPasswordLayout.setError(null);
binding.newPasswordLayout.setError(null);
xmppConnectionService.updateAccountPasswordOnServer(account, newPassword, ChangePasswordActivity.this);
binding.changePasswordButton.setEnabled(false);
binding.changePasswordButton.setText(R.string.updating);
}
}
};
private EditText mCurrentPassword;
private EditText mNewPassword;
private TextInputLayout mNewPasswordLayout;
private TextInputLayout mCurrentPasswordLayout;
private Account mAccount;
@Override
void onBackendConnected() {
this.mAccount = extractAccount(getIntent());
if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
this.mCurrentPasswordLayout.setVisibility(View.GONE);
this.binding.currentPasswordLayout.setVisibility(View.GONE);
} else {
this.mCurrentPassword.setVisibility(View.VISIBLE);
this.binding.currentPasswordLayout.setVisibility(View.VISIBLE);
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_change_password);
setSupportActionBar(findViewById(R.id.toolbar));
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_change_password);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
Button mCancelButton = findViewById(R.id.left_button);
mCancelButton.setOnClickListener(view -> finish());
this.mChangePasswordButton = findViewById(R.id.right_button);
this.mChangePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
this.mCurrentPassword = findViewById(R.id.current_password);
this.mCurrentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
this.mNewPassword = findViewById(R.id.new_password);
this.mNewPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
this.mCurrentPasswordLayout = findViewById(R.id.current_password_layout);
this.mNewPasswordLayout = findViewById(R.id.new_password_layout);
binding.cancelButton.setOnClickListener(view -> finish());
binding.changePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
binding.currentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
binding.newPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
Intent intent = getIntent();
String password = intent != null ? intent.getStringExtra("password") : null;
if (password != null) {
this.mNewPassword.getEditableText().clear();
this.mNewPassword.getEditableText().append(password);
binding.newPassword.getEditableText().clear();
binding.newPassword.getEditableText().append(password);
}
}
@ -97,21 +95,21 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
@Override
public void onPasswordChangeFailed() {
runOnUiThread(() -> {
mNewPasswordLayout.setError(getString(R.string.could_not_change_password));
mChangePasswordButton.setEnabled(true);
mChangePasswordButton.setText(R.string.change_password);
binding.newPasswordLayout.setError(getString(R.string.could_not_change_password));
binding.changePasswordButton.setEnabled(true);
binding.changePasswordButton.setText(R.string.change_password);
});
}
private void removeErrorsOnAllBut(TextInputLayout exception) {
if (this.mCurrentPasswordLayout != exception) {
this.mCurrentPasswordLayout.setErrorEnabled(false);
this.mCurrentPasswordLayout.setError(null);
if (this.binding.currentPasswordLayout != exception) {
this.binding.currentPasswordLayout.setErrorEnabled(false);
this.binding.currentPasswordLayout.setError(null);
}
if (this.mNewPasswordLayout != exception) {
this.mNewPasswordLayout.setErrorEnabled(false);
this.mNewPasswordLayout.setError(null);
if (this.binding.newPasswordLayout != exception) {
this.binding.newPasswordLayout.setErrorEnabled(false);
this.binding.newPasswordLayout.setError(null);
}
}

View file

@ -19,8 +19,11 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Strings;
import java.util.Collections;
@ -39,7 +42,6 @@ import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.ui.adapter.ChannelSearchResultAdapter;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.xmpp.Jid;
@ -81,6 +83,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_channel_discovery);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
configureActionBar(getSupportActionBar(), true);
binding.list.setAdapter(this.adapter);
this.adapter.setOnChannelSearchResultSelectedListener(this);
@ -155,7 +158,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
private void toggleLoadingScreen() {
adapter.submitList(Collections.emptyList());
binding.progressBar.setVisibility(View.VISIBLE);
binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
}
@Override
@ -163,13 +166,13 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
super.onStart();
this.method = getMethod(this);
if (!optedIn && method == ChannelDiscoveryService.Method.JABBER_NETWORK) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.channel_discovery_opt_in_title);
builder.setMessage(Html.fromHtml(getString(R.string.channel_discover_opt_in_message)));
builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
builder.setPositiveButton(R.string.confirm, (dialog, which) -> optIn());
builder.setOnCancelListener(dialog -> finish());
final AlertDialog dialog = builder.create();
final androidx.appcompat.app.AlertDialog dialog = builder.create();
dialog.setOnShowListener(d -> {
final TextView textView = dialog.findViewById(android.R.id.message);
if (textView == null) {
@ -186,7 +189,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
private void holdLoading() {
adapter.submitList(Collections.emptyList());
binding.progressBar.setVisibility(View.GONE);
binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
}
@Override
@ -220,10 +223,10 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
runOnUiThread(() -> {
adapter.submitList(results);
binding.progressBar.setVisibility(View.GONE);
if (results.size() == 0) {
binding.list.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_primary_background_no_results));
if (results.isEmpty()) {
binding.list.setBackground(ContextCompat.getDrawable(this,R.drawable.background_no_results));
} else {
binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
}
});
@ -234,11 +237,11 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
final List<String> accounts = AccountUtils.getEnabledAccounts(xmppConnectionService);
if (accounts.size() == 1) {
joinChannelSearchResult(accounts.get(0), result);
} else if (accounts.size() == 0) {
} else if (accounts.isEmpty()) {
Toast.makeText(this, R.string.please_enable_an_account, Toast.LENGTH_LONG).show();
} else {
final AtomicReference<String> account = new AtomicReference<>(accounts.get(0));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.choose_account);
builder.setSingleChoiceItems(accounts.toArray(new CharSequence[0]), 0, (dialog, which) -> account.set(accounts.get(which)));
builder.setPositiveButton(R.string.join, (dialog, which) -> joinChannelSearchResult(account.get(), result));
@ -271,10 +274,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
}
public void joinChannelSearchResult(final String selectedAccount, final Room result) {
final Jid jid =
Config.DOMAIN_LOCK == null
? Jid.ofEscaped(selectedAccount)
: Jid.ofLocalAndDomainEscaped(selectedAccount, Config.DOMAIN_LOCK);
final Jid jid = Jid.ofEscaped(selectedAccount);
final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin);
final Account account = xmppConnectionService.findAccountByJid(jid);
final Conversation conversation =

View file

@ -3,20 +3,21 @@ package eu.siacs.conversations.ui;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.Toast;
import androidx.databinding.DataBindingUtil;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.adapter.AccountAdapter;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.adapter.AccountAdapter;
public class ChooseAccountForProfilePictureActivity extends XmppActivity {
protected final List<Account> accountList = new ArrayList<>();
protected ListView accountListView;
protected AccountAdapter mAccountAdapter;
@Override
@ -28,25 +29,21 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
setSupportActionBar(findViewById(R.id.toolbar));
final ActivityManageAccountsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar(), false);
accountListView = findViewById(R.id.account_list);
this.mAccountAdapter = new AccountAdapter(this, accountList, false);
accountListView.setAdapter(this.mAccountAdapter);
accountListView.setOnItemClickListener((arg0, view, position, arg3) -> {
binding.accountList.setAdapter(this.mAccountAdapter);
binding.accountList.setOnItemClickListener((arg0, view, position, arg3) -> {
final Account account = accountList.get(position);
goToProfilePictureActivity(account);
});
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
}
@Override

View file

@ -9,6 +9,7 @@ import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView.MultiChoiceModeListener;
@ -51,7 +52,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
public static final String EXTRA_SHOW_ENTER_JID = "extra_show_enter_jid";
public static final String EXTRA_CONVERSATION = "extra_conversation";
private static final String EXTRA_FILTERED_CONTACTS = "extra_filtered_contacts";
private final List<String> mActivatedAccounts = new ArrayList<>();
private final ArrayList<String> mActivatedAccounts = new ArrayList<>();
private final Set<String> selected = new HashSet<>();
private Set<String> filterContacts;
@ -130,7 +131,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
if (this.showEnterJid) {
this.binding.fab.show();
} else {
binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
}
final SharedPreferences preferences = getPreferences();
@ -139,7 +140,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
}
private void onFabClicked(View v) {
if (selected.size() == 0) {
if (selected.isEmpty()) {
showEnterJidDialog(null);
} else {
submitSelection();
@ -154,7 +155,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle(getTitleFromIntent());
binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
binding.chooseContactList.setFastScrollEnabled(false);
binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
binding.fab.show();
final View view = getSearchEditText();
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@ -166,12 +168,13 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public void onDestroyActionMode(ActionMode mode) {
this.binding.fab.setImageResource(R.drawable.ic_person_add_white_24dp);
this.binding.fab.setImageResource(R.drawable.ic_person_add_24dp);
if (this.showEnterJid) {
this.binding.fab.show();
} else {
this.binding.fab.hide();
}
binding.chooseContactList.setFastScrollEnabled(true);
selected.clear();
}
@ -199,8 +202,9 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
if (selected.size() != 0) {
getListView().playSoundEffect(0);
getListView().playSoundEffect(SoundEffectConstants.CLICK);
}
getListItemAdapter().notifyDataSetChanged();
Contact item = (Contact) getListItems().get(position);
if (checked) {
selected.add(item.getJid().toString());
@ -361,13 +365,9 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
void onBackendConnected() {
filterContacts();
this.mActivatedAccounts.clear();
for (Account account : xmppConnectionService.getAccounts()) {
for (final Account account : xmppConnectionService.getAccounts()) {
if (account.isEnabled()) {
if (Config.DOMAIN_LOCK != null) {
this.mActivatedAccounts.add(account.getJid().getEscapedLocal());
} else {
this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
}
this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
}
}
ActivityResult activityResult = this.postponedActivityResult.pop();

View file

@ -55,6 +55,8 @@ import me.drakeet.support.toast.ToastCompat;
import static eu.siacs.conversations.entities.Bookmark.printableValue;
import static eu.siacs.conversations.utils.StringUtils.changed;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnConfigurationPushed, XmppConnectionService.OnRoomDestroy, TextWatcher, OnMediaLoaded {
public static final String ACTION_VIEW_MUC = "view_muc";
@ -97,7 +99,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
private final OnClickListener mNotifyStatusClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this);
builder.setTitle(R.string.pref_notification_settings);
String[] choices = {
getString(R.string.notify_on_all_messages),
@ -130,7 +132,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
@Override
public void onClick(View v) {
final MucOptions mucOptions = mConversation.getMucOptions();
AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this);
MucConfiguration configuration = MucConfiguration.get(ConferenceDetailsActivity.this, mAdvancedMode, mucOptions);
builder.setTitle(configuration.title);
final boolean[] values = configuration.values;
@ -168,6 +170,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_details);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings);
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
@ -216,12 +219,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE);
}
@ -277,7 +276,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
final MucOptions mucOptions = mConversation.getMucOptions();
this.binding.mucEditor.setVisibility(View.VISIBLE);
this.binding.mucDisplay.setVisibility(View.GONE);
this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
this.binding.editMucNameButton.setImageResource(R.drawable.ic_cancel_24dp);
final String name = mucOptions.getName();
this.binding.mucEditTitle.setText("");
final boolean owner = mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER);
@ -311,7 +310,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
private void hideEditor() {
this.binding.mucEditor.setVisibility(View.GONE);
this.binding.mucDisplay.setVisibility(View.VISIBLE);
this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_edit_body, R.drawable.ic_edit_black_24dp));
this.binding.editMucNameButton.setImageResource(R.drawable.ic_edit_24dp);
}
private void onMucInfoUpdated(String subject, String name) {
@ -384,7 +383,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
protected void destroyRoom() {
final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(groupChat ? R.string.destroy_room : R.string.destroy_channel);
builder.setMessage(groupChat ? R.string.destroy_room_dialog : R.string.destroy_channel_dialog);
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
@ -434,12 +433,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
final MucOptions mucOptions = mConversation.getMucOptions();
final User self = mucOptions.getSelf();
String account;
if (Config.DOMAIN_LOCK != null) {
account = mConversation.getAccount().getJid().getEscapedLocal();
} else {
account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
}
final String account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details);
this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE);
this.binding.detailsAccount.setText(getString(R.string.using_account, account));
@ -469,7 +463,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor());
MyLinkify.addLinks(spannable, false);
this.binding.mucSubject.setText(spannable);
this.binding.mucSubject.setTextAppearance(this, subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead);
this.binding.mucSubject.setTextAppearance( subject.length() > (hasTitle ? 128 : 196) ? com.google.android.material.R.style.TextAppearance_Material3_BodyMedium : com.google.android.material.R.style.TextAppearance_Material3_BodyLarge);
this.binding.mucSubject.setAutoLinkMask(0);
this.binding.mucSubject.setVisibility(View.VISIBLE);
this.binding.mucSubject.setMovementMethod(LinkMovementMethod.getInstance());
@ -507,24 +501,19 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
this.binding.mucSettings.setVisibility(View.GONE);
}
int ic_notifications = getThemeResource(R.attr.icon_notifications, R.drawable.ic_notifications_black_24dp);
int ic_notifications_off = getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
int ic_notifications_paused = getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp);
int ic_notifications_none = getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
long mutedTill = mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
final long mutedTill = mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
if (mutedTill == Long.MAX_VALUE) {
this.binding.notificationStatusText.setText(R.string.notify_never);
this.binding.notificationStatusButton.setImageResource(ic_notifications_off);
this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_off_24dp);
} else if (System.currentTimeMillis() < mutedTill) {
this.binding.notificationStatusText.setText(R.string.notify_paused);
this.binding.notificationStatusButton.setImageResource(ic_notifications_paused);
this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_paused_24dp);
} else if (mConversation.alwaysNotify()) {
this.binding.notificationStatusText.setText(R.string.notify_on_all_messages);
this.binding.notificationStatusButton.setImageResource(ic_notifications);
this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_24dp);
} else {
this.binding.notificationStatusText.setText(R.string.notify_only_when_highlighted);
this.binding.notificationStatusButton.setImageResource(ic_notifications_none);
this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_none_24dp);
}
final List<User> users = mucOptions.getUsers();
Collections.sort(users, (a, b) -> {
@ -629,9 +618,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
boolean subjectChanged = changed(binding.mucEditSubject.getEditableText().toString(), mucOptions.getSubject());
boolean nameChanged = changed(binding.mucEditTitle.getEditableText().toString(), mucOptions.getName());
if (subjectChanged || nameChanged) {
this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_save, R.drawable.ic_save_black_24dp));
this.binding.editMucNameButton.setImageResource(R.drawable.ic_save_24dp);
} else {
this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
this.binding.editMucNameButton.setImageResource(R.drawable.ic_cancel_24dp);
}
}
}

View file

@ -30,6 +30,9 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.openintents.openpgp.util.OpenPgpUtils;
import java.util.Collection;
@ -144,7 +147,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
} else {
value = jid.toEscapedString();
}
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.action_add_phone_book));
builder.setMessage(getString(R.string.add_phone_book_text, value));
builder.setNegativeButton(getString(R.string.cancel), null);
@ -215,6 +218,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
this.messageFingerprint = getIntent().getStringExtra("fingerprint");
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_contact_details);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
@ -238,14 +242,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
} else {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
this.showLastSeen = preferences.getBoolean("last_activity", false);
}
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
this.showLastSeen = preferences.getBoolean("last_activity", false);
binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE);
mMediaAdapter.setAttachments(Collections.emptyList());
}
@ -268,8 +267,6 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
if (MenuDoubleTabUtil.shouldIgnoreTap()) {
return false;
}
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setNegativeButton(getString(R.string.cancel), null);
switch (menuItem.getItemId()) {
case android.R.id.home:
finish();
@ -281,6 +278,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
shareLink(false);
break;
case R.id.action_delete_contact:
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setNegativeButton(getString(R.string.cancel), null);
builder.setTitle(getString(R.string.action_delete_contact))
.setMessage(JidDialog.style(this, R.string.remove_contact_text, contact.getJid().toEscapedString()))
.setPositiveButton(getString(R.string.delete),
@ -431,12 +430,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
}
binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid()));
String account;
if (Config.DOMAIN_LOCK != null) {
account = contact.getAccount().getJid().getEscapedLocal();
} else {
account = contact.getAccount().getJid().asBareJid().toEscapedString();
}
final String account = contact.getAccount().getJid().asBareJid().toEscapedString();
binding.detailsAccount.setText(getString(R.string.using_account, account));
AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size);
binding.detailsContactBadge.setOnClickListener(this::onBadgeClick);
@ -498,7 +492,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
TextView keyType = view.findViewById(R.id.key_type);
keyType.setText(R.string.openpgp_key_id);
if ("pgp".equals(messageFingerprint)) {
keyType.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
keyType.setTextColor(MaterialColors.getColor(keyType, com.google.android.material.R.attr.colorPrimaryVariant));
}
key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId()));
final OnClickListener openKey = v -> launchOpenKeyChain(contact.getPgpKeyId());
@ -510,7 +504,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
binding.keysWrapper.setVisibility(hasKeys ? View.VISIBLE : View.GONE);
List<ListItem.Tag> tagList = contact.getTags(this);
if (tagList.size() == 0 || !this.showDynamicTags) {
if (tagList.isEmpty() || !this.showDynamicTags) {
binding.tags.setVisibility(View.GONE);
} else {
binding.tags.setVisibility(View.VISIBLE);

View file

@ -16,10 +16,4 @@ public class ConversationActivity extends AppCompatActivity {
startActivity(new Intent(this, ConversationsActivity.class));
finish();
}
@Override
protected void onResume(){
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
}
}

View file

@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -63,6 +64,7 @@ import androidx.core.view.inputmethod.InputConnectionCompat;
import androidx.core.view.inputmethod.InputContentInfoCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
@ -1062,7 +1064,7 @@ public class ConversationFragment extends XmppFragment
};
if (conversation == null
|| conversation.getMode() == Conversation.MODE_MULTI
|| Attachment.canBeSendInband(attachments)
|| Attachment.canBeSendInBand(attachments)
|| (conversation.getAccount().httpUploadAvailable()
&& FileBackend.allFilesUnderSize(
getActivity(), attachments, getMaxHttpUploadSize(conversation)))) {
@ -1934,8 +1936,8 @@ public class ConversationFragment extends XmppFragment
@SuppressLint("InflateParams")
protected void clearHistoryDialog(final Conversation conversation) {
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
builder.setTitle(getString(R.string.clear_conversation_history));
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.clear_conversation_history);
final View dialogView =
requireActivity().getLayoutInflater().inflate(R.layout.dialog_clear_history, null);
final CheckBox endConversationCheckBox =
@ -1958,7 +1960,7 @@ public class ConversationFragment extends XmppFragment
}
protected void muteConversationDialog(final Conversation conversation) {
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.disable_notifications);
final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
final CharSequence[] labels = new CharSequence[durations.length];
@ -2132,7 +2134,7 @@ public class ConversationFragment extends XmppFragment
}
private void showErrorMessage(final Message message) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.error_message);
final String errorMessage = message.getErrorMessage();
final String[] errorMessageParts =
@ -2159,7 +2161,7 @@ public class ConversationFragment extends XmppFragment
}
private void deleteFile(final Message message) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.delete_file_dialog);
builder.setMessage(R.string.delete_file_dialog_msg);
@ -2921,10 +2923,11 @@ public class ConversationFragment extends XmppFragment
status = Presence.Status.OFFLINE;
}
this.binding.textSendButton.setTag(action);
this.binding.textSendButton.setIconResource(SendButtonTool.getSendButtonImageResource(action));
this.binding.textSendButton.setIconTint(ColorStateList.valueOf(SendButtonTool.getSendButtonColor(this.binding.textSendButton, status)));
// TODO send button color
final Activity activity = getActivity();
if (activity != null) {
this.binding.textSendButton.setImageResource(
SendButtonTool.getSendButtonImageResource(activity, action, status));
}
}
@ -3247,9 +3250,8 @@ public class ConversationFragment extends XmppFragment
});
}
public void showNoPGPKeyDialog(boolean plural, DialogInterface.OnClickListener listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setIconAttribute(android.R.attr.alertDialogIcon);
public void showNoPGPKeyDialog(final boolean plural, final DialogInterface.OnClickListener listener) {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
if (plural) {
builder.setTitle(getString(R.string.no_pgp_keys));
builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));

View file

@ -59,18 +59,18 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.openintents.openpgp.util.OpenPgpApi;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
import eu.siacs.conversations.databinding.ActivityConversationsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
@ -80,11 +80,11 @@ import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationRead;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
import eu.siacs.conversations.ui.interfaces.OnConversationsListItemUpdated;
import eu.siacs.conversations.ui.util.ActionBarUtil;
import eu.siacs.conversations.ui.util.ActivityResult;
import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ToolbarUtils;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.XmppUri;
@ -227,10 +227,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
private boolean openBatteryOptimizationDialogIfNeeded() {
if (isOptimizingBattery()
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
&& getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
if (isOptimizingBattery() && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.battery_optimizations_enabled);
builder.setMessage(getString(R.string.battery_optimizations_enabled_dialog, getString(R.string.app_name)));
builder.setPositiveButton(R.string.next, (dialog, which) -> {
@ -372,6 +370,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
ConversationMenuConfigurator.reloadFeatures(this);
OmemoSetting.load(this);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_conversations);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
this.getFragmentManager().addOnBackStackChangedListener(this::invalidateActionBarTitle);
@ -466,9 +465,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
conversationFragment.reInit(conversation, extras == null ? new Bundle() : extras);
if (mainNeedsRefresh) {
refreshFragment(R.id.main_fragment);
} else {
invalidateActionBarTitle();
}
invalidateActionBarTitle();
}
private static void executePendingTransactions(final FragmentManager fragmentManager) {
@ -546,15 +544,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
this.mSkipBackgroundBinding = true;
recreate();
} else {
this.mSkipBackgroundBinding = false;
}
mRedirectInProcess.set(false);
}
@ -630,21 +621,31 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
}
final FragmentManager fragmentManager = getFragmentManager();
final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
if (mainFragment instanceof ConversationFragment) {
final Conversation conversation = ((ConversationFragment) mainFragment).getConversation();
if (mainFragment instanceof ConversationFragment conversationFragment) {
final Conversation conversation = conversationFragment.getConversation();
if (conversation != null) {
actionBar.setTitle(conversation.getName());
actionBar.setDisplayHomeAsUpEnabled(true);
ActionBarUtil.setActionBarOnClickListener(
ToolbarUtils.setActionBarOnClickListener(
binding.toolbar,
(v) -> openConversationDetails(conversation)
);
return;
}
}
actionBar.setTitle(R.string.app_name);
final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
if (secondaryFragment instanceof ConversationFragment conversationFragment) {
final Conversation conversation = conversationFragment.getConversation();
if (conversation != null) {
actionBar.setTitle(conversation.getName());
} else {
actionBar.setTitle(R.string.app_name);
}
} else {
actionBar.setTitle(R.string.app_name);
}
actionBar.setDisplayHomeAsUpEnabled(false);
ActionBarUtil.resetActionBarOnClickListeners(binding.toolbar);
ToolbarUtils.resetActionBarOnClickListeners(binding.toolbar);
}
private void openConversationDetails(final Conversation conversation) {

View file

@ -50,6 +50,8 @@ import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.collect.Collections2;
@ -72,10 +74,8 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
import eu.siacs.conversations.ui.util.PendingActionHelper;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ScrollState;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.EasyOnboardingInvite;
import eu.siacs.conversations.utils.ThemeHelper;
import static androidx.recyclerview.widget.ItemTouchHelper.LEFT;
import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
@ -111,7 +111,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
Paint paint = new Paint();
paint.setColor(StyledAttributes.getColor(activity,R.attr.conversations_overview_background));
paint.setColor(MaterialColors.getColor(viewHolder.itemView, com.google.android.material.R.attr.colorSecondaryFixedDim));
paint.setStyle(Paint.Style.FILL);
c.drawRect(viewHolder.itemView.getLeft(),viewHolder.itemView.getTop()
,viewHolder.itemView.getRight(),viewHolder.itemView.getBottom(), paint);
@ -196,8 +196,6 @@ public class ConversationsOverviewFragment extends XmppFragment {
activity.xmppConnectionService.archiveConversation(c);
}
});
ThemeHelper.fix(snackbar);
snackbar.show();
}
};
@ -381,14 +379,14 @@ public class ConversationsOverviewFragment extends XmppFragment {
private void selectAccountToStartEasyInvite() {
final List<Account> accounts = EasyOnboardingInvite.getSupportingAccounts(activity.xmppConnectionService);
if (accounts.size() == 0) {
if (accounts.isEmpty()) {
//This can technically happen if opening the menu item races with accounts reconnecting or something
Toast.makeText(getActivity(),R.string.no_active_accounts_support_this, Toast.LENGTH_LONG).show();
} else if (accounts.size() == 1) {
openEasyInviteScreen(accounts.get(0));
} else {
final AtomicReference<Account> selectedAccount = new AtomicReference<>(accounts.get(0));
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity);
final MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(activity);
alertDialogBuilder.setTitle(R.string.choose_account);
final String[] asStrings = Collections2.transform(accounts, a -> a.getJid().asBareJid().toEscapedString()).toArray(new String[0]);
alertDialogBuilder.setSingleChoiceItems(asStrings, 0, (dialog, which) -> selectedAccount.set(accounts.get(which)));

View file

@ -3,18 +3,20 @@ package eu.siacs.conversations.ui;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.widget.Spinner;
import android.widget.AutoCompleteTextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.CreateConferenceDialogBinding;
import eu.siacs.conversations.databinding.DialogCreateConferenceBinding;
import eu.siacs.conversations.ui.util.DelayedHintHelper;
public class CreatePrivateGroupChatDialog extends DialogFragment {
@ -39,9 +41,9 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.create_private_group_chat);
CreateConferenceDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_conference_dialog, null, false);
final DialogCreateConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_conference, null, false);
ArrayList<String> mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY);
StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account);
builder.setView(binding.getRoot());
@ -57,7 +59,7 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
public interface CreateConferenceDialogListener {
void onCreateDialogPositiveClick(Spinner spinner, String subject);
void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String subject);
}
@Override

View file

@ -17,13 +17,14 @@ import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
import java.security.SecureRandom;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.CreatePublicChannelDialogBinding;
import eu.siacs.conversations.databinding.DialogCreatePublicChannelBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
@ -44,7 +45,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
private boolean nameEntered = false;
private boolean skipTetxWatcher = false;
public static CreatePublicChannelDialog newInstance(List<String> accounts) {
public static CreatePublicChannelDialog newInstance(final List<String> accounts) {
CreatePublicChannelDialog dialog = new CreatePublicChannelDialog();
Bundle bundle = new Bundle();
bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) accounts);
@ -63,9 +64,9 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
public Dialog onCreateDialog(Bundle savedInstanceState) {
jidWasModified = savedInstanceState != null && savedInstanceState.getBoolean("jid_was_modified_false", false);
nameEntered = savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.create_public_channel);
final CreatePublicChannelDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_public_channel_dialog, null, false);
final DialogCreatePublicChannelBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_public_channel, null, false);
binding.account.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@ -107,7 +108,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
builder.setPositiveButton(nameEntered ? R.string.create : R.string.next, null);
builder.setNegativeButton(nameEntered ? R.string.back : R.string.cancel, null);
DelayedHintHelper.setHint(R.string.channel_bare_jid_example, binding.jid);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
binding.jid.setAdapter(knownHostsAdapter);
final AlertDialog dialog = builder.create();
binding.groupChatName.setOnEditorActionListener((v, actionId, event) -> {
@ -121,7 +122,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
return dialog;
}
private void updateJidSuggestion(CreatePublicChannelDialogBinding binding) {
private void updateJidSuggestion(final DialogCreatePublicChannelBinding binding) {
if (jidWasModified) {
return;
}
@ -138,7 +139,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
super.onSaveInstanceState(outState);
}
private static String getJidSuggestion(CreatePublicChannelDialogBinding binding) {
private static String getJidSuggestion(final DialogCreatePublicChannelBinding binding) {
final Account account = StartConversationActivity.getSelectedAccount(binding.getRoot().getContext(), binding.account);
final XmppConnection connection = account == null ? null : account.getXmppConnection();
if (connection == null) {
@ -169,7 +170,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
return name.replaceAll("\\s+","-");
}
private void goBack(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
private void goBack(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
if (nameEntered) {
nameEntered = false;
updateInputs(binding, true);
@ -179,7 +180,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
}
private void submit(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
private void submit(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
final Context context = binding.getRoot().getContext();
final Editable nameText = binding.groupChatName.getText();
final String name = nameText == null ? "" : nameText.toString().trim();
@ -227,7 +228,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
private void updateInputs(CreatePublicChannelDialogBinding binding, boolean requestFocus) {
private void updateInputs(final DialogCreatePublicChannelBinding binding, final boolean requestFocus) {
binding.xmppAddressLayout.setVisibility(nameEntered ? View.VISIBLE : View.GONE);
binding.nameLayout.setVisibility(nameEntered ? View.GONE : View.VISIBLE);
if (!requestFocus) {
@ -265,7 +266,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
}
@Override
public void onAttach(Context context) {
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
mListener = (CreatePublicChannelDialogListener) context;

View file

@ -33,9 +33,10 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog.Builder;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import com.google.common.base.CharMatcher;
@ -98,7 +99,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private Jid jidToEdit;
private boolean mInitMode = false;
private Boolean mForceRegister = null;
private boolean mUsernameMode = Config.DOMAIN_LOCK != null;
private boolean mUsernameMode = false;
private boolean mShowOptions = false;
private Account mAccount;
private final OnClickListener mCancelButtonClickListener = v -> {
@ -609,6 +610,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.mSavedInstanceInit = savedInstanceState.getBoolean("initMode", false);
}
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_edit_account);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.accountJid.addTextChangedListener(this.mTextWatcher);
binding.accountJid.setOnFocusChangeListener(this.mEditTextFocusListener);
@ -697,13 +699,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
final Intent intent = getIntent();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
} else if (intent != null) {
if (intent != null) {
try {
this.jidToEdit = Jid.ofEscaped(intent.getStringExtra("jid"));
} catch (final IllegalArgumentException | NullPointerException ignored) {
@ -758,7 +757,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
private void displayVerificationWarningDialog(final XmppUri xmppUri) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.verify_omemo_keys);
View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
final CheckBox isTrustedSource = view.findViewById(R.id.trusted_source);
@ -773,7 +772,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
});
builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
AlertDialog dialog = builder.create();
final var dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(d -> finish());
dialog.show();
@ -835,7 +834,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.binding.accountJidLayout.setHint(getString(R.string.username_hint));
} else {
final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
R.layout.simple_list_item,
R.layout.item_autocomplete,
xmppConnectionService.getKnownHosts());
this.binding.accountJid.setAdapter(mKnownHostsAdapter);
}
@ -853,7 +852,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mAccount != null && mAccount.getJid().getDomain() != null) {
return mAccount.getServer();
} else {
return Config.DOMAIN_LOCK;
return null;
}
}
@ -940,7 +939,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private void changePresence() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean manualStatus = sharedPreferences.getBoolean(SettingsActivity.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false);
String current = mAccount.getPresenceStatusMessage();
if (current != null && !current.trim().isEmpty()) {
@ -949,7 +948,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
setAvailabilityRadioButton(mAccount.getPresenceStatus(), binding);
binding.show.setVisibility(manualStatus ? View.VISIBLE : View.GONE);
List<PresenceTemplate> templates = xmppConnectionService.getPresenceTemplates(mAccount);
PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.simple_list_item, templates);
PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.item_autocomplete, templates);
binding.statusMessage.setAdapter(presenceTemplateAdapter);
binding.statusMessage.setOnItemClickListener((parent, view, position, id) -> {
PresenceTemplate template = (PresenceTemplate) parent.getItemAtPosition(position);
@ -1144,7 +1143,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
this.binding.pgpFingerprint.setText(OpenPgpUtils.convertKeyIdToHex(pgpKeyId));
this.binding.pgpFingerprint.setOnClickListener(openPgp);
if ("pgp".equals(messageFingerprint)) {
this.binding.pgpFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
this.binding.pgpFingerprintDesc.setTextColor(MaterialColors.getColor(binding.pgpFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
}
this.binding.pgpFingerprintDesc.setOnClickListener(openPgp);
this.binding.actionDeletePgp.setOnClickListener(delete);
@ -1155,10 +1154,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
this.binding.axolotlFingerprintBox.setVisibility(View.VISIBLE);
if (ownAxolotlFingerprint.equals(messageFingerprint)) {
this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint_selected_message);
} else {
this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption);
this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorOnSurface));
this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint);
}
this.binding.axolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(ownAxolotlFingerprint.substring(2)));
@ -1222,10 +1221,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
private void updateDisplayName(String displayName) {
if (TextUtils.isEmpty(displayName)) {
this.binding.yourName.setText(R.string.no_name_set_instructions);
this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1_Tertiary);
this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
} else {
this.binding.yourName.setText(displayName);
this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1);
this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
}
}
@ -1249,7 +1248,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
private void showDeletePgpDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.unpublish_pgp);
builder.setMessage(R.string.unpublish_pgp_message);
builder.setNegativeButton(R.string.cancel, null);
@ -1279,7 +1278,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
Toast.makeText(EditAccountActivity.this, getString(R.string.device_does_not_support_data_saver, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
}
});
} else if (showBatteryWarning && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
} else if (showBatteryWarning) {
this.binding.osOptimizationDisable.setText(R.string.disable);
this.binding.osOptimizationHeadline.setText(R.string.battery_optimizations_enabled);
this.binding.osOptimizationBody.setText(getString(R.string.battery_optimizations_enabled_explained, getString(R.string.app_name)));
@ -1297,7 +1296,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
}
public void showWipePepDialog() {
Builder builder = new Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.clear_other_devices));
builder.setIconAttribute(android.R.attr.alertDialogIcon);
builder.setMessage(getString(R.string.clear_other_devices_desc));
@ -1324,7 +1323,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mCaptchaDialog != null && mCaptchaDialog.isShowing()) {
mCaptchaDialog.dismiss();
}
final Builder builder = new Builder(EditAccountActivity.this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
final View view = getLayoutInflater().inflate(R.layout.captcha, null);
final ImageView imageView = view.findViewById(R.id.captcha);
final EditText input = view.findViewById(R.id.input);
@ -1372,7 +1371,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
if (mFetchingMamPrefsToast != null) {
mFetchingMamPrefsToast.cancel();
}
Builder builder = new Builder(EditAccountActivity.this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
builder.setTitle(R.string.server_side_mam_prefs);
String defaultAttr = prefs.getAttribute("default");
final List<String> defaults = Arrays.asList("never", "roster", "always");

View file

@ -13,15 +13,17 @@ import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.EnterJidDialogBinding;
import eu.siacs.conversations.databinding.DialogEnterJidBinding;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
@ -46,28 +48,28 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
private KnownHostsAdapter knownHostsAdapter;
private Collection<String> whitelistedDomains = Collections.emptyList();
private EnterJidDialogBinding binding;
private DialogEnterJidBinding binding;
private AlertDialog dialog;
private boolean sanityCheckJid = false;
private boolean issuedWarning = false;
public static EnterJidDialog newInstance(
final List<String> activatedAccounts,
final ArrayList<String> activatedAccounts,
final String title,
final String positiveButton,
final String prefilledJid,
final String account,
boolean allowEditJid,
final boolean sanity_check_jid) {
EnterJidDialog dialog = new EnterJidDialog();
final EnterJidDialog dialog = new EnterJidDialog();
Bundle bundle = new Bundle();
bundle.putString(TITLE_KEY, title);
bundle.putString(POSITIVE_BUTTON_KEY, positiveButton);
bundle.putString(PREFILLED_JID_KEY, prefilledJid);
bundle.putString(ACCOUNT_KEY, account);
bundle.putBoolean(ALLOW_EDIT_JID_KEY, allowEditJid);
bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) activatedAccounts);
bundle.putStringArrayList(ACCOUNTS_LIST_KEY, activatedAccounts);
bundle.putBoolean(SANITY_CHECK_JID, sanity_check_jid);
dialog.setArguments(bundle);
return dialog;
@ -91,16 +93,16 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getArguments().getString(TITLE_KEY));
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final var arguments = getArguments();
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(arguments.getString(TITLE_KEY));
binding =
DataBindingUtil.inflate(
getActivity().getLayoutInflater(), R.layout.enter_jid_dialog, null, false);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
DataBindingUtil.inflate(requireActivity().getLayoutInflater(), R.layout.dialog_enter_jid, null, false);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
binding.jid.setAdapter(this.knownHostsAdapter);
binding.jid.addTextChangedListener(this);
String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
final String prefilledJid = arguments.getString(PREFILLED_JID_KEY);
if (prefilledJid != null) {
binding.jid.append(prefilledJid);
if (!getArguments().getBoolean(ALLOW_EDIT_JID_KEY)) {
@ -114,18 +116,18 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
DelayedHintHelper.setHint(R.string.account_settings_example_jabber_id, binding.jid);
String account = getArguments().getString(ACCOUNT_KEY);
if (account == null) {
final String account = getArguments().getString(ACCOUNT_KEY);
if (Strings.isNullOrEmpty(account)) {
StartConversationActivity.populateAccountSpinner(
getActivity(),
getArguments().getStringArrayList(ACCOUNTS_LIST_KEY),
arguments.getStringArrayList(ACCOUNTS_LIST_KEY),
binding.account);
} else {
ArrayAdapter<String> adapter =
new ArrayAdapter<>(
getActivity(), R.layout.simple_list_item, new String[] {account});
final ArrayAdapter<String> adapter =
new ArrayAdapter<>(requireActivity(), R.layout.item_autocomplete, new String[] {account});
binding.account.setText(account);
binding.account.setEnabled(false);
adapter.setDropDownViewResource(R.layout.simple_list_item);
adapter.setDropDownViewResource(R.layout.item_autocomplete);
binding.account.setAdapter(adapter);
}
@ -135,9 +137,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
this.dialog = builder.create();
View.OnClickListener dialogOnClick =
v -> {
handleEnter(binding, account);
};
v -> handleEnter(binding, account);
binding.jid.setOnEditorActionListener(
(v, actionId, event) -> {
@ -150,21 +150,13 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
return dialog;
}
private void handleEnter(EnterJidDialogBinding binding, String account) {
private void handleEnter(DialogEnterJidBinding binding, String account) {
final Jid accountJid;
if (!binding.account.isEnabled() && account == null) {
return;
}
try {
if (Config.DOMAIN_LOCK != null) {
accountJid =
Jid.ofEscaped(
(String) binding.account.getSelectedItem(),
Config.DOMAIN_LOCK,
null);
} else {
accountJid = Jid.ofEscaped((String) binding.account.getSelectedItem());
}
accountJid = Jid.ofEscaped((String) binding.account.getEditableText().toString());
} catch (final IllegalArgumentException e) {
return;
}

View file

@ -13,6 +13,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.DialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import java.util.ArrayList;
@ -50,11 +51,11 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(R.string.join_public_channel);
DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
final DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
DelayedHintHelper.setHint(R.string.channel_full_jid_example, binding.jid);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
binding.jid.setAdapter(knownHostsAdapter);
String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
if (prefilledJid != null) {
@ -117,6 +118,6 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
}
public interface JoinConferenceDialogListener {
void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
}
}

View file

@ -40,7 +40,6 @@ import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.utils.ThemeHelper;
public abstract class LocationActivity extends ActionBarActivity implements LocationListener {
protected LocationManager locationManager;
@ -78,7 +77,6 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context ctx = getApplicationContext();
setTheme(ThemeHelper.find(this));
final PackageManager packageManager = ctx.getPackageManager();
hasLocationFeature = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION) ||
@ -90,7 +88,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
// Ask for location permissions if location services are enabled and we're
// just starting the activity (we don't want to keep pestering them on every
// screen rotation or if there's no point because it's disabled anyways).
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && savedInstanceState == null) {
if (savedInstanceState == null) {
requestPermissions(REQUEST_CODE_CREATE);
}
@ -224,7 +222,6 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
@Override
protected void onResume() {
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
Configuration.getInstance().load(this, getPreferences());
map.onResume();
this.setMyLoc(null);

View file

@ -29,6 +29,7 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_media_browser);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);

View file

@ -33,6 +33,8 @@ import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -40,7 +42,6 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.MTMDecision;
import eu.siacs.conversations.services.MemorizingTrustManager;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.utils.ThemeHelper;
public class MemorizingActivity extends AppCompatActivity implements OnClickListener, OnCancelListener {
@ -53,10 +54,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList
@Override
public void onCreate(Bundle savedInstanceState) {
LOGGER.log(Level.FINE, "onCreate");
setTheme(ThemeHelper.find(this));
super.onCreate(savedInstanceState);
getLayoutInflater().inflate(R.layout.toolbar, findViewById(android.R.id.content));
setSupportActionBar(findViewById(R.id.toolbar));
}
@Override
@ -69,7 +67,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList
int titleId = i.getIntExtra(MemorizingTrustManager.DECISION_TITLE_ID, R.string.mtm_accept_cert);
String cert = i.getStringExtra(MemorizingTrustManager.DECISION_INTENT_CERT);
LOGGER.log(Level.FINE, "onResume with " + i.getExtras() + " decId=" + decisionId + " data: " + i.getData());
dialog = new AlertDialog.Builder(this).setTitle(titleId)
dialog = new MaterialAlertDialogBuilder(this).setTitle(titleId)
.setMessage(cert)
.setPositiveButton(R.string.always, this)
.setNeutralButton(R.string.once, this)

View file

@ -102,8 +102,9 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
final ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
configureActionBar(getSupportActionBar(), true);
this.userAdapter = new UserAdapter(getPreferences().getBoolean("advanced_muc_mode", false));
binding.list.setAdapter(this.userAdapter);

View file

@ -11,6 +11,9 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
@ -33,10 +36,7 @@ public abstract class OmemoActivity extends XmppActivity {
Object account = v.getTag(R.id.TAG_ACCOUNT);
Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT);
Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);
if (account != null
&& fingerprint != null
&& account instanceof Account
&& fingerprintStatus != null
if (account instanceof Account
&& fingerprint instanceof String
&& fingerprintStatus instanceof FingerprintStatus) {
getMenuInflater().inflate(R.menu.omemo_key_context, menu);
@ -130,8 +130,8 @@ public abstract class OmemoActivity extends XmppActivity {
binding.tglTrust.setChecked(status.isTrusted());
if (status.isActive()) {
binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint);
binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption);
binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurface));
binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurface));
if (status.isVerified()) {
binding.verifiedFingerprint.setVisibility(View.VISIBLE);
binding.verifiedFingerprint.setAlpha(1.0f);
@ -157,8 +157,8 @@ public abstract class OmemoActivity extends XmppActivity {
toast = v -> hideToast();
}
} else {
binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint_Disabled);
binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Disabled);
binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurfaceVariant));
binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurfaceVariant));
toast = v -> replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
if (status.isVerified()) {
binding.tglTrust.setVisibility(View.GONE);
@ -181,7 +181,7 @@ public abstract class OmemoActivity extends XmppActivity {
binding.keyType.setVisibility(View.GONE);
}
if (highlight) {
binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Highlight);
binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorPrimaryVariant));
binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
} else {
binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
@ -191,7 +191,7 @@ public abstract class OmemoActivity extends XmppActivity {
}
public void showPurgeKeyDialog(final Account account, final String fingerprint) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.distrust_omemo_key);
builder.setMessage(R.string.distrust_omemo_key_text);
builder.setNegativeButton(getString(R.string.cancel), null);

View file

@ -91,6 +91,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(this.binding.toolbar);
configureActionBar(getSupportActionBar());
this.binding.cancelButton.setOnClickListener((v) -> this.finish());
@ -114,6 +115,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
final CropImage.ActivityResult result = CropImage.getActivityResult(data);
if (resultCode == RESULT_OK) {

View file

@ -18,6 +18,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.databinding.DataBindingUtil;
import com.canhub.cropper.CropImage;
@ -25,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityPublishProfilePictureBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
@ -77,7 +79,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
public void onAvatarPublicationFailed(int res) {
runOnUiThread(() -> {
hintOrWarning.setText(res);
hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
hintOrWarning.setVisibility(View.VISIBLE);
publishing = false;
togglePublishButton(true, R.string.publish);
@ -87,8 +88,12 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_publish_profile_picture);
setSupportActionBar(findViewById(R.id.toolbar));
ActivityPublishProfilePictureBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
this.avatar = findViewById(R.id.account_image);
this.cancelButton = findViewById(R.id.cancel_button);
@ -220,7 +225,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
final Intent intent = getIntent();
this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
@ -261,7 +266,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
if (bm == null) {
togglePublishButton(false, R.string.publish);
this.hintOrWarning.setVisibility(View.VISIBLE);
this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
return;
}
@ -272,7 +276,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
} else {
togglePublishButton(false, R.string.publish);
this.hintOrWarning.setVisibility(View.VISIBLE);
this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
if (account.getStatus() == Account.State.ONLINE) {
this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
} else {

View file

@ -15,6 +15,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import com.google.common.collect.ImmutableSet;
@ -33,10 +34,9 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityRecordingBinding;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.utils.ThemeHelper;
import eu.siacs.conversations.utils.TimeFrameUtils;
public class RecordingActivity extends Activity implements View.OnClickListener {
public class RecordingActivity extends BaseActivity implements View.OnClickListener {
private ActivityRecordingBinding binding;
@ -61,7 +61,6 @@ public class RecordingActivity extends Activity implements View.OnClickListener
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.findDialog(this));
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_recording);
this.binding.cancelButton.setOnClickListener(this);
@ -69,19 +68,13 @@ public class RecordingActivity extends Activity implements View.OnClickListener
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
protected void onResume() {
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
this.binding.timer.setTextAppearance(this, R.style.TextAppearance_Conversations_Title);
this.binding.timer.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
// TODO reset font family. make red?
this.binding.timer.setText(R.string.unable_to_start_recording);
}
}

View file

@ -179,6 +179,7 @@ public class RtpSessionActivity extends XmppActivity
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
}
@Override
@ -920,34 +921,34 @@ public class RtpSessionActivity extends XmppActivity
} else if (state == RtpEndUserState.INCOMING_CALL) {
this.binding.rejectCall.setContentDescription(getString(R.string.dismiss_call));
this.binding.rejectCall.setOnClickListener(this::rejectCall);
this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_24dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.answer_call));
this.binding.acceptCall.setOnClickListener(this::acceptCall);
this.binding.acceptCall.setImageResource(R.drawable.ic_call_white_48dp);
this.binding.acceptCall.setImageResource(R.drawable.ic_call_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (state == RtpEndUserState.INCOMING_CONTENT_ADD) {
this.binding.rejectCall.setContentDescription(
getString(R.string.reject_switch_to_video));
this.binding.rejectCall.setOnClickListener(this::rejectContentAdd);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.accept));
this.binding.acceptCall.setOnClickListener((v -> acceptContentAdd(contentAddition)));
this.binding.acceptCall.setImageResource(R.drawable.ic_baseline_check_24);
this.binding.acceptCall.setImageResource(R.drawable.ic_check_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (asList(RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONTACT_OFFLINE)
.contains(state)) {
this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.record_voice_mail));
this.binding.acceptCall.setOnClickListener(this::recordVoiceMail);
this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_white_24dp);
this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else if (asList(
RtpEndUserState.CONNECTIVITY_ERROR,
@ -958,18 +959,18 @@ public class RtpSessionActivity extends XmppActivity
.contains(state)) {
this.binding.rejectCall.setContentDescription(getString(R.string.exit));
this.binding.rejectCall.setOnClickListener(this::exit);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
this.binding.rejectCall.setVisibility(View.VISIBLE);
this.binding.endCall.setVisibility(View.INVISIBLE);
this.binding.acceptCall.setContentDescription(getString(R.string.try_again));
this.binding.acceptCall.setOnClickListener(this::retry);
this.binding.acceptCall.setImageResource(R.drawable.ic_replay_white_48dp);
this.binding.acceptCall.setImageResource(R.drawable.ic_replay_24dp);
this.binding.acceptCall.setVisibility(View.VISIBLE);
} else {
this.binding.rejectCall.setVisibility(View.INVISIBLE);
this.binding.endCall.setContentDescription(getString(R.string.hang_up));
this.binding.endCall.setOnClickListener(this::endCall);
this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
this.binding.endCall.setImageResource(R.drawable.ic_call_end_24dp);
this.binding.endCall.setVisibility(View.VISIBLE);
this.binding.acceptCall.setVisibility(View.INVISIBLE);
}
@ -1038,7 +1039,7 @@ public class RtpSessionActivity extends XmppActivity
switch (selectedAudioDevice) {
case EARPIECE -> {
this.binding.inCallActionRight.setImageResource(
R.drawable.ic_volume_off_black_24dp);
R.drawable.ic_volume_off_24dp);
if (numberOfChoices >= 2) {
this.binding.inCallActionRight.setOnClickListener(this::switchToSpeaker);
} else {
@ -1047,12 +1048,12 @@ public class RtpSessionActivity extends XmppActivity
}
}
case WIRED_HEADSET -> {
this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_black_24dp);
this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_mic_24dp);
this.binding.inCallActionRight.setOnClickListener(null);
this.binding.inCallActionRight.setClickable(false);
}
case SPEAKER_PHONE -> {
this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_black_24dp);
this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_24dp);
if (numberOfChoices >= 2) {
this.binding.inCallActionRight.setOnClickListener(this::switchToEarpiece);
} else {
@ -1062,7 +1063,7 @@ public class RtpSessionActivity extends XmppActivity
}
case BLUETOOTH -> {
this.binding.inCallActionRight.setImageResource(
R.drawable.ic_bluetooth_audio_black_24dp);
R.drawable.ic_bluetooth_audio_24dp);
this.binding.inCallActionRight.setOnClickListener(null);
this.binding.inCallActionRight.setClickable(false);
}
@ -1076,17 +1077,17 @@ public class RtpSessionActivity extends XmppActivity
this.binding.inCallActionRight.setVisibility(View.VISIBLE);
if (isCameraSwitchable) {
this.binding.inCallActionFarRight.setImageResource(
R.drawable.ic_flip_camera_android_black_24dp);
R.drawable.ic_flip_camera_android_24dp);
this.binding.inCallActionFarRight.setVisibility(View.VISIBLE);
this.binding.inCallActionFarRight.setOnClickListener(this::switchCamera);
} else {
this.binding.inCallActionFarRight.setVisibility(View.GONE);
}
if (videoEnabled) {
this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_black_24dp);
this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_24dp);
this.binding.inCallActionRight.setOnClickListener(this::disableVideo);
} else {
this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_black_24dp);
this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_24dp);
this.binding.inCallActionRight.setOnClickListener(this::enableVideo);
}
}
@ -1140,10 +1141,10 @@ public class RtpSessionActivity extends XmppActivity
@SuppressLint("RestrictedApi")
private void updateInCallButtonConfigurationMicrophone(final boolean microphoneEnabled) {
if (microphoneEnabled) {
this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_black_24dp);
this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_24dp);
this.binding.inCallActionLeft.setOnClickListener(this::disableMicrophone);
} else {
this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_black_24dp);
this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_24dp);
this.binding.inCallActionLeft.setOnClickListener(this::enableMicrophone);
}
this.binding.inCallActionLeft.setVisibility(View.VISIBLE);

View file

@ -182,7 +182,6 @@ public final class ScanActivity extends Activity implements SurfaceTextureListen
@Override
protected void onResume() {
super.onResume();
SettingsUtils.applyScreenshotPreventionSetting(this);
maybeOpenCamera();
}

View file

@ -42,8 +42,10 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
import java.lang.ref.WeakReference;
@ -64,7 +66,6 @@ import eu.siacs.conversations.ui.util.DateSeparator;
import eu.siacs.conversations.ui.util.ListViewUtils;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ShareUtil;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.FtsUtils;
import eu.siacs.conversations.utils.MessageUtils;
@ -95,6 +96,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
}
super.onCreate(bundle);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_search);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(this.binding.toolbar);
configureActionBar(getSupportActionBar());
this.messageListAdapter = new MessageAdapter(this, this.messages, uuid == null);
@ -223,12 +225,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
private void changeBackground(boolean hasSearch, boolean hasResults) {
if (hasSearch) {
if (hasResults) {
binding.searchResults.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_secondary));
binding.searchResults.setBackgroundColor(MaterialColors.getColor(binding.searchResults, com.google.android.material.R.attr.colorSurface));
} else {
binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_no_results));
binding.searchResults.setBackgroundResource(R.drawable.background_no_results);
}
} else {
binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_search));
binding.searchResults.setBackgroundResource(R.drawable.background_search);
}
}
@ -248,14 +250,14 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
if (!currentSearch.watch(term)) {
return;
}
if (term.size() > 0) {
xmppConnectionService.search(term, uuid,this);
} else {
if (term.isEmpty()) {
MessageSearchTask.cancelRunningTasks();
this.messages.clear();
messageListAdapter.setHighlightedTerm(null);
messageListAdapter.notifyDataSetChanged();
changeBackground(false, false);
} else {
xmppConnectionService.search(term, uuid,this);
}
}
@ -267,7 +269,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
DateSeparator.addAll(messages);
this.messages.addAll(messages);
messageListAdapter.notifyDataSetChanged();
changeBackground(true, messages.size() > 0);
changeBackground(true, !messages.isEmpty());
ListViewUtils.scrollToBottom(this.binding.searchResults);
});
}

View file

@ -22,7 +22,10 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@ -37,8 +40,10 @@ import java.util.Collections;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.Conversations;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.OmemoSetting;
import eu.siacs.conversations.databinding.ActivitySettingsBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.ExportBackupService;
@ -46,10 +51,8 @@ import eu.siacs.conversations.services.MemorizingTrustManager;
import eu.siacs.conversations.services.QuickConversationsService;
import eu.siacs.conversations.services.UnifiedPushDistributor;
import eu.siacs.conversations.ui.util.SettingsUtils;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener {
@ -74,7 +77,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
final ActivitySettingsBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_settings);
FragmentManager fm = getFragmentManager();
mSettingsFragment = (SettingsFragment) fm.findFragmentById(R.id.settings_content);
if (mSettingsFragment == null
@ -83,13 +86,8 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
fm.beginTransaction().replace(R.id.settings_content, mSettingsFragment).commit();
}
mSettingsFragment.setActivityIntent(getIntent());
this.mTheme = findTheme();
setTheme(this.mTheme);
getWindow()
.getDecorView()
.setBackgroundColor(
StyledAttributes.getColor(this, R.attr.color_background_primary));
setSupportActionBar(findViewById(R.id.toolbar));
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
}
@ -185,6 +183,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
}
}
final PreferenceCategory uiPreferenceCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui");
final Preference dynamicColorsPreference = mSettingsFragment.findPreference("dynamic_colors");
if (dynamicColorsPreference != null && !DynamicColors.isDynamicColorAvailable()) {
uiPreferenceCategory.removePreference(dynamicColorsPreference);
}
ListPreference automaticMessageDeletionList =
(ListPreference) mSettingsFragment.findPreference(AUTOMATIC_MESSAGE_DELETION);
if (automaticMessageDeletionList != null) {
@ -204,36 +208,6 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
automaticMessageDeletionList.setEntryValues(entryValues);
}
boolean removeLocation =
new Intent("eu.siacs.conversations.location.request")
.resolveActivity(getPackageManager())
== null;
boolean removeVoice =
new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
.resolveActivity(getPackageManager())
== null;
ListPreference quickAction =
(ListPreference) mSettingsFragment.findPreference("quick_action");
if (quickAction != null && (removeLocation || removeVoice)) {
ArrayList<CharSequence> entries =
new ArrayList<>(Arrays.asList(quickAction.getEntries()));
ArrayList<CharSequence> entryValues =
new ArrayList<>(Arrays.asList(quickAction.getEntryValues()));
int index = entryValues.indexOf("location");
if (index > 0 && removeLocation) {
entries.remove(index);
entryValues.remove(index);
}
index = entryValues.indexOf("voice");
if (index > 0 && removeVoice) {
entries.remove(index);
entryValues.remove(index);
}
quickAction.setEntries(entries.toArray(new CharSequence[entries.size()]));
quickAction.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()]));
}
final Preference removeCertsPreference =
mSettingsFragment.findPreference("remove_trusted_certificates");
if (removeCertsPreference != null) {
@ -242,17 +216,16 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
final MemorizingTrustManager mtm =
xmppConnectionService.getMemorizingTrustManager();
final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
if (aliases.size() == 0) {
if (aliases.isEmpty()) {
displayToast(getString(R.string.toast_no_trusted_certs));
return true;
}
final ArrayList<Integer> selectedItems = new ArrayList<>();
final AlertDialog.Builder dialogBuilder =
new AlertDialog.Builder(SettingsActivity.this);
final MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(SettingsActivity.this);
dialogBuilder.setTitle(
getResources().getString(R.string.dialog_manage_certs_title));
dialogBuilder.setMultiChoiceItems(
aliases.toArray(new CharSequence[aliases.size()]),
aliases.toArray(new CharSequence[0]),
null,
(dialog, indexSelected, isChecked) -> {
if (isChecked) {
@ -262,7 +235,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
}
((AlertDialog) dialog)
.getButton(DialogInterface.BUTTON_POSITIVE)
.setEnabled(selectedItems.size() > 0);
.setEnabled(!selectedItems.isEmpty());
});
dialogBuilder.setPositiveButton(
@ -273,13 +246,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
if (count > 0) {
for (int i = 0; i < count; i++) {
try {
Integer item =
Integer.valueOf(
final int item =
Integer.parseInt(
selectedItems.get(i).toString());
String alias = aliases.get(item);
mtm.deleteCertificate(alias);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (final KeyStoreException e) {
displayToast("Error: " + e.getLocalizedMessage());
}
}
@ -372,10 +344,8 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
private boolean isCallable(final Intent i) {
return i != null
&& getPackageManager()
.queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
.size()
> 0;
&& !getPackageManager()
.queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
}
private boolean cleanCache() {
@ -413,7 +383,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
}
private boolean deleteOmemoIdentities() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.pref_delete_omemo_identities);
final List<CharSequence> accounts = new ArrayList<>();
for (Account account : xmppConnectionService.getAccounts()) {
@ -502,10 +472,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
} else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
xmppConnectionService.expireOldMessages(true);
} else if (name.equals(THEME)) {
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
}
final var value = preferences.getString(THEME,getString(R.string.theme));
final int desiredNightMode = Conversations.getDesiredNightMode(value);
setDesiredNightMode(desiredNightMode);
} else if (name.equals("dynamic_colors")) {
final var value = preferences.getBoolean("dynamic_colors",false);
setDynamicColors(value);
} else if (name.equals(PREVENT_SCREENSHOTS)) {
SettingsUtils.applyScreenshotPreventionSetting(this);
} else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
@ -572,7 +544,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
private void createBackup() {
ContextCompat.startForegroundService(this, new Intent(this, ExportBackupService.class));
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setMessage(R.string.backup_started_message);
builder.setPositiveButton(R.string.ok, null);
builder.create().show();

View file

@ -5,7 +5,6 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
@ -15,11 +14,6 @@ import androidx.databinding.DataBindingUtil;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.math.DoubleMath;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.util.GeoPoint;
import java.math.RoundingMode;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityShareLocationBinding;
@ -27,7 +21,11 @@ import eu.siacs.conversations.ui.util.LocationHelper;
import eu.siacs.conversations.ui.widget.Marker;
import eu.siacs.conversations.ui.widget.MyLocation;
import eu.siacs.conversations.utils.LocationProvider;
import eu.siacs.conversations.utils.ThemeHelper;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.util.GeoPoint;
import java.math.RoundingMode;
public class ShareLocationActivity extends LocationActivity implements LocationListener {
@ -58,6 +56,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_share_location);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
setupMapView(binding.map, LocationProvider.getGeoPoint(this));
@ -71,13 +70,12 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
this.snackBar.setAction(R.string.enable, view -> {
if (isLocationEnabledAndAllowed()) {
updateUi();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasLocationPermissions()) {
} else if (!hasLocationPermissions()) {
requestPermissions(REQUEST_CODE_SNACKBAR_PRESSED);
} else if (!isLocationEnabled()) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
ThemeHelper.fix(this.snackBar);
this.binding.shareButton.setOnClickListener(this::shareLocation);
@ -87,7 +85,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
if (!marker_fixed_to_loc) {
if (!isLocationEnabled()) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
} else {
requestPermissions(REQUEST_CODE_FAB_PRESSED);
}
}
@ -117,16 +115,9 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
@NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 &&
grantResults[0] != PackageManager.PERMISSION_GRANTED &&
Build.VERSION.SDK_INT >= 23 &&
permissions.length > 0 &&
(
Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) ||
Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) ||
Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
) &&
!shouldShowRequestPermissionRationale(permissions[0])) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED && permissions.length > 0 && (
Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) || Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) || Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
) && !shouldShowRequestPermissionRationale(permissions[0])) {
noAskAgain = true;
}
@ -172,7 +163,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
}
@Override
public void onLocationChanged(final Location location) {
public void onLocationChanged(@NonNull final Location location) {
if (this.myLoc == null) {
this.marker_fixed_to_loc = true;
}
@ -206,7 +197,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
}
private boolean isLocationEnabledAndAllowed() {
return this.hasLocationFeature && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || this.hasLocationPermissions()) && this.isLocationEnabled();
return this.hasLocationFeature && this.hasLocationPermissions() && this.isLocationEnabled();
}
private void toggleFixedLocation() {
@ -229,8 +220,8 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
if (isLocationEnabledAndAllowed()) {
this.binding.fab.setVisibility(View.VISIBLE);
runOnUiThread(() -> {
this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_white_24dp :
R.drawable.ic_gps_not_fixed_white_24dp);
this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_24dp :
R.drawable.ic_gps_not_fixed_24dp);
this.binding.fab.setContentDescription(getResources().getString(
marker_fixed_to_loc ? R.string.action_unfix_from_location : R.string.action_fix_to_location
));

View file

@ -9,21 +9,24 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityShareWithBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.xmpp.Jid;
public class ShareWithActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
import java.util.ArrayList;
import java.util.List;
public class ShareWithActivity extends XmppActivity
implements XmppConnectionService.OnConversationUpdate {
private static final int REQUEST_STORAGE_PERMISSION = 0x733f32;
private Conversation mPendingConversation = null;
@ -48,11 +51,10 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
private ConversationAdapter mAdapter;
private final List<Conversation> mConversations = new ArrayList<>();
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
protected void onActivityResult(
final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_START_NEW_CONVERSATION
&& resultCode == RESULT_OK) {
if (requestCode == REQUEST_START_NEW_CONVERSATION && resultCode == RESULT_OK) {
share.contact = data.getStringExtra("contact");
share.account = data.getStringExtra(EXTRA_ACCOUNT);
}
@ -65,7 +67,10 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
public void onRequestPermissionsResult(
final int requestCode,
@NonNull final String[] permissions,
@NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0)
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@ -77,27 +82,35 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
}
}
} else {
Toast.makeText(this, getString(R.string.no_storage_permission, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
Toast.makeText(
this,
getString(
R.string.no_storage_permission,
getString(R.string.app_name)),
Toast.LENGTH_SHORT)
.show();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_with);
setSupportActionBar(findViewById(R.id.toolbar));
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
final ActivityShareWithBinding binding =
DataBindingUtil.setContentView(this, R.layout.activity_share_with);
setSupportActionBar(binding.toolbar);
final var actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(false);
}
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setTitle(R.string.title_activity_share_with);
setTitle(getString(R.string.title_activity_sharewith));
RecyclerView mListView = findViewById(R.id.choose_conversation_list);
mAdapter = new ConversationAdapter(this, this.mConversations);
mListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
mListView.setAdapter(mAdapter);
binding.chooseConversationList.setLayoutManager(
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
binding.chooseConversationList.setAdapter(mAdapter);
mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
this.share = new Share();
}
@ -112,8 +125,9 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add:
final Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
intent.putExtra("direct_search",true);
final Intent intent =
new Intent(getApplicationContext(), ChooseContactActivity.class);
intent.putExtra("direct_search", true);
startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
return true;
}
@ -133,7 +147,8 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
if (Intent.ACTION_SEND.equals(action)) {
final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
final boolean asQuote = intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
final boolean asQuote =
intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
if (data != null && "geo".equals(data.getScheme())) {
this.share.uris.clear();
@ -151,14 +166,16 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
this.share.uris = uris == null ? new ArrayList<>() : uris;
}
if (xmppConnectionServiceBound) {
xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0, false);
xmppConnectionService.populateWithOrderedConversations(
mConversations, this.share.uris.isEmpty(), false);
}
}
@Override
void onBackendConnected() {
if (xmppConnectionServiceBound && share != null && ((share.contact != null && share.account != null))) {
if (xmppConnectionServiceBound
&& share != null
&& ((share.contact != null && share.account != null))) {
share();
return;
}
@ -167,32 +184,34 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
private void share() {
final Conversation conversation;
Account account;
try {
account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
} catch (final IllegalArgumentException e) {
account = null;
}
if (account == null) {
return;
}
Account account;
try {
account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
} catch (final IllegalArgumentException e) {
account = null;
}
if (account == null) {
return;
}
try {
conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), false, true);
} catch (final IllegalArgumentException e) {
return;
}
try {
conversation =
xmppConnectionService.findOrCreateConversation(
account, Jid.of(share.contact), false, true);
} catch (final IllegalArgumentException e) {
return;
}
share(conversation);
}
private void share(final Conversation conversation) {
if (share.uris.size() != 0 && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
if (!share.uris.isEmpty() && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
mPendingConversation = conversation;
return;
}
Intent intent = new Intent(this, ConversationsActivity.class);
final Intent intent = new Intent(this, ConversationsActivity.class);
intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
if (share.uris.size() > 0) {
if (!share.uris.isEmpty()) {
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@ -207,15 +226,20 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
try {
startActivity(intent);
} catch (SecurityException e) {
Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
Toast.makeText(
this,
R.string.sharing_application_not_grant_permission,
Toast.LENGTH_SHORT)
.show();
return;
}
finish();
}
public void refreshUiReal() {
//TODO inject desired order to not resort on refresh
xmppConnectionService.populateWithOrderedConversations(mConversations, this.share != null && this.share.uris.size() == 0, false);
// TODO inject desired order to not resort on refresh
xmppConnectionService.populateWithOrderedConversations(
mConversations, this.share != null && this.share.uris.isEmpty(), false);
mAdapter.notifyDataSetChanged();
}
}

View file

@ -45,7 +45,7 @@ public class ShortcutActivity extends AbstractSearchableListItemActivity {
}
@Override
protected void onStart() {
public void onStart() {
super.onStart();
ActionBar bar = getSupportActionBar();
if(bar != null){

View file

@ -49,6 +49,8 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_show_location);
setSupportActionBar(binding.toolbar);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
configureActionBar(getSupportActionBar());
setupMapView(this.binding.map, this.loc);

View file

@ -6,7 +6,6 @@ import android.app.Dialog;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -55,7 +54,10 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import com.google.common.collect.Iterables;
import com.leinardi.android.speeddial.SpeedDialActionItem;
import com.leinardi.android.speeddial.SpeedDialView;
@ -109,7 +111,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
private ListItemAdapter mContactsAdapter;
private final List<ListItem> conferences = new ArrayList<>();
private ListItemAdapter mConferenceAdapter;
private final List<String> mActivatedAccounts = new ArrayList<>();
private final ArrayList<String> mActivatedAccounts = new ArrayList<>();
private EditText mSearchEditText;
private final AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);
private final AtomicBoolean mOpenedFab = new AtomicBoolean(false);
@ -220,19 +222,20 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
};
public static void populateAccountSpinner(Context context, List<String> accounts, Spinner spinner) {
if (accounts.size() > 0) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.simple_list_item, accounts);
adapter.setDropDownViewResource(R.layout.simple_list_item);
spinner.setAdapter(adapter);
spinner.setEnabled(true);
} else {
public static void populateAccountSpinner(final Context context, final List<String> accounts, final AutoCompleteTextView spinner) {
if (accounts.isEmpty()) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
R.layout.simple_list_item,
R.layout.item_autocomplete,
Collections.singletonList(context.getString(R.string.no_accounts)));
adapter.setDropDownViewResource(R.layout.simple_list_item);
adapter.setDropDownViewResource(R.layout.item_autocomplete);
spinner.setAdapter(adapter);
spinner.setEnabled(false);
} else {
final ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.item_autocomplete, accounts);
adapter.setDropDownViewResource(R.layout.item_autocomplete);
spinner.setAdapter(adapter);
spinner.setEnabled(true);
spinner.setText(Iterables.getFirst(accounts,null),false);
}
}
@ -273,6 +276,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_start_conversation);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
setSupportActionBar(binding.toolbar);
configureActionBar(getSupportActionBar());
@ -363,7 +367,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
final SpeedDialActionItem actionItem = new SpeedDialActionItem.Builder(menuItem.getItemId(), menuItem.getIcon())
.setLabel(menuItem.getTitle() != null ? menuItem.getTitle().toString() : null)
.setFabImageTintColor(ContextCompat.getColor(this, R.color.white))
.setFabImageTintColor(MaterialColors.getColor(speedDialView, com.google.android.material.R.attr.colorOnSurface))
.setFabBackgroundColor(MaterialColors.getColor(speedDialView, com.google.android.material.R.attr.colorSurfaceContainerHighest))
.create();
speedDialView.addActionItem(actionItem);
}
@ -394,13 +399,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
@Override
public void onStart() {
super.onStart();
final int theme = findTheme();
if (this.mTheme != theme) {
recreate();
} else {
if (pendingViewIntent.peek() == null) {
askForContactsPermissions();
}
if (pendingViewIntent.peek() == null) {
askForContactsPermissions();
}
mConferenceAdapter.refreshSettings();
mContactsAdapter.refreshSettings();
@ -490,7 +490,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
protected void deleteContact() {
final int position = contact_context_id;
final Contact contact = (Contact) contacts.get(position);
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.action_delete_contact);
builder.setMessage(JidDialog.style(this, R.string.remove_contact_text, contact.getJid().toEscapedString()));
@ -506,7 +506,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
final Bookmark bookmark = (Bookmark) conferences.get(position);
final var conversation = bookmark.getConversation();
final boolean hasConversation = conversation != null;
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setNegativeButton(R.string.cancel, null);
builder.setTitle(R.string.delete_bookmark);
if (hasConversation) {
@ -611,18 +611,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
dialog.show(ft, FRAGMENT_TAG_DIALOG);
}
public static Account getSelectedAccount(Context context, Spinner spinner) {
public static Account getSelectedAccount(final Context context, final AutoCompleteTextView spinner) {
if (spinner == null || !spinner.isEnabled()) {
return null;
}
if (context instanceof XmppActivity) {
Jid jid;
final Jid jid;
try {
if (Config.DOMAIN_LOCK != null) {
jid = Jid.ofEscaped((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
} else {
jid = Jid.ofEscaped((String) spinner.getSelectedItem());
}
jid = Jid.ofEscaped(spinner.getText().toString());
} catch (final IllegalArgumentException e) {
return null;
}
@ -792,7 +788,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
if (requiresConsent
|| shouldShowRequestPermissionRationale(
Manifest.permission.READ_CONTACTS)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
final AtomicBoolean requestPermission = new AtomicBoolean(false);
if (QuickConversationsService.isQuicksy()) {
builder.setTitle(R.string.quicksy_wants_your_consent);
@ -1007,7 +1003,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
private void displayVerificationWarningDialog(final Contact contact, final Invite invite) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.verify_omemo_keys);
View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
final CheckBox isTrustedSource = view.findViewById(R.id.trusted_source);
@ -1104,7 +1100,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
public void onCreateDialogPositiveClick(Spinner spinner, String name) {
public void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String name) {
if (!xmppConnectionServiceBound) {
return;
}
@ -1122,7 +1118,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
@Override
public void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
public void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
if (!xmppConnectionServiceBound) {
return;
}

View file

@ -14,14 +14,7 @@ import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.databinding.DataBindingUtil;
import org.whispersystems.libsignal.IdentityKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@ -40,6 +33,14 @@ import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import org.whispersystems.libsignal.IdentityKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated {
private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
@ -70,12 +71,14 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_trust_keys);
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
this.contactJids = new ArrayList<>();
for (String jid : getIntent().getStringArrayExtra("contacts")) {
final var intent = getIntent();
final String[] contacts = intent == null ? null : intent.getStringArrayExtra("contacts");
for (final String jid : (contacts == null ? new String[0] : contacts)) {
try {
this.contactJids.add(Jid.of(jid));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (final IllegalArgumentException ignored) {
}
}
@ -100,7 +103,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.trust_keys, menu);
MenuItem scanQrCode = menu.findItem(R.id.action_scan_qr_code);
scanQrCode.setVisible((ownKeysToTrust.size() > 0 || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
scanQrCode.setVisible((!ownKeysToTrust.isEmpty() || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
return super.onCreateOptionsMenu(menu);
}
@ -191,7 +194,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
}
);
}
if (fingerprints.size() == 0) {
if (fingerprints.isEmpty()) {
keysCardBinding.noKeysToAccept.setVisibility(View.VISIBLE);
if (hasNoOtherTrustedKeys(jid)) {
if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
@ -254,8 +257,8 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
}
}
private void disableEncryptionDialog(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
private void disableEncryptionDialog(final View view) {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(R.string.disable_encryption);
builder.setMessage(R.string.disable_encryption_message);
builder.setPositiveButton(R.string.disable_now, (dialog, which) -> {
@ -279,7 +282,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
private boolean foreignActuallyHasKeys() {
synchronized (this.foreignKeysToTrust) {
for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
if (entry.getValue().size() > 0) {
if (!entry.getValue().isEmpty()) {
return true;
}
}
@ -305,7 +308,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
foreignKeysToTrust.clear();
for (Jid jid : contactJids) {
Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid);
if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) {
if (hasNoOtherTrustedKeys(jid) && ownKeysSet.isEmpty()) {
foreignKeysSet.addAll(service.getKeysWithTrust(FingerprintStatus.createActive(false), jid));
}
Map<String, Boolean> foreignFingerprints = new HashMap<>();
@ -315,7 +318,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
foreignFingerprints.put(fingerprint, false);
}
}
if (foreignFingerprints.size() > 0 || !acceptedTargets.contains(jid)) {
if (!foreignFingerprints.isEmpty() || !acceptedTargets.contains(jid)) {
foreignKeysToTrust.put(jid, foreignFingerprints);
}
}

View file

@ -42,7 +42,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UriHandlerActivity extends AppCompatActivity {
public class UriHandlerActivity extends BaseActivity {
public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
private static final String EXTRA_ALLOW_PROVISIONING = "extra_allow_provisioning";

View file

@ -2,7 +2,6 @@ package eu.siacs.conversations.ui;
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
@ -17,10 +16,10 @@ import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@ -50,10 +49,11 @@ import androidx.annotation.BoolRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog.Builder;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.databinding.DataBindingUtil;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.common.base.Strings;
import eu.siacs.conversations.BuildConfig;
@ -80,7 +80,6 @@ import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.SignupUtils;
import eu.siacs.conversations.utils.ThemeHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
@ -106,7 +105,6 @@ public abstract class XmppActivity extends ActionBarActivity {
private boolean isCameraFeatureAvailable = false;
protected int mTheme;
protected boolean mUsingEnterKey = false;
protected boolean mUseTor = false;
protected Toast mToast;
@ -154,7 +152,6 @@ public abstract class XmppActivity extends ActionBarActivity {
}
};
public boolean mSkipBackgroundBinding = false;
public static boolean cancelPotentialWork(Message message, ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
@ -212,14 +209,10 @@ public abstract class XmppActivity extends ActionBarActivity {
abstract protected void refreshUiReal();
@Override
protected void onStart() {
public void onStart() {
super.onStart();
if (!xmppConnectionServiceBound) {
if (this.mSkipBackgroundBinding) {
Log.d(Config.LOGTAG, "skipping background binding");
} else {
connectToBackend();
}
connectToBackend();
} else {
this.registerListeners();
this.onBackendConnected();
@ -255,7 +248,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
public void showInstallPgpDialog() {
Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(getString(R.string.openkeychain_required));
builder.setIconAttribute(android.R.attr.alertDialogIcon);
builder.setMessage(Html.fromHtml(getString(R.string.openkeychain_required_long, getString(R.string.app_name))));
@ -298,7 +291,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected void deleteAccount(final Account account, final Runnable postDelete) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
final View dialogView = getLayoutInflater().inflate(R.layout.dialog_delete_account, null);
final CheckBox deleteFromServer =
dialogView.findViewById(R.id.delete_from_server);
@ -495,28 +488,12 @@ public abstract class XmppActivity extends ActionBarActivity {
ExceptionHelper.init(getApplicationContext());
EmojiInitializationService.execute(this);
this.isCameraFeatureAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
this.mTheme = findTheme();
setTheme(this.mTheme);
}
protected boolean isCameraFeatureAvailable() {
return this.isCameraFeatureAvailable;
}
public boolean isDarkTheme() {
return ThemeHelper.isDark(mTheme);
}
public int getThemeResource(int r_attr_name, int r_drawable_def) {
int[] attrs = {r_attr_name};
TypedArray ta = this.getTheme().obtainStyledAttributes(attrs);
int res = ta.getResourceId(0, r_drawable_def);
ta.recycle();
return res;
}
protected boolean isOptimizingBattery() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
@ -698,21 +675,10 @@ public abstract class XmppActivity extends ActionBarActivity {
}
}
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
protected void setListItemBackgroundOnView(View view) {
int sdk = android.os.Build.VERSION.SDK_INT;
if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(getResources().getDrawable(R.drawable.greybackground));
} else {
view.setBackground(getResources().getDrawable(R.drawable.greybackground));
}
}
protected void choosePgpSignId(Account account) {
xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<Account>() {
protected void choosePgpSignId(final Account account) {
xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<>() {
@Override
public void success(Account account1) {
public void success(final Account a) {
}
@Override
@ -733,8 +699,7 @@ public abstract class XmppActivity extends ActionBarActivity {
protected void displayErrorDialog(final int errorCode) {
runOnUiThread(() -> {
Builder builder = new Builder(XmppActivity.this);
builder.setIconAttribute(android.R.attr.alertDialogIcon);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(XmppActivity.this);
builder.setTitle(getString(R.string.error));
builder.setMessage(errorCode);
builder.setNeutralButton(R.string.accept, null);
@ -744,7 +709,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected void showAddToRosterDialog(final Contact contact) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(contact.getJid().toString());
builder.setMessage(getString(R.string.not_in_roster));
builder.setNegativeButton(getString(R.string.cancel), null);
@ -753,7 +718,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
private void showAskForPresenceDialog(final Contact contact) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle(contact.getJid().toString());
builder.setMessage(R.string.request_presence_updates);
builder.setNegativeButton(R.string.cancel, null);
@ -787,8 +752,8 @@ public abstract class XmppActivity extends ActionBarActivity {
final @StringRes int hint,
boolean password,
boolean permitEmpty) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
DialogQuickeditBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_quickedit, null, false);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
final DialogQuickeditBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_quickedit, null, false);
if (password) {
binding.inputEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
@ -829,7 +794,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected boolean hasStoragePermission(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
@ -911,10 +876,6 @@ public abstract class XmppActivity extends ActionBarActivity {
SettingsUtils.applyScreenshotPreventionSetting(this);
}
protected int findTheme() {
return ThemeHelper.find(this);
}
@Override
public void onPause() {
super.onPause();
@ -936,14 +897,26 @@ public abstract class XmppActivity extends ActionBarActivity {
if (uri == null || uri.isEmpty()) {
return;
}
Point size = new Point();
final Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
final int width = (size.x < size.y ? size.x : size.y);
Bitmap bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width);
ImageView view = new ImageView(this);
view.setBackgroundColor(Color.WHITE);
final int width = Math.min(size.x, size.y);
final boolean nightMode = (this.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
final int black;
final int white;
if (nightMode) {
black = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceContainerHighest,"No surface color configured");
white = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceInverse,"No inverse surface color configured");
} else {
black = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceInverse,"No inverse surface color configured");
white = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceContainerHighest,"No surface color configured");
}
final var bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width, black, white);
final ImageView view = new ImageView(this);
view.setBackgroundColor(white);
view.setImageBitmap(bitmap);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setView(view);
builder.create().show();
}

View file

@ -8,15 +8,16 @@ import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import java.util.List;
import com.google.android.material.color.MaterialColors;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.AccountRowBinding;
import eu.siacs.conversations.databinding.ItemAccountBinding;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.StyledAttributes;
import java.util.List;
public class AccountAdapter extends ArrayAdapter<Account> {
@ -35,36 +36,33 @@ public class AccountAdapter extends ArrayAdapter<Account> {
this.showStateButton = true;
}
@NonNull
@Override
public View getView(int position, View view, @NonNull ViewGroup parent) {
final Account account = getItem(position);
final ViewHolder viewHolder;
if (view == null) {
AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false);
ItemAccountBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_account, parent, false);
view = binding.getRoot();
viewHolder = new ViewHolder(binding);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
if (Config.DOMAIN_LOCK != null) {
viewHolder.binding.accountJid.setText(account.getJid().getLocal());
} else {
viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
}
viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
AvatarWorkerTask.loadAvatar(account, viewHolder.binding.accountImage, R.dimen.avatar);
viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorPrimary));
break;
case DISABLED:
case LOGGED_OUT:
case CONNECTING:
viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorOnSurfaceVariant));
break;
default:
viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorError));
break;
}
final boolean isDisabled = (account.getStatus() == Account.State.DISABLED);
@ -84,9 +82,9 @@ public class AccountAdapter extends ArrayAdapter<Account> {
}
private static class ViewHolder {
private final AccountRowBinding binding;
private final ItemAccountBinding binding;
private ViewHolder(AccountRowBinding binding) {
private ViewHolder(ItemAccountBinding binding) {
this.binding = binding;
}
}

View file

@ -13,18 +13,18 @@ import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Locale;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.SearchResultItemBinding;
import eu.siacs.conversations.databinding.ItemChannelDiscoveryBinding;
import eu.siacs.conversations.entities.Room;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.xmpp.Jid;
import java.util.Locale;
public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchResultAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
private static final DiffUtil.ItemCallback<Room> DIFF = new DiffUtil.ItemCallback<Room>() {
private static final DiffUtil.ItemCallback<Room> DIFF = new DiffUtil.ItemCallback<>() {
@Override
public boolean areItemsTheSame(@NonNull Room a, @NonNull Room b) {
return a.address != null && a.address.equals(b.address);
@ -45,7 +45,7 @@ public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchR
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.search_result_item, viewGroup, false));
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_channel_discovery, viewGroup, false));
}
@Override
@ -99,9 +99,9 @@ public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchR
public static class ViewHolder extends RecyclerView.ViewHolder {
private final SearchResultItemBinding binding;
private final ItemChannelDiscoveryBinding binding;
private ViewHolder(SearchResultItemBinding binding) {
private ViewHolder(final ItemChannelDiscoveryBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

View file

@ -6,30 +6,30 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ConversationListRowBinding;
import eu.siacs.conversations.databinding.ItemConversationBinding;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Conversational;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.ui.ConversationFragment;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.Attachment;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
import java.util.List;
public class ConversationAdapter
extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> {
@ -48,7 +48,7 @@ public class ConversationAdapter
return new ConversationViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()),
R.layout.conversation_list_row,
R.layout.item_conversation,
parent,
false));
}
@ -68,14 +68,13 @@ public class ConversationAdapter
}
if (conversation == ConversationFragment.getConversation(activity)) {
viewHolder.binding.frame.setBackgroundColor(
StyledAttributes.getColor(activity, R.attr.color_background_tertiary));
viewHolder.binding.frame.setBackgroundResource(R.drawable.background_selected_item_conversation);
//viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurfaceDim));
} else {
viewHolder.binding.frame.setBackgroundColor(
StyledAttributes.getColor(activity, R.attr.color_background_primary));
viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurface));
}
Message message = conversation.getLatestMessage();
final Message message = conversation.getLatestMessage();
final int unreadCount = conversation.unreadCount();
final boolean isRead = conversation.isRead();
final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
@ -106,68 +105,9 @@ public class ConversationAdapter
&& (message.isFileOrImage()
|| message.treatAsDownloadable()
|| message.isGeoUri())) {
final int imageResource;
if (message.isGeoUri()) {
imageResource =
activity.getThemeResource(
R.attr.ic_attach_location, R.drawable.ic_attach_location);
showPreviewText = false;
} else {
// TODO move this into static MediaPreview method and use same icons as in
// MediaAdapter
final String mime = message.getMimeType();
if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
final Message.FileParams fileParams = message.getFileParams();
if (fileParams.width > 0 && fileParams.height > 0) {
imageResource =
activity.getThemeResource(
R.attr.ic_attach_videocam,
R.drawable.ic_attach_videocam);
showPreviewText = false;
} else if (fileParams.runtime > 0) {
imageResource =
activity.getThemeResource(
R.attr.ic_attach_record, R.drawable.ic_attach_record);
showPreviewText = false;
} else {
imageResource =
activity.getThemeResource(
R.attr.ic_attach_document,
R.drawable.ic_attach_document);
showPreviewText = true;
}
} else {
switch (Strings.nullToEmpty(mime).split("/")[0]) {
case "image":
imageResource =
activity.getThemeResource(
R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
showPreviewText = false;
break;
case "video":
imageResource =
activity.getThemeResource(
R.attr.ic_attach_videocam,
R.drawable.ic_attach_videocam);
showPreviewText = false;
break;
case "audio":
imageResource =
activity.getThemeResource(
R.attr.ic_attach_record,
R.drawable.ic_attach_record);
showPreviewText = false;
break;
default:
imageResource =
activity.getThemeResource(
R.attr.ic_attach_document,
R.drawable.ic_attach_document);
showPreviewText = true;
break;
}
}
}
final var attachment = Attachment.of(message);
final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
showPreviewText = false;
viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
} else {
@ -231,36 +171,21 @@ public class ConversationAdapter
if (ongoingCall.isPresent()) {
viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
final int ic_ongoing_call =
activity.getThemeResource(
R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp);
viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call);
viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_phone_in_talk_24dp);
} else {
final long muted_till =
conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
if (muted_till == Long.MAX_VALUE) {
viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
int ic_notifications_off =
activity.getThemeResource(
R.attr.icon_notifications_off,
R.drawable.ic_notifications_off_black_24dp);
viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off);
viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_off_24dp);
} else if (muted_till >= System.currentTimeMillis()) {
viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
int ic_notifications_paused =
activity.getThemeResource(
R.attr.icon_notifications_paused,
R.drawable.ic_notifications_paused_black_24dp);
viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused);
viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_paused_24dp);
} else if (conversation.alwaysNotify()) {
viewHolder.binding.notificationStatus.setVisibility(View.GONE);
} else {
viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
int ic_notifications_none =
activity.getThemeResource(
R.attr.icon_notifications_none,
R.drawable.ic_notifications_none_black_24dp);
viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none);
viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_none_24dp);
}
}
@ -307,9 +232,9 @@ public class ConversationAdapter
}
static class ConversationViewHolder extends RecyclerView.ViewHolder {
private final ConversationListRowBinding binding;
private final ItemConversationBinding binding;
private ConversationViewHolder(ConversationListRowBinding binding) {
private ConversationViewHolder(final ItemConversationBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

View file

@ -6,32 +6,35 @@ import android.widget.Filter;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.regex.Pattern;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import eu.siacs.conversations.Config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
public class KnownHostsAdapter extends ArrayAdapter<String> {
private static final Pattern E164_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
private ArrayList<String> domains;
private List<String> domains;
private final Filter domainFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
final ArrayList<String> suggestions = new ArrayList<>();
protected FilterResults performFiltering(final CharSequence constraint) {
final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
final String[] split = constraint == null ? new String[0] : constraint.toString().split("@");
if (split.length == 1) {
final String local = split[0].toLowerCase(Locale.ENGLISH);
if (Config.QUICKSY_DOMAIN != null && E164_PATTERN.matcher(local).matches()) {
suggestions.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
builder.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
} else {
for (String domain : domains) {
suggestions.add(local + '@' + domain);
builder.add(local + '@' + domain);
}
}
} else if (split.length == 2) {
@ -40,45 +43,49 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
if (domains.contains(domainPart)) {
return new FilterResults();
}
for (String domain : domains) {
for (final String domain : domains) {
if (domain.contains(domainPart)) {
suggestions.add(localPart + "@" + domain);
builder.add(localPart + "@" + domain);
}
}
} else {
return new FilterResults();
}
FilterResults filterResults = new FilterResults();
final var suggestions = builder.build();
final FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
ArrayList filteredList = (ArrayList) results.values;
if (results.count > 0) {
clear();
addAll(filteredList);
notifyDataSetChanged();
protected void publishResults(final CharSequence constraint, final FilterResults results) {
final ImmutableList.Builder<String> suggestions = new ImmutableList.Builder<>();
if (results.values instanceof Collection<?> collection) {
for(final Object item : collection) {
if (item instanceof String string) {
suggestions.add(string);
}
}
}
clear();
addAll(suggestions.build());
notifyDataSetChanged();
}
};
public KnownHostsAdapter(Context context, int viewResourceId, Collection<String> mKnownHosts) {
public KnownHostsAdapter(final Context context, final int viewResourceId, final Collection<String> knownHosts) {
super(context, viewResourceId, new ArrayList<>());
domains = new ArrayList<>(mKnownHosts);
Collections.sort(domains);
domains = Ordering.natural().sortedCopy(knownHosts);
}
public KnownHostsAdapter(Context context, int viewResourceId) {
public KnownHostsAdapter(final Context context, final int viewResourceId) {
super(context, viewResourceId, new ArrayList<>());
domains = new ArrayList<>();
domains = ImmutableList.of();
}
public void refresh(Collection<String> knownHosts) {
domains = new ArrayList<>(knownHosts);
Collections.sort(domains);
public void refresh(final Collection<String> knownHosts) {
this.domains = Ordering.natural().sortedCopy(knownHosts);
notifyDataSetChanged();
}

View file

@ -2,6 +2,7 @@ package eu.siacs.conversations.ui.adapter;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -9,30 +10,30 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import com.wefika.flowlayout.FlowLayout;
import java.util.List;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ContactBinding;
import eu.siacs.conversations.databinding.ItemContactBinding;
import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.ui.SettingsActivity;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.xmpp.Jid;
import java.util.List;
public class ListItemAdapter extends ArrayAdapter<ListItem> {
protected XmppActivity activity;
private boolean showDynamicTags = false;
private OnTagClickedListener mOnTagClickedListener = null;
private final View.OnClickListener onTagTvClick = view -> {
if (view instanceof TextView && mOnTagClickedListener != null) {
TextView tv = (TextView) view;
if (view instanceof TextView tv && mOnTagClickedListener != null) {
final String tag = tv.getText().toString();
mOnTagClickedListener.onTagClicked(tag);
}
@ -49,22 +50,25 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
}
@NonNull
@Override
public View getView(int position, View view, ViewGroup parent) {
public View getView(int position, View view, @NonNull ViewGroup parent) {
LayoutInflater inflater = activity.getLayoutInflater();
ListItem item = getItem(position);
ViewHolder viewHolder;
if (view == null) {
ContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.contact,parent,false);
final ItemContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.item_contact,parent,false);
viewHolder = ViewHolder.get(binding);
view = binding.getRoot();
} else {
viewHolder = (ViewHolder) view.getTag();
}
view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
List<ListItem.Tag> tags = item.getTags(activity);
if (tags.size() == 0 || !this.showDynamicTags) {
if (view.isActivated()) {
Log.d(Config.LOGTAG,"item "+item.getDisplayName()+" is activated");
}
//view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
final List<ListItem.Tag> tags = item.getTags(activity);
if (tags.isEmpty() || !this.showDynamicTags) {
viewHolder.tags.setVisibility(View.GONE);
} else {
viewHolder.tags.setVisibility(View.VISIBLE);
@ -108,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
}
public static ViewHolder get(ContactBinding binding) {
public static ViewHolder get(final ItemContactBinding binding) {
ViewHolder viewHolder = new ViewHolder();
viewHolder.name = binding.contactDisplayName;
viewHolder.jid = binding.contactJid;

View file

@ -1,47 +1,50 @@
package eu.siacs.conversations.ui.adapter;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.AttrRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.core.widget.ImageViewCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ItemMediaBinding;
import eu.siacs.conversations.services.ExportBackupService;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.Attachment;
import eu.siacs.conversations.ui.util.ViewUtil;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.MediaBinding;
import eu.siacs.conversations.services.ExportBackupService;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.Attachment;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.ui.util.ViewUtil;
public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHolder> {
public static final List<String> DOCUMENT_MIMES = Arrays.asList(
"application/pdf",
"application/vnd.oasis.opendocument.text",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"text/x-tex",
"text/plain"
);
public static final List<String> DOCUMENT_MIMES =
Arrays.asList(
"application/pdf",
"application/vnd.oasis.opendocument.text",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"text/x-tex",
"text/plain");
public static final List<String> CODE_MIMES = Arrays.asList("text/html", "text/xml");
private final ArrayList<Attachment> attachments = new ArrayList<>();
@ -55,58 +58,77 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
}
@SuppressWarnings("rawtypes")
public static void setMediaSize(RecyclerView recyclerView, int mediaSize) {
public static void setMediaSize(final RecyclerView recyclerView, int mediaSize) {
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter instanceof MediaAdapter) {
((MediaAdapter) adapter).setMediaSize(mediaSize);
if (adapter instanceof MediaAdapter mediaAdapter) {
mediaAdapter.setMediaSize(mediaSize);
}
}
private static @AttrRes
int getImageAttr(Attachment attachment) {
final @AttrRes int attr;
public static @DrawableRes int getImageDrawable(final Attachment attachment) {
if (attachment.getType() == Attachment.Type.LOCATION) {
attr = R.attr.media_preview_location;
return R.drawable.ic_location_pin_48dp;
} else if (attachment.getType() == Attachment.Type.RECORDING) {
attr = R.attr.media_preview_recording;
return R.drawable.ic_mic_48dp;
} else {
final String mime = attachment.getMime();
Log.d(Config.LOGTAG, "mime=" + mime);
if (mime == null) {
attr = R.attr.media_preview_unknown;
} else if (mime.equals("audio/x-m4b")) {
attr = R.attr.media_preview_audiobook;
} else if (mime.startsWith("audio/")) {
attr = R.attr.media_preview_audio;
} else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
attr = R.attr.media_preview_calendar;
} else if (mime.equals("text/x-vcard")) {
attr = R.attr.media_preview_contact;
} else if (mime.equals("application/vnd.android.package-archive")) {
attr = R.attr.media_preview_app;
} else if (mime.equals("application/zip") || mime.equals("application/rar")) {
attr = R.attr.media_preview_archive;
} else if (mime.equals("application/epub+zip") || mime.equals("application/vnd.amazon.mobi8-ebook")) {
attr = R.attr.media_preview_ebook;
} else if (mime.equals(ExportBackupService.MIME_TYPE)) {
attr = R.attr.media_preview_backup;
} else if (DOCUMENT_MIMES.contains(mime)) {
attr = R.attr.media_preview_document;
} else if (mime.equals("application/gpx+xml")) {
attr = R.attr.media_preview_tour;
} else if (mime.startsWith("image/")) {
attr = R.attr.media_preview_image;
} else {
attr = R.attr.media_preview_unknown;
}
return getImageDrawable(attachment.getMime());
}
return attr;
}
static void renderPreview(Context context, Attachment attachment, ImageView imageView) {
imageView.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary));
imageView.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255));
imageView.setImageDrawable(StyledAttributes.getDrawable(context, getImageAttr(attachment)));
private static @DrawableRes int getImageDrawable(final String mime) {
// TODO ideas for more mime types: XML, HTML documents, GPG/PGP files, eml files,
// spreadsheets (table symbol)
// add bz2 and tar.gz to archive detection
if (Strings.isNullOrEmpty(mime)) {
return R.drawable.ic_help_center_48dp;
} else if (mime.equals("audio/x-m4b")) {
return R.drawable.ic_play_lesson_48dp;
} else if (mime.startsWith("audio/")) {
return R.drawable.ic_headphones_48dp;
} else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
return R.drawable.ic_event_48dp;
} else if (mime.equals("text/x-vcard")) {
return R.drawable.ic_person_48dp;
} else if (mime.equals("application/vnd.android.package-archive")) {
return R.drawable.ic_adb_48dp;
} else if (mime.equals("application/zip") || mime.equals("application/rar")) {
return R.drawable.ic_archive_48dp;
} else if (mime.equals("application/epub+zip")
|| mime.equals("application/vnd.amazon.mobi8-ebook")) {
return R.drawable.ic_book_48dp;
} else if (mime.equals(ExportBackupService.MIME_TYPE)) {
return R.drawable.ic_backup_48dp;
} else if (DOCUMENT_MIMES.contains(mime)) {
return R.drawable.ic_description_48dp;
} else if (mime.equals("application/gpx+xml")) {
return R.drawable.ic_tour_48dp;
} else if (mime.startsWith("image/")) {
return R.drawable.ic_image_48dp;
} else if (mime.startsWith("video/")) {
return R.drawable.ic_movie_48dp;
} else if (CODE_MIMES.contains(mime)) {
return R.drawable.ic_code_48dp;
} else if (mime.equals("message/rfc822")) {
return R.drawable.ic_email_48dp;
} else {
return R.drawable.ic_help_center_48dp;
}
}
static void renderPreview(final Attachment attachment, final ImageView imageView) {
ImageViewCompat.setImageTintList(
imageView,
ColorStateList.valueOf(
MaterialColors.getColor(
imageView, com.google.android.material.R.attr.colorOnSurface)));
imageView.setImageResource(getImageDrawable(attachment));
imageView.setBackgroundColor(
MaterialColors.getColor(
imageView,
com.google.android.material.R.attr.colorSurfaceContainerHighest));
}
private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) {
@ -126,8 +148,7 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
if (drawable instanceof AsyncDrawable asyncDrawable) {
return asyncDrawable.getBitmapWorkerTask();
}
}
@ -137,8 +158,9 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
@NonNull
@Override
public MediaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
MediaBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media, parent, false);
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ItemMediaBinding binding =
DataBindingUtil.inflate(layoutInflater, R.layout.item_media, parent, false);
return new MediaViewHolder(binding);
}
@ -146,16 +168,15 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
final Attachment attachment = attachments.get(position);
if (attachment.renderThumbnail()) {
holder.binding.media.setImageAlpha(255);
loadPreview(attachment, holder.binding.media);
} else {
cancelPotentialWork(attachment, holder.binding.media);
renderPreview(activity, attachment, holder.binding.media);
renderPreview(attachment, holder.binding.media);
}
holder.binding.getRoot().setOnClickListener(v -> ViewUtil.view(activity, attachment));
}
public void setAttachments(List<Attachment> attachments) {
public void setAttachments(final List<Attachment> attachments) {
this.attachments.clear();
this.attachments.addAll(attachments);
notifyDataSetChanged();
@ -167,16 +188,21 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
private void loadPreview(Attachment attachment, ImageView imageView) {
if (cancelPotentialWork(attachment, imageView)) {
final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment, mediaSize, true);
final Bitmap bm =
activity.xmppConnectionService
.getFileBackend()
.getPreviewForUri(attachment, mediaSize, true);
if (bm != null) {
cancelPotentialWork(attachment, imageView);
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
imageView.setBackgroundColor(Color.TRANSPARENT);
} else {
// TODO consider if this is still a good, general purpose loading color
imageView.setBackgroundColor(0xff333333);
imageView.setImageDrawable(null);
final BitmapWorkerTask task = new BitmapWorkerTask(mediaSize, imageView);
final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(activity.getResources(), null, task);
imageView.setImageDrawable(asyncDrawable);
try {
task.execute(attachment);
@ -204,11 +230,11 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
}
}
class MediaViewHolder extends RecyclerView.ViewHolder {
static class MediaViewHolder extends RecyclerView.ViewHolder {
private final MediaBinding binding;
private final ItemMediaBinding binding;
MediaViewHolder(MediaBinding binding) {
MediaViewHolder(ItemMediaBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
@ -225,13 +251,15 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
}
@Override
protected Bitmap doInBackground(Attachment... params) {
protected Bitmap doInBackground(final Attachment... params) {
this.attachment = params[0];
final XmppActivity activity = XmppActivity.find(imageViewReference);
if (activity == null) {
return null;
}
return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, mediaSize, false);
return activity.xmppConnectionService
.getFileBackend()
.getPreviewForUri(this.attachment, mediaSize, false);
}
@Override

View file

@ -15,22 +15,25 @@ import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.widget.ImageViewCompat;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ItemMediaPreviewBinding;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ConversationFragment;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.Attachment;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.MediaPreviewBinding;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.ConversationFragment;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.Attachment;
public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
public class MediaPreviewAdapter
extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
private final ArrayList<Attachment> mediaPreviews = new ArrayList<>();
@ -43,8 +46,9 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
@NonNull
@Override
public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false);
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ItemMediaPreviewBinding binding =
DataBindingUtil.inflate(layoutInflater, R.layout.item_media_preview, parent, false);
return new MediaPreviewViewHolder(binding);
}
@ -53,18 +57,19 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
final Context context = conversationFragment.getActivity();
final Attachment attachment = mediaPreviews.get(position);
if (attachment.renderThumbnail()) {
holder.binding.mediaPreview.setImageAlpha(255);
ImageViewCompat.setImageTintList(holder.binding.mediaPreview, null);
loadPreview(attachment, holder.binding.mediaPreview);
} else {
cancelPotentialWork(attachment, holder.binding.mediaPreview);
MediaAdapter.renderPreview(context, attachment, holder.binding.mediaPreview);
MediaAdapter.renderPreview(attachment, holder.binding.mediaPreview);
}
holder.binding.deleteButton.setOnClickListener(v -> {
final int pos = mediaPreviews.indexOf(attachment);
mediaPreviews.remove(pos);
notifyItemRemoved(pos);
conversationFragment.toggleInputMethod();
});
holder.binding.deleteButton.setOnClickListener(
v -> {
final int pos = mediaPreviews.indexOf(attachment);
mediaPreviews.remove(pos);
notifyItemRemoved(pos);
conversationFragment.toggleInputMethod();
});
holder.binding.mediaPreview.setOnClickListener(v -> view(context, attachment));
}
@ -76,9 +81,14 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
try {
context.startActivity(view);
} catch (final ActivityNotFoundException e) {
Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show();
Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT)
.show();
} catch (final SecurityException e) {
Toast.makeText(context, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
Toast.makeText(
context,
R.string.sharing_application_not_grant_permission,
Toast.LENGTH_SHORT)
.show();
}
}
@ -90,16 +100,27 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
private void loadPreview(Attachment attachment, ImageView imageView) {
if (cancelPotentialWork(attachment, imageView)) {
XmppActivity activity = (XmppActivity) conversationFragment.getActivity();
final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment,Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)),true);
final Bitmap bm =
activity.xmppConnectionService
.getFileBackend()
.getPreviewForUri(
attachment,
Math.round(
activity.getResources()
.getDimension(R.dimen.media_preview_size)),
true);
if (bm != null) {
cancelPotentialWork(attachment, imageView);
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
} else {
imageView.setBackgroundColor(0xff333333);
imageView.setBackgroundColor(
ContextCompat.getColor(imageView.getContext(), R.color.gray_800));
imageView.setImageDrawable(null);
final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task);
final AsyncDrawable asyncDrawable =
new AsyncDrawable(
conversationFragment.getActivity().getResources(), null, task);
imageView.setImageDrawable(asyncDrawable);
try {
task.execute(attachment);
@ -126,8 +147,7 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
if (imageView != null) {
final Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable) {
final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
if (drawable instanceof AsyncDrawable asyncDrawable) {
return asyncDrawable.getBitmapWorkerTask();
}
}
@ -140,7 +160,7 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
}
public boolean hasAttachments() {
return mediaPreviews.size() > 0;
return !mediaPreviews.isEmpty();
}
public ArrayList<Attachment> getAttachments() {
@ -153,9 +173,9 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
static class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
private final MediaPreviewBinding binding;
private final ItemMediaPreviewBinding binding;
MediaPreviewViewHolder(MediaPreviewBinding binding) {
MediaPreviewViewHolder(ItemMediaPreviewBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
@ -189,7 +209,14 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
if (activity == null) {
return null;
}
return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), false);
return activity.xmppConnectionService
.getFileBackend()
.getPreviewForUri(
this.attachment,
Math.round(
activity.getResources()
.getDimension(R.dimen.media_preview_size)),
false);
}
@Override

View file

@ -5,6 +5,7 @@ import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.os.Build;
import android.preference.PreferenceManager;
@ -20,16 +21,22 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.widget.ImageViewCompat;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.color.MaterialColors;
import com.google.common.base.Strings;
import java.net.URI;
@ -58,6 +65,7 @@ import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.service.AudioPlayer;
import eu.siacs.conversations.ui.text.DividerSpan;
import eu.siacs.conversations.ui.text.QuoteSpan;
import eu.siacs.conversations.ui.util.Attachment;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.MyLinkify;
import eu.siacs.conversations.ui.util.QuoteHelper;
@ -160,15 +168,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
return this.getItemViewType(getItem(position));
}
private int getMessageTextColor(boolean onDark, boolean primary) {
if (onDark) {
return ContextCompat.getColor(activity, primary ? R.color.white : R.color.white70);
} else {
return ContextCompat.getColor(activity, primary ? R.color.black87 : R.color.black54);
}
}
private void displayStatus(ViewHolder viewHolder, Message message, int type, boolean darkBackground) {
private void displayStatus(ViewHolder viewHolder, Message message, int type, final BubbleColor bubbleColor) {
String filesize = null;
String info = null;
boolean error = false;
@ -179,8 +179,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (viewHolder.edit_indicator != null) {
if (message.edited()) {
viewHolder.edit_indicator.setVisibility(View.VISIBLE);
viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp);
viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f);
setImageTint(viewHolder.edit_indicator, bubbleColor);
} else {
viewHolder.edit_indicator.setVisibility(View.GONE);
}
@ -211,8 +210,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
break;
case Message.STATUS_SEND_RECEIVED:
case Message.STATUS_SEND_DISPLAYED:
viewHolder.indicatorReceived.setImageResource(darkBackground ? R.drawable.ic_done_white_18dp : R.drawable.ic_done_black_18dp);
viewHolder.indicatorReceived.setAlpha(darkBackground ? 0.7f : 0.57f);
setImageTint(viewHolder.indicatorReceived, bubbleColor);
viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
break;
case Message.STATUS_SEND_FAILED:
@ -245,18 +243,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
break;
}
if (error && type == SENT) {
if (darkBackground) {
viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_Warning_OnDark);
} else {
viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_Warning);
}
viewHolder.time.setTextColor(MaterialColors.getColor(viewHolder.time, com.google.android.material.R.attr.colorError));
} else {
if (darkBackground) {
viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_OnDark);
} else {
viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption);
}
viewHolder.time.setTextColor(this.getMessageTextColor(darkBackground, false));
setTextColor(viewHolder.time,bubbleColor);
}
if (message.getEncryption() == Message.ENCRYPTION_NONE) {
viewHolder.indicator.setVisibility(View.GONE);
@ -271,15 +260,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
if (verified) {
viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_verified_user_white_18dp : R.drawable.ic_verified_user_black_18dp);
viewHolder.indicator.setImageResource(R.drawable.ic_verified_user_24dp);
} else {
viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_lock_white_18dp : R.drawable.ic_lock_black_18dp);
}
if (darkBackground) {
viewHolder.indicator.setAlpha(0.7f);
} else {
viewHolder.indicator.setAlpha(0.57f);
viewHolder.indicator.setImageResource(R.drawable.ic_lock_24dp);
}
setImageTint(viewHolder.indicator, bubbleColor);
viewHolder.indicator.setVisibility(View.VISIBLE);
}
@ -313,37 +298,29 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
private void displayInfoMessage(ViewHolder viewHolder, CharSequence text, boolean darkBackground) {
private void displayInfoMessage(ViewHolder viewHolder, CharSequence text, final BubbleColor bubbleColor) {
viewHolder.download_button.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE);
viewHolder.messageBody.setText(text);
if (darkBackground) {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Secondary_OnDark);
} else {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Secondary);
}
viewHolder.messageBody.setTextColor(bubbleToOnSurfaceVariant(viewHolder.messageBody,bubbleColor));
viewHolder.messageBody.setTextIsSelectable(false);
}
private void displayEmojiMessage(final ViewHolder viewHolder, final String body, final boolean darkBackground) {
private void displayEmojiMessage(final ViewHolder viewHolder, final String body, final BubbleColor bubbleColor) {
viewHolder.download_button.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE);
if (darkBackground) {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Emoji_OnDark);
} else {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Emoji);
}
Spannable span = new SpannableString(body);
setTextColor(viewHolder.messageBody, bubbleColor);
final Spannable span = new SpannableString(body);
float size = Emoticons.isEmoji(body) ? 3.0f : 2.0f;
span.setSpan(new RelativeSizeSpan(size), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
viewHolder.messageBody.setText(span);
}
private void applyQuoteSpan(SpannableStringBuilder body, int start, int end, boolean darkBackground) {
private void applyQuoteSpan(final TextView textView, SpannableStringBuilder body, int start, int end, final BubbleColor bubbleColor) {
if (start > 1 && !"\n\n".equals(body.subSequence(start - 2, start).toString())) {
body.insert(start++, "\n");
body.setSpan(new DividerSpan(false), start - 2, start, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@ -353,17 +330,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
body.insert(end, "\n");
body.setSpan(new DividerSpan(false), end, end + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
int color = darkBackground ? this.getMessageTextColor(darkBackground, false)
: ContextCompat.getColor(activity, R.color.green700_desaturated);
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
body.setSpan(new QuoteSpan(color, metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
body.setSpan(new QuoteSpan(bubbleToOnSurfaceVariant(textView, bubbleColor), metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
/**
* Applies QuoteSpan to group of lines which starts with > or » characters.
* Appends likebreaks and applies DividerSpan to them to show a padding between quote and text.
*/
private boolean handleTextQuotes(SpannableStringBuilder body, boolean darkBackground) {
private boolean handleTextQuotes(final TextView textView, final SpannableStringBuilder body, final BubbleColor bubbleColor) {
boolean startsWithQuote = false;
int quoteDepth = 1;
while (QuoteHelper.bodyContainsQuoteStart(body) && quoteDepth <= Config.QUOTE_MAX_DEPTH) {
@ -382,7 +357,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (i == 0) startsWithQuote = true;
} else if (quoteStart >= 0) {
// Line start without quote, apply spans there
applyQuoteSpan(body, quoteStart, i - 1, darkBackground);
applyQuoteSpan(textView, body, quoteStart, i - 1, bubbleColor);
quoteStart = -1;
}
}
@ -407,26 +382,19 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
if (quoteStart >= 0) {
// Apply spans to finishing open quote
applyQuoteSpan(body, quoteStart, body.length(), darkBackground);
applyQuoteSpan(textView, body, quoteStart, body.length(), bubbleColor);
}
quoteDepth++;
}
return startsWithQuote;
}
private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground, int type) {
private void displayTextMessage(final ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor, int type) {
viewHolder.download_button.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.messageBody.setVisibility(View.VISIBLE);
if (darkBackground) {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_OnDark);
} else {
viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1);
}
viewHolder.messageBody.setHighlightColor(ContextCompat.getColor(activity, darkBackground
? (type == SENT || !mUseGreenBackground ? R.color.black26 : R.color.grey800) : R.color.grey500));
setTextColor(viewHolder.messageBody, bubbleColor);
viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
if (message.getBody() != null) {
@ -446,7 +414,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
int end = body.getSpanEnd(mergeSeparator);
body.setSpan(new DividerSpan(true), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
boolean startsWithQuote = handleTextQuotes(body, darkBackground);
boolean startsWithQuote = handleTextQuotes(viewHolder.messageBody, body, bubbleColor);
if (!message.isPrivateMessage()) {
if (hasMeCommand) {
body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
@ -469,7 +437,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
body.insert(privateMarkerIndex, " ");
}
body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
body.setSpan(new ForegroundColorSpan(bubbleToOnSurfaceVariant(viewHolder.messageBody, bubbleColor)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (hasMeCommand) {
body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1,
@ -477,8 +445,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
if (message.getConversation().getMode() == Conversation.MODE_MULTI && message.getStatus() == Message.STATUS_RECEIVED) {
if (message.getConversation() instanceof Conversation) {
final Conversation conversation = (Conversation) message.getConversation();
if (message.getConversation() instanceof Conversation conversation) {
Pattern pattern = NotificationService.generateNickHighlightPattern(conversation.getMucOptions().getActualNick());
Matcher matcher = pattern.matcher(body);
while (matcher.find()) {
@ -495,7 +462,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
StylingHelper.format(body, viewHolder.messageBody.getCurrentTextColor());
if (highlightedTerm != null) {
StylingHelper.highlight(activity, body, highlightedTerm, StylingHelper.isDarkText(viewHolder.messageBody));
StylingHelper.highlight(viewHolder.messageBody, body, highlightedTerm);
}
MyLinkify.addLinks(body, true);
viewHolder.messageBody.setAutoLinkMask(0);
@ -507,45 +474,54 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text, final boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text, final BubbleColor bubbleColor) {
toggleWhisperInfo(viewHolder, message, bubbleColor);
viewHolder.image.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.download_button.setVisibility(View.VISIBLE);
viewHolder.download_button.setText(text);
final var attachment = Attachment.of(message);
final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
viewHolder.download_button.setIconResource(imageResource);
viewHolder.download_button.setOnClickListener(v -> ConversationFragment.downloadFile(activity, message));
}
private void displayOpenableMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
private void displayOpenableMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
toggleWhisperInfo(viewHolder, message, bubbleColor);
viewHolder.image.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.download_button.setVisibility(View.VISIBLE);
viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message)));
final var attachment = Attachment.of(message);
final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
viewHolder.download_button.setIconResource(imageResource);
viewHolder.download_button.setOnClickListener(v -> openDownloadable(message));
}
private void displayLocationMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
private void displayLocationMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
toggleWhisperInfo(viewHolder, message, bubbleColor);
viewHolder.image.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.download_button.setVisibility(View.VISIBLE);
viewHolder.download_button.setText(R.string.show_location);
final var attachment = Attachment.of(message);
final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
viewHolder.download_button.setIconResource(imageResource);
viewHolder.download_button.setOnClickListener(v -> showLocation(message));
}
private void displayAudioMessage(ViewHolder viewHolder, Message message, boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
private void displayAudioMessage(ViewHolder viewHolder, Message message, final BubbleColor bubbleColor) {
toggleWhisperInfo(viewHolder, message, bubbleColor);
viewHolder.image.setVisibility(View.GONE);
viewHolder.download_button.setVisibility(View.GONE);
final RelativeLayout audioPlayer = viewHolder.audioPlayer;
audioPlayer.setVisibility(View.VISIBLE);
AudioPlayer.ViewHolder.get(audioPlayer).setDarkBackground(darkBackground);
AudioPlayer.ViewHolder.get(audioPlayer).setBubbleColor(bubbleColor);
this.audioPlayer.init(audioPlayer, message);
}
private void displayMediaPreviewMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
private void displayMediaPreviewMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
toggleWhisperInfo(viewHolder, message, bubbleColor);
viewHolder.download_button.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE);
@ -573,7 +549,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.image.setOnClickListener(v -> openDownloadable(message));
}
private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
if (message.isPrivateMessage()) {
final String privateMarker;
if (message.getStatus() <= Message.STATUS_RECEIVED) {
@ -583,7 +559,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
privateMarker = activity.getString(R.string.private_message_to, Strings.nullToEmpty(cp == null ? null : cp.getResource()));
}
final SpannableString body = new SpannableString(privateMarker);
body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
body.setSpan(new ForegroundColorSpan(bubbleToOnSurfaceVariant(viewHolder.messageBody, bubbleColor)), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
viewHolder.messageBody.setText(body);
viewHolder.messageBody.setVisibility(View.VISIBLE);
@ -611,7 +587,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
@Override
public View getView(int position, View view, ViewGroup parent) {
public View getView(final int position, View view, final @NonNull ViewGroup parent) {
final Message message = getItem(position);
final boolean omemoEncryption = message.getEncryption() == Message.ENCRYPTION_AXOLOTL;
final boolean isInValidSession = message.isValidInSession() && (!omemoEncryption || message.isTrusted());
@ -623,19 +599,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder = new ViewHolder();
switch (type) {
case DATE_SEPARATOR:
view = activity.getLayoutInflater().inflate(R.layout.message_date_bubble, parent, false);
view = activity.getLayoutInflater().inflate(R.layout.item_message_date_bubble, parent, false);
viewHolder.status_message = view.findViewById(R.id.message_body);
viewHolder.message_box = view.findViewById(R.id.message_box);
viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
break;
case RTP_SESSION:
view = activity.getLayoutInflater().inflate(R.layout.message_rtp_session, parent, false);
view = activity.getLayoutInflater().inflate(R.layout.item_message_rtp_session, parent, false);
viewHolder.status_message = view.findViewById(R.id.message_body);
viewHolder.message_box = view.findViewById(R.id.message_box);
viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
break;
case SENT:
view = activity.getLayoutInflater().inflate(R.layout.message_sent, parent, false);
view = activity.getLayoutInflater().inflate(R.layout.item_message_sent, parent, false);
viewHolder.message_box = view.findViewById(R.id.message_box);
viewHolder.contact_picture = view.findViewById(R.id.message_photo);
viewHolder.download_button = view.findViewById(R.id.download_button);
@ -648,7 +623,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
break;
case RECEIVED:
view = activity.getLayoutInflater().inflate(R.layout.message_received, parent, false);
view = activity.getLayoutInflater().inflate(R.layout.item_message_received, parent, false);
viewHolder.message_box = view.findViewById(R.id.message_box);
viewHolder.contact_picture = view.findViewById(R.id.message_photo);
viewHolder.download_button = view.findViewById(R.id.download_button);
@ -662,7 +637,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
break;
case STATUS:
view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false);
view = activity.getLayoutInflater().inflate(R.layout.item_message_status, parent, false);
viewHolder.contact_picture = view.findViewById(R.id.message_photo);
viewHolder.status_message = view.findViewById(R.id.status_message);
viewHolder.load_more_messages = view.findViewById(R.id.load_more_messages);
@ -678,7 +653,17 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
boolean darkBackground = type == RECEIVED && (!isInValidSession || mUseGreenBackground) || activity.isDarkTheme();
final boolean colorfulBackground = mUseGreenBackground;
final BubbleColor bubbleColor;
if (type == RECEIVED) {
if (isInValidSession) {
bubbleColor = colorfulBackground ? BubbleColor.TERTIARY : BubbleColor.SURFACE;
} else {
bubbleColor = BubbleColor.WARNING;
}
} else {
bubbleColor = colorfulBackground ? BubbleColor.SECONDARY : BubbleColor.SURFACE;
}
if (type == DATE_SEPARATOR) {
if (UIHelper.today(message.getTimeSent())) {
@ -688,10 +673,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
} else {
viewHolder.status_message.setText(DateUtils.formatDateTime(activity, message.getTimeSent(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR));
}
viewHolder.message_box.setBackgroundResource(activity.isDarkTheme() ? R.drawable.date_bubble_grey : R.drawable.date_bubble_white);
if (colorfulBackground) {
setBackgroundTint(viewHolder.message_box,BubbleColor.PRIMARY);
setTextColor(viewHolder.status_message, BubbleColor.PRIMARY);
} else {
setBackgroundTint(viewHolder.message_box,BubbleColor.SURFACE);
setTextColor(viewHolder.status_message, BubbleColor.SURFACE);
}
return view;
} else if (type == RTP_SESSION) {
final boolean isDarkTheme = activity.isDarkTheme();
final boolean received = message.getStatus() <= Message.STATUS_RECEIVED;
final RtpSessionStatus rtpSessionStatus = RtpSessionStatus.of(message.getBody());
final long duration = rtpSessionStatus.duration;
@ -710,9 +700,16 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.status_message.setText(activity.getString(R.string.outgoing_call_timestamp, UIHelper.readableTimeDifferenceFull(activity, message.getTimeSent())));
}
}
viewHolder.indicatorReceived.setImageResource(RtpSessionStatus.getDrawable(received, rtpSessionStatus.successful, isDarkTheme));
viewHolder.indicatorReceived.setAlpha(isDarkTheme ? 0.7f : 0.57f);
viewHolder.message_box.setBackgroundResource(isDarkTheme ? R.drawable.date_bubble_grey : R.drawable.date_bubble_white);
if (colorfulBackground) {
setBackgroundTint(viewHolder.message_box,BubbleColor.TERTIARY);
setTextColor(viewHolder.status_message, BubbleColor.TERTIARY);
setImageTint(viewHolder.indicatorReceived, BubbleColor.TERTIARY);
} else {
setBackgroundTint(viewHolder.message_box,BubbleColor.SURFACE);
setTextColor(viewHolder.status_message, BubbleColor.SURFACE);
setImageTint(viewHolder.indicatorReceived, BubbleColor.SURFACE);
}
viewHolder.indicatorReceived.setImageResource(RtpSessionStatus.getDrawable(received, rtpSessionStatus.successful));
return view;
} else if (type == STATUS) {
if ("LOAD_MORE".equals(message.getBody())) {
@ -769,43 +766,43 @@ public class MessageAdapter extends ArrayAdapter<Message> {
final boolean unInitiatedButKnownSize = MessageUtils.unInitiatedButKnownSize(message);
if (unInitiatedButKnownSize || message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) {
if (unInitiatedButKnownSize || transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), darkBackground);
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), bubbleColor);
} else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), darkBackground);
displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), bubbleColor);
} else {
displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground);
displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, bubbleColor);
}
} else if (message.isFileOrImage() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
if (message.getFileParams().width > 0 && message.getFileParams().height > 0) {
displayMediaPreviewMessage(viewHolder, message, darkBackground);
displayMediaPreviewMessage(viewHolder, message, bubbleColor);
} else if (message.getFileParams().runtime > 0) {
displayAudioMessage(viewHolder, message, darkBackground);
displayAudioMessage(viewHolder, message, bubbleColor);
} else {
displayOpenableMessage(viewHolder, message, darkBackground);
displayOpenableMessage(viewHolder, message, bubbleColor);
}
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
if (account.isPgpDecryptionServiceConnected()) {
if (conversation instanceof Conversation && !account.hasPendingPgpIntent((Conversation) conversation)) {
displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), bubbleColor);
} else {
displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), bubbleColor);
}
} else {
displayInfoMessage(viewHolder, activity.getString(R.string.install_openkeychain), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.install_openkeychain), bubbleColor);
viewHolder.message_box.setOnClickListener(this::promptOpenKeychainInstall);
viewHolder.messageBody.setOnClickListener(this::promptOpenKeychainInstall);
}
} else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
displayInfoMessage(viewHolder, activity.getString(R.string.decryption_failed), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.decryption_failed), bubbleColor);
} else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE) {
displayInfoMessage(viewHolder, activity.getString(R.string.not_encrypted_for_this_device), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.not_encrypted_for_this_device), bubbleColor);
} else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
displayInfoMessage(viewHolder, activity.getString(R.string.omemo_decryption_failed), darkBackground);
displayInfoMessage(viewHolder, activity.getString(R.string.omemo_decryption_failed), bubbleColor);
} else {
if (message.isGeoUri()) {
displayLocationMessage(viewHolder, message, darkBackground);
displayLocationMessage(viewHolder, message, bubbleColor);
} else if (message.bodyIsOnlyEmojis() && message.getType() != Message.TYPE_PRIVATE) {
displayEmojiMessage(viewHolder, message.getBody().trim(), darkBackground);
displayEmojiMessage(viewHolder, message.getBody().trim(), bubbleColor);
} else if (message.treatAsDownloadable()) {
try {
final URI uri = new URI(message.getBody());
@ -814,31 +811,27 @@ public class MessageAdapter extends ArrayAdapter<Message> {
activity.getString(R.string.check_x_filesize_on_host,
UIHelper.getFileDescriptionString(activity, message),
uri.getHost()),
darkBackground);
bubbleColor);
} catch (Exception e) {
displayDownloadableMessage(viewHolder,
message,
activity.getString(R.string.check_x_filesize,
UIHelper.getFileDescriptionString(activity, message)),
darkBackground);
bubbleColor);
}
} else {
displayTextMessage(viewHolder, message, darkBackground, type);
displayTextMessage(viewHolder, message, bubbleColor, type);
}
}
setBackgroundTint(viewHolder.message_box, bubbleColor);
setTextColor(viewHolder.messageBody, bubbleColor);
if (type == RECEIVED) {
setTextColor(viewHolder.encryption, bubbleColor);
if (isInValidSession) {
int bubble;
if (!mUseGreenBackground) {
bubble = activity.getThemeResource(R.attr.message_bubble_received_monochrome, R.drawable.message_bubble_received_white);
} else {
bubble = activity.getThemeResource(R.attr.message_bubble_received_green, R.drawable.message_bubble_received);
}
viewHolder.message_box.setBackgroundResource(bubble);
viewHolder.encryption.setVisibility(View.GONE);
} else {
viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning);
viewHolder.encryption.setVisibility(View.VISIBLE);
if (omemoEncryption && !message.isTrusted()) {
viewHolder.encryption.setText(R.string.not_trusted);
@ -848,7 +841,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
}
displayStatus(viewHolder, message, type, darkBackground);
displayStatus(viewHolder, message, type, bubbleColor);
return view;
}
@ -911,13 +904,68 @@ public class MessageAdapter extends ArrayAdapter<Message> {
void onContactPictureLongClicked(View v, Message message);
}
private static void setBackgroundTint(final View view, final BubbleColor bubbleColor) {
view.setBackgroundTintList(bubbleToColorStateList(view, bubbleColor));
}
private static ColorStateList bubbleToColorStateList(final View view, final BubbleColor bubbleColor) {
final @AttrRes int colorAttributeResId = switch (bubbleColor) {
case SURFACE -> com.google.android.material.R.attr.colorSurfaceContainerHigh;
case PRIMARY -> com.google.android.material.R.attr.colorPrimaryContainer;
case SECONDARY -> com.google.android.material.R.attr.colorSecondaryContainer;
case TERTIARY -> com.google.android.material.R.attr.colorTertiaryContainer;
case WARNING -> com.google.android.material.R.attr.colorErrorContainer;
};
return ColorStateList.valueOf(MaterialColors.getColor(view,colorAttributeResId));
}
public static void setImageTint(final ImageView imageView, final BubbleColor bubbleColor) {
ImageViewCompat.setImageTintList(imageView,bubbleToOnSurfaceColorStateList(imageView, bubbleColor));
}
public static void setTextColor(final TextView textView, final BubbleColor bubbleColor) {
textView.setTextColor(bubbleToOnSurfaceColor(textView, bubbleColor));
}
private static @ColorInt int bubbleToOnSurfaceVariant(final View view, final BubbleColor bubbleColor) {
final @AttrRes int colorAttributeResId;
if (bubbleColor == BubbleColor.SURFACE) {
colorAttributeResId = com.google.android.material.R.attr.colorOnSurfaceVariant;
} else {
colorAttributeResId = bubbleToOnSurface(bubbleColor);
}
return MaterialColors.getColor(view,colorAttributeResId);
}
private static @ColorInt int bubbleToOnSurfaceColor(final View view, final BubbleColor bubbleColor) {
return MaterialColors.getColor(view, bubbleToOnSurface(bubbleColor));
}
public static ColorStateList bubbleToOnSurfaceColorStateList(final View view, final BubbleColor bubbleColor) {
return ColorStateList.valueOf(bubbleToOnSurfaceColor(view, bubbleColor));
}
private static @AttrRes int bubbleToOnSurface(final BubbleColor bubbleColor) {
return switch (bubbleColor) {
case SURFACE -> com.google.android.material.R.attr.colorOnSurface;
case PRIMARY -> com.google.android.material.R.attr.colorOnPrimaryContainer;
case SECONDARY -> com.google.android.material.R.attr.colorOnSecondaryContainer;
case TERTIARY -> com.google.android.material.R.attr.colorOnTertiaryContainer;
case WARNING -> com.google.android.material.R.attr.colorOnErrorContainer;
};
}
public enum BubbleColor {
SURFACE, PRIMARY, SECONDARY, TERTIARY, WARNING
}
private static class ViewHolder {
public Button load_more_messages;
public MaterialButton load_more_messages;
public ImageView edit_indicator;
public RelativeLayout audioPlayer;
protected LinearLayout message_box;
protected Button download_button;
protected MaterialButton download_button;
protected ImageView image;
protected ImageView indicator;
protected ImageView indicatorReceived;

View file

@ -17,7 +17,7 @@ import org.openintents.openpgp.util.OpenPgpUtils;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.databinding.ContactBinding;
import eu.siacs.conversations.databinding.ItemContactBinding;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.XmppConnectionService;
@ -62,7 +62,7 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.contact, viewGroup, false));
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_contact, viewGroup, false));
}
@Override
@ -129,11 +129,11 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
MucDetailsContextMenuHelper.onCreateContextMenu(menu,v);
}
class ViewHolder extends RecyclerView.ViewHolder {
static class ViewHolder extends RecyclerView.ViewHolder {
private final ContactBinding binding;
private final ItemContactBinding binding;
private ViewHolder(ContactBinding binding) {
private ViewHolder(ItemContactBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

View file

@ -11,13 +11,14 @@ import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.UserPreviewBinding;
import eu.siacs.conversations.databinding.ItemUserPreviewBinding;
import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.util.AvatarWorkerTask;
import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper;
public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreviewAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreviewAdapter.ViewHolder>
implements View.OnCreateContextMenuListener {
private MucOptions.User selectedUser = null;
@ -28,29 +29,43 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.user_preview, viewGroup, false));
return new ViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(viewGroup.getContext()),
R.layout.item_user_preview,
viewGroup,
false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
final MucOptions.User user = getItem(position);
AvatarWorkerTask.loadAvatar(user, viewHolder.binding.avatar, R.dimen.media_size);
viewHolder.binding.getRoot().setOnClickListener(v -> {
final XmppActivity activity = XmppActivity.find(v);
if (activity != null) {
activity.highlightInMuc(user.getConversation(), user.getName());
}
});
viewHolder
.binding
.getRoot()
.setOnClickListener(
v -> {
final XmppActivity activity = XmppActivity.find(v);
if (activity != null) {
activity.highlightInMuc(user.getConversation(), user.getName());
}
});
viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
viewHolder.binding.getRoot().setTag(user);
viewHolder.binding.getRoot().setOnLongClickListener(v -> {
selectedUser = user;
return false;
});
viewHolder
.binding
.getRoot()
.setOnLongClickListener(
v -> {
selectedUser = user;
return false;
});
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
public void onCreateContextMenu(
ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MucDetailsContextMenuHelper.onCreateContextMenu(menu, v);
}
@ -60,9 +75,9 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
class ViewHolder extends RecyclerView.ViewHolder {
private final UserPreviewBinding binding;
private final ItemUserPreviewBinding binding;
private ViewHolder(UserPreviewBinding binding) {
private ViewHolder(final ItemUserPreviewBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

View file

@ -1,80 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.xmpp.forms.Field;
public class FormBooleanFieldWrapper extends FormFieldWrapper {
protected CheckBox checkBox;
protected FormBooleanFieldWrapper(Context context, Field field) {
super(context, field);
checkBox = view.findViewById(R.id.field);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkBox.setError(null);
invokeOnFormFieldValuesEdited();
}
});
}
@Override
protected void setLabel(String label, boolean required) {
CheckBox checkBox = view.findViewById(R.id.field);
checkBox.setText(createSpannableLabelString(label, required));
}
@Override
public List<String> getValues() {
List<String> values = new ArrayList<>();
values.add(Boolean.toString(checkBox.isChecked()));
return values;
}
@Override
protected void setValues(List<String> values) {
if (values.size() == 0) {
checkBox.setChecked(false);
} else {
checkBox.setChecked(Boolean.parseBoolean(values.get(0)));
}
}
@Override
public boolean validates() {
if (checkBox.isChecked() || !field.isRequired()) {
return true;
} else {
checkBox.setError(context.getString(R.string.this_field_is_required));
checkBox.requestFocus();
return false;
}
}
@Override
public boolean edited() {
if (field.getValues().size() == 0) {
return checkBox.isChecked();
} else {
return super.edited();
}
}
@Override
protected int getLayoutResource() {
return R.layout.form_boolean;
}
@Override
void setReadOnly(boolean readOnly) {
checkBox.setEnabled(!readOnly);
}
}

View file

@ -1,30 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import java.util.Hashtable;
import eu.siacs.conversations.xmpp.forms.Field;
public class FormFieldFactory {
private static final Hashtable<String, Class> typeTable = new Hashtable<>();
static {
typeTable.put("text-single", FormTextFieldWrapper.class);
typeTable.put("text-multi", FormTextFieldWrapper.class);
typeTable.put("text-private", FormTextFieldWrapper.class);
typeTable.put("jid-single", FormJidSingleFieldWrapper.class);
typeTable.put("boolean", FormBooleanFieldWrapper.class);
}
protected static FormFieldWrapper createFromField(Context context, Field field) {
Class clazz = typeTable.get(field.getType());
if (clazz == null) {
clazz = FormTextFieldWrapper.class;
}
return FormFieldWrapper.createFromField(clazz, context, field);
}
}

View file

@ -1,93 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.View;
import java.util.List;
import eu.siacs.conversations.ui.util.StyledAttributes;
import eu.siacs.conversations.xmpp.forms.Field;
public abstract class FormFieldWrapper {
protected final Context context;
protected final Field field;
protected final View view;
OnFormFieldValuesEdited onFormFieldValuesEditedListener;
FormFieldWrapper(Context context, Field field) {
this.context = context;
this.field = field;
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.view = inflater.inflate(getLayoutResource(), null);
String label = field.getLabel();
if (label == null) {
label = field.getFieldName();
}
setLabel(label, field.isRequired());
}
public final void submit() {
this.field.setValues(getValues());
}
public final View getView() {
return view;
}
protected abstract void setLabel(String label, boolean required);
abstract List<String> getValues();
protected abstract void setValues(List<String> values);
abstract boolean validates();
abstract protected int getLayoutResource();
abstract void setReadOnly(boolean readOnly);
protected SpannableString createSpannableLabelString(String label, boolean required) {
SpannableString spannableString = new SpannableString(label + (required ? " *" : ""));
if (required) {
int start = label.length();
int end = label.length() + 2;
spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, end, 0);
spannableString.setSpan(new ForegroundColorSpan(StyledAttributes.getColor(context, androidx.appcompat.R.attr.colorAccent)), start, end, 0);
}
return spannableString;
}
protected void invokeOnFormFieldValuesEdited() {
if (this.onFormFieldValuesEditedListener != null) {
this.onFormFieldValuesEditedListener.onFormFieldValuesEdited();
}
}
public boolean edited() {
return !field.getValues().equals(getValues());
}
public void setOnFormFieldValuesEditedListener(OnFormFieldValuesEdited listener) {
this.onFormFieldValuesEditedListener = listener;
}
protected static <F extends FormFieldWrapper> FormFieldWrapper createFromField(Class<F> c, Context context, Field field) {
try {
F fieldWrapper = c.getDeclaredConstructor(Context.class, Field.class).newInstance(context,field);
fieldWrapper.setValues(field.getValues());
return fieldWrapper;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public interface OnFormFieldValuesEdited {
void onFormFieldValuesEdited();
}
}

View file

@ -1,43 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import android.text.InputType;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.forms.Field;
public class FormJidSingleFieldWrapper extends FormTextFieldWrapper {
protected FormJidSingleFieldWrapper(Context context, Field field) {
super(context, field);
editText.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
editText.setHint(R.string.account_settings_example_jabber_id);
}
@Override
public boolean validates() {
String value = getValue();
if (!value.isEmpty()) {
try {
Jid.of(value);
} catch (IllegalArgumentException e) {
editText.setError(context.getString(R.string.invalid_jid));
editText.requestFocus();
return false;
}
}
return super.validates();
}
@Override
protected void setValues(List<String> values) {
StringBuilder builder = new StringBuilder();
for(String value : values) {
builder.append(value);
}
editText.setText(builder.toString());
}
}

View file

@ -1,97 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.R;
import eu.siacs.conversations.xmpp.forms.Field;
public class FormTextFieldWrapper extends FormFieldWrapper {
protected EditText editText;
protected FormTextFieldWrapper(Context context, Field field) {
super(context, field);
editText = view.findViewById(R.id.field);
editText.setSingleLine(!"text-multi".equals(field.getType()));
if ("text-private".equals(field.getType())) {
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
editText.setError(null);
invokeOnFormFieldValuesEdited();
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
@Override
protected void setLabel(String label, boolean required) {
TextView textView = view.findViewById(R.id.label);
textView.setText(createSpannableLabelString(label, required));
}
protected String getValue() {
return editText.getText().toString();
}
@Override
public List<String> getValues() {
List<String> values = new ArrayList<>();
for (String line : getValue().split("\\n")) {
if (line.length() > 0) {
values.add(line);
}
}
return values;
}
@Override
protected void setValues(List<String> values) {
StringBuilder builder = new StringBuilder();
for(int i = 0; i < values.size(); ++i) {
builder.append(values.get(i));
if (i < values.size() - 1 && "text-multi".equals(field.getType())) {
builder.append("\n");
}
}
editText.setText(builder.toString());
}
@Override
public boolean validates() {
if (getValue().trim().length() > 0 || !field.isRequired()) {
return true;
} else {
editText.setError(context.getString(R.string.this_field_is_required));
editText.requestFocus();
return false;
}
}
@Override
protected int getLayoutResource() {
return R.layout.form_text;
}
@Override
void setReadOnly(boolean readOnly) {
editText.setEnabled(!readOnly);
}
}

View file

@ -1,72 +0,0 @@
package eu.siacs.conversations.ui.forms;
import android.content.Context;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
import eu.siacs.conversations.xmpp.forms.Data;
import eu.siacs.conversations.xmpp.forms.Field;
public class FormWrapper {
private final LinearLayout layout;
private final Data form;
private final List<FormFieldWrapper> fieldWrappers = new ArrayList<>();
private FormWrapper(Context context, LinearLayout linearLayout, Data form) {
this.form = form;
this.layout = linearLayout;
this.layout.removeAllViews();
for(Field field : form.getFields()) {
FormFieldWrapper fieldWrapper = FormFieldFactory.createFromField(context,field);
if (fieldWrapper != null) {
layout.addView(fieldWrapper.getView());
fieldWrappers.add(fieldWrapper);
}
}
}
public Data submit() {
for(FormFieldWrapper fieldWrapper : fieldWrappers) {
fieldWrapper.submit();
}
this.form.submit();
return this.form;
}
public boolean validates() {
boolean validates = true;
for(FormFieldWrapper fieldWrapper : fieldWrappers) {
validates &= fieldWrapper.validates();
}
return validates;
}
public void setOnFormFieldValuesEditedListener(FormFieldWrapper.OnFormFieldValuesEdited listener) {
for(FormFieldWrapper fieldWrapper : fieldWrappers) {
fieldWrapper.setOnFormFieldValuesEditedListener(listener);
}
}
public void setReadOnly(boolean b) {
for(FormFieldWrapper fieldWrapper : fieldWrappers) {
fieldWrapper.setReadOnly(b);
}
}
public boolean edited() {
boolean edited = false;
for(FormFieldWrapper fieldWrapper : fieldWrappers) {
edited |= fieldWrapper.edited();
}
return edited;
}
public static FormWrapper createInLayout(Context context, LinearLayout layout, Data form) {
return new FormWrapper(context, layout, form);
}
}

View file

@ -22,11 +22,6 @@ import android.widget.TextView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.lang.ref.WeakReference;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Message;
@ -36,7 +31,17 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.utils.WeakReferenceSet;
public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener, Runnable, SensorEventListener {
import java.lang.ref.WeakReference;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AudioPlayer
implements View.OnClickListener,
MediaPlayer.OnCompletionListener,
SeekBar.OnSeekBarChangeListener,
Runnable,
SensorEventListener {
private static final int REFRESH_INTERVAL = 250;
private static final Object LOCK = new Object();
@ -57,33 +62,43 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
final Context context = adapter.getContext();
this.messageAdapter = adapter;
this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
this.proximitySensor = this.sensorManager == null ? null : this.sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
this.proximitySensor =
this.sensorManager == null
? null
: this.sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
initializeProximityWakeLock(context);
synchronized (AudioPlayer.LOCK) {
if (AudioPlayer.player != null) {
AudioPlayer.player.setOnCompletionListener(this);
if (AudioPlayer.player.isPlaying() && sensorManager != null) {
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(
this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
}
}
private static String formatTime(int ms) {
return String.format(Locale.ENGLISH, "%d:%02d", ms / 60000, Math.min(Math.round((ms % 60000) / 1000f), 59));
return String.format(
Locale.ENGLISH,
"%d:%02d",
ms / 60000,
Math.min(Math.round((ms % 60000) / 1000f), 59));
}
private void initializeProximityWakeLock(Context context) {
if (Build.VERSION.SDK_INT >= 21) {
synchronized (AudioPlayer.LOCK) {
if (AudioPlayer.wakeLock == null) {
final PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
AudioPlayer.wakeLock = powerManager == null ? null : powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, AudioPlayer.class.getSimpleName());
AudioPlayer.wakeLock.setReferenceCounted(false);
}
synchronized (AudioPlayer.LOCK) {
if (AudioPlayer.wakeLock == null) {
final PowerManager powerManager =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
AudioPlayer.wakeLock =
powerManager == null
? null
: powerManager.newWakeLock(
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
AudioPlayer.class.getSimpleName());
AudioPlayer.wakeLock.setReferenceCounted(false);
}
} else {
AudioPlayer.wakeLock = null;
}
}
@ -92,41 +107,39 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
audioPlayer.setTag(message);
if (init(ViewHolder.get(audioPlayer), message)) {
this.audioPlayerLayouts.addWeakReferenceTo(audioPlayer);
executor.execute(()-> this.stopRefresher(true));
executor.execute(() -> this.stopRefresher(true));
} else {
this.audioPlayerLayouts.removeWeakReferenceTo(audioPlayer);
}
}
}
private boolean init(ViewHolder viewHolder, Message message) {
if (viewHolder.darkBackground) {
viewHolder.runtime.setTextAppearance(this.messageAdapter.getContext(), R.style.TextAppearance_Conversations_Caption_OnDark);
} else {
viewHolder.runtime.setTextAppearance(this.messageAdapter.getContext(), R.style.TextAppearance_Conversations_Caption);
}
private boolean init(final ViewHolder viewHolder, final Message message) {
MessageAdapter.setTextColor(viewHolder.runtime, viewHolder.bubbleColor);
viewHolder.progress.setOnSeekBarChangeListener(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ColorStateList color = ContextCompat.getColorStateList(messageAdapter.getContext(), viewHolder.darkBackground ? R.color.white70 : R.color.green700_desaturated);
viewHolder.progress.setThumbTintList(color);
viewHolder.progress.setProgressTintList(color);
}
viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
final ColorStateList color =
MessageAdapter.bubbleToOnSurfaceColorStateList(
viewHolder.progress, viewHolder.bubbleColor);
viewHolder.progress.setThumbTintList(color);
viewHolder.progress.setProgressTintList(color);
viewHolder.playPause.setOnClickListener(this);
final Context context = viewHolder.playPause.getContext();
if (message == currentlyPlayingMessage) {
if (AudioPlayer.player != null && AudioPlayer.player.isPlaying()) {
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
viewHolder.progress.setEnabled(true);
} else {
viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
viewHolder.progress.setEnabled(false);
}
return true;
} else {
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
viewHolder.progress.setProgress(0);
@ -145,9 +158,16 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
private void startStop(ImageButton playPause) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(messageAdapter.getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
&& ContextCompat.checkSelfPermission(
messageAdapter.getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
pendingOnClickView.push(new WeakReference<>(playPause));
ActivityCompat.requestPermissions(messageAdapter.getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, ConversationsActivity.REQUEST_PLAY_PAUSE);
ActivityCompat.requestPermissions(
messageAdapter.getActivity(),
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
ConversationsActivity.REQUEST_PLAY_PAUSE);
return;
}
initializeProximityWakeLock(playPause.getContext());
@ -163,13 +183,13 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
private boolean playPauseCurrent(final ViewHolder viewHolder) {
final Context context = viewHolder.playPause.getContext();
viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
if (player.isPlaying()) {
viewHolder.progress.setEnabled(false);
player.pause();
messageAdapter.flagScreenOff();
releaseProximityWakeLock();
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
} else {
viewHolder.progress.setEnabled(true);
@ -177,7 +197,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
messageAdapter.flagScreenOn();
acquireProximityWakeLock();
this.stopRefresher(true);
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
}
return false;
@ -193,19 +214,24 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
AudioPlayer.player = new MediaPlayer();
try {
AudioPlayer.currentlyPlayingMessage = message;
AudioPlayer.player.setAudioStreamType(earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
AudioPlayer.player.setAudioStreamType(
earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
AudioPlayer.player.setDataSource(
messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
AudioPlayer.player.setOnCompletionListener(this);
AudioPlayer.player.prepare();
AudioPlayer.player.start();
messageAdapter.flagScreenOn();
acquireProximityWakeLock();
viewHolder.progress.setEnabled(true);
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.pause_audio));
sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
viewHolder.playPause.setContentDescription(
viewHolder.playPause.getContext().getString(R.string.pause_audio));
sensorManager.registerListener(
this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
return true;
} catch (Exception e) {
} catch (final Exception e) {
messageAdapter.flagScreenOff();
releaseProximityWakeLock();
AudioPlayer.currentlyPlayingMessage = null;
@ -251,14 +277,16 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
}
private void resetPlayerUi(RelativeLayout audioPlayer) {
private void resetPlayerUi(final RelativeLayout audioPlayer) {
if (audioPlayer == null) {
return;
}
final ViewHolder viewHolder = ViewHolder.get(audioPlayer);
final Message message = (Message) audioPlayer.getTag();
viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.play_audio));
viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
viewHolder.playPause.setContentDescription(
viewHolder.playPause.getContext().getString(R.string.play_audio));
viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
if (message != null) {
viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
}
@ -297,14 +325,10 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch(SeekBar seekBar) {}
public void stop() {
synchronized (AudioPlayer.LOCK) {
@ -361,7 +385,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
} else {
viewHolder.progress.setProgress(current * 100 / duration);
}
viewHolder.runtime.setText(String.format("%s / %s", formatTime(current), formatTime(duration)));
viewHolder.runtime.setText(
String.format("%s / %s", formatTime(current), formatTime(duration)));
return true;
}
@ -391,7 +416,11 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
try {
ViewHolder currentViewHolder = getCurrentViewHolder();
if (currentViewHolder != null) {
play(currentViewHolder, currentlyPlayingMessage, streamType == AudioManager.STREAM_VOICE_CALL, progress);
play(
currentViewHolder,
currentlyPlayingMessage,
streamType == AudioManager.STREAM_VOICE_CALL,
progress);
}
} catch (Exception e) {
Log.w(Config.LOGTAG, e);
@ -401,8 +430,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
public void onAccuracyChanged(Sensor sensor, int i) {}
private void acquireProximityWakeLock() {
synchronized (AudioPlayer.LOCK) {
@ -435,22 +463,24 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
private TextView runtime;
private SeekBar progress;
private ImageButton playPause;
private boolean darkBackground = false;
private MessageAdapter.BubbleColor bubbleColor = MessageAdapter.BubbleColor.SURFACE;
public static ViewHolder get(RelativeLayout audioPlayer) {
ViewHolder viewHolder = (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
if (viewHolder == null) {
viewHolder = new ViewHolder();
viewHolder.runtime = audioPlayer.findViewById(R.id.runtime);
viewHolder.progress = audioPlayer.findViewById(R.id.progress);
viewHolder.playPause = audioPlayer.findViewById(R.id.play_pause);
audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
public static ViewHolder get(final RelativeLayout audioPlayer) {
final var existingViewHolder =
(ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
if (existingViewHolder != null) {
return existingViewHolder;
}
final ViewHolder viewHolder = new ViewHolder();
viewHolder.runtime = audioPlayer.findViewById(R.id.runtime);
viewHolder.progress = audioPlayer.findViewById(R.id.progress);
viewHolder.playPause = audioPlayer.findViewById(R.id.play_pause);
audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
return viewHolder;
}
public void setDarkBackground(boolean darkBackground) {
this.darkBackground = darkBackground;
public void setBubbleColor(final MessageAdapter.BubbleColor bubbleColor) {
this.bubbleColor = bubbleColor;
}
}
}

View file

@ -1,88 +0,0 @@
package eu.siacs.conversations.ui.util;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.reflect.Field;
public class ActionBarUtil {
public static void resetActionBarOnClickListeners(@NonNull View view) {
final View title = findActionBarTitle(view);
final View subtitle = findActionBarSubTitle(view);
if (title != null) {
title.setOnClickListener(null);
}
if (subtitle != null) {
subtitle.setOnClickListener(null);
}
}
public static void setActionBarOnClickListener(@NonNull View view,
@NonNull final View.OnClickListener onClickListener) {
final View title = findActionBarTitle(view);
final View subtitle = findActionBarSubTitle(view);
if (title != null) {
title.setOnClickListener(onClickListener);
}
if (subtitle != null) {
subtitle.setOnClickListener(onClickListener);
}
}
private static @Nullable View findActionBarTitle(@NonNull View root) {
return findActionBarItem(root, "action_bar_title", "mTitleTextView");
}
private static @Nullable
View findActionBarSubTitle(@NonNull View root) {
return findActionBarItem(root, "action_bar_subtitle", "mSubtitleTextView");
}
private static @Nullable View findActionBarItem(@NonNull View root,
@NonNull String resourceName,
@NonNull String toolbarFieldName) {
View result = findViewSupportOrAndroid(root, resourceName);
if (result == null) {
View actionBar = findViewSupportOrAndroid(root, "action_bar");
if (actionBar != null) {
result = reflectiveRead(actionBar, toolbarFieldName);
}
}
if (result == null && root.getClass().getName().endsWith("widget.Toolbar")) {
result = reflectiveRead(root, toolbarFieldName);
}
return result;
}
@SuppressWarnings("ConstantConditions")
private static @Nullable View findViewSupportOrAndroid(@NonNull View root,
@NonNull String resourceName) {
Context context = root.getContext();
View result = null;
if (result == null) {
int supportID = context.getResources().getIdentifier(resourceName, "id", context.getPackageName());
result = root.findViewById(supportID);
}
if (result == null) {
int androidID = context.getResources().getIdentifier(resourceName, "id", "android");
result = root.findViewById(androidID);
}
return result;
}
@SuppressWarnings("unchecked")
private static <T> T reflectiveRead(@NonNull Object object, @NonNull String fieldName) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(object);
} catch (final Exception ex) {
return null;
}
}
}

View file

@ -38,6 +38,9 @@ import android.os.Parcelable;
import com.google.common.base.MoreObjects;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.utils.MimeUtils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
@ -46,9 +49,6 @@ import java.util.Collections;
import java.util.List;
import java.util.UUID;
import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.MimeUtils;
public class Attachment implements Parcelable {
Attachment(Parcel in) {
@ -71,17 +71,18 @@ public class Attachment implements Parcelable {
return 0;
}
public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
@Override
public Attachment createFromParcel(Parcel in) {
return new Attachment(in);
}
public static final Creator<Attachment> CREATOR =
new Creator<Attachment>() {
@Override
public Attachment createFromParcel(Parcel in) {
return new Attachment(in);
}
@Override
public Attachment[] newArray(int size) {
return new Attachment[size];
}
};
@Override
public Attachment[] newArray(int size) {
return new Attachment[size];
}
};
public String getMime() {
return mime;
@ -103,7 +104,10 @@ public class Attachment implements Parcelable {
}
public enum Type {
FILE, IMAGE, LOCATION, RECORDING
FILE,
IMAGE,
LOCATION,
RECORDING
}
private final Uri uri;
@ -125,8 +129,8 @@ public class Attachment implements Parcelable {
this.uuid = UUID.randomUUID();
}
public static boolean canBeSendInband(final List<Attachment> attachments) {
for (Attachment attachment : attachments) {
public static boolean canBeSendInBand(final List<Attachment> attachments) {
for (final Attachment attachment : attachments) {
if (attachment.type != Type.LOCATION) {
return false;
}
@ -135,10 +139,30 @@ public class Attachment implements Parcelable {
}
public static List<Attachment> of(final Context context, Uri uri, Type type) {
final String mime = type == Type.LOCATION ? null : MimeUtils.guessMimeTypeFromUri(context, uri);
final String mime =
type == Type.LOCATION ? null : MimeUtils.guessMimeTypeFromUri(context, uri);
return Collections.singletonList(new Attachment(uri, type, mime));
}
public static Attachment of(final Message message) {
final UUID uuid = UUID.fromString(message.getUuid());
if (message.isGeoUri()) {
return new Attachment(uuid, Uri.EMPTY, Type.LOCATION, null);
}
final String mime = message.getMimeType();
if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
final Message.FileParams fileParams = message.getFileParams();
if (fileParams.width > 0 && fileParams.height > 0) {
return new Attachment(uuid, Uri.EMPTY, Type.FILE, "video/*");
} else if (fileParams.runtime > 0) {
return new Attachment(uuid, Uri.EMPTY, Type.FILE, "audio/*");
} else {
return new Attachment(uuid, Uri.EMPTY, Type.FILE, "application/octet-stream");
}
}
return new Attachment(uuid, Uri.EMPTY, Type.FILE, mime);
}
public static List<Attachment> of(final Context context, List<Uri> uris, final String type) {
final List<Attachment> attachments = new ArrayList<>();
for (final Uri uri : uris) {
@ -146,16 +170,25 @@ public class Attachment implements Parcelable {
continue;
}
final String mime = MimeUtils.guessMimeTypeFromUriAndMime(context, uri, type);
attachments.add(new Attachment(uri, mime != null && isImage(mime) ? Type.IMAGE : Type.FILE, mime));
attachments.add(
new Attachment(
uri, mime != null && isImage(mime) ? Type.IMAGE : Type.FILE, mime));
}
return attachments;
}
public static Attachment of(UUID uuid, final File file, String mime) {
return new Attachment(uuid, Uri.fromFile(file), mime != null && (isImage(mime) || mime.startsWith("video/")) ? Type.IMAGE : Type.FILE, mime);
return new Attachment(
uuid,
Uri.fromFile(file),
mime != null && (isImage(mime) || mime.startsWith("video/"))
? Type.IMAGE
: Type.FILE,
mime);
}
public static List<Attachment> extractAttachments(final Context context, final Intent intent, Type type) {
public static List<Attachment> extractAttachments(
final Context context, final Intent intent, Type type) {
List<Attachment> uris = new ArrayList<>();
if (intent == null) {
return uris;
@ -167,7 +200,8 @@ public class Attachment implements Parcelable {
if (clipData != null) {
for (int i = 0; i < clipData.getItemCount(); ++i) {
final Uri uri = clipData.getItemAt(i).getUri();
final String mime = MimeUtils.guessMimeTypeFromUriAndMime(context, uri, contentType);
final String mime =
MimeUtils.guessMimeTypeFromUriAndMime(context, uri, contentType);
uris.add(new Attachment(uri, type, mime));
}
}
@ -179,13 +213,12 @@ public class Attachment implements Parcelable {
}
public boolean renderThumbnail() {
return type == Type.IMAGE || (type == Type.FILE && mime != null && renderFileThumbnail(mime));
return type == Type.IMAGE
|| (type == Type.FILE && mime != null && renderFileThumbnail(mime));
}
private static boolean renderFileThumbnail(final String mime) {
return mime.startsWith("video/")
|| isImage(mime)
|| "application/pdf".equals(mime);
return mime.startsWith("video/") || isImage(mime) || "application/pdf".equals(mime);
}
public Uri getUri() {

View file

@ -102,14 +102,16 @@ public class ConversationMenuConfigurator {
return;
}
if (conversation.getNextEncryption() != Message.ENCRYPTION_NONE) {
menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
if (next == Message.ENCRYPTION_NONE) {
menuSecure.setIcon(R.drawable.ic_lock_open_outline_24dp);
} else {
menuSecure.setIcon(R.drawable.ic_lock_24dp);
}
pgp.setVisible(Config.supportOpenPgp());
none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
axolotl.setVisible(Config.supportOmemo());
switch (conversation.getNextEncryption()) {
switch (next) {
case Message.ENCRYPTION_PGP:
menuSecure.setTitle(R.string.encrypted_with_openpgp);
pgp.setChecked(true);

View file

@ -12,6 +12,8 @@ import android.view.View;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
@ -200,7 +202,7 @@ public final class MucDetailsContextMenuHelper {
activity.xmppConnectionService.changeRoleInConference(conversation, user.getName(), MucOptions.Role.NONE);
}
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
builder.setTitle(R.string.ban_from_conference);
String jid = user.getRealJid().asBareJid().toString();
SpannableString message = new SpannableString(activity.getString(R.string.removing_from_public_conference, jid));

View file

@ -36,6 +36,8 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@ -72,7 +74,7 @@ public class PresenceSelector {
private static void showPresenceSelectionDialog(final Activity activity, final Contact contact, final String[] resourceArray, final OnFullJidSelected onFullJidSelected) {
final Presences presences = contact.getPresences();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
builder.setTitle(activity.getString(R.string.choose_presence));
Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
final Map<String, String> resourceTypeMap = typeAndName.first;
@ -128,8 +130,8 @@ public class PresenceSelector {
}
}
public static void warnMutualPresenceSubscription(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
public static void warnMutualPresenceSubscription(final Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
builder.setTitle(conversation.getContact().getJid().toString());
builder.setMessage(R.string.without_mutual_presence_updates);
builder.setNegativeButton(R.string.cancel, null);

View file

@ -31,8 +31,15 @@ package eu.siacs.conversations.ui.util;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
import android.view.View;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;
import com.google.android.material.color.MaterialColors;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation;
@ -42,149 +49,90 @@ import eu.siacs.conversations.utils.UIHelper;
public class SendButtonTool {
public static SendButtonAction getAction(final Activity activity, final Conversation c, final String text) {
if (activity == null) {
return SendButtonAction.TEXT;
}
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
final boolean empty = text.length() == 0;
final boolean conference = c.getMode() == Conversation.MODE_MULTI;
if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) {
return SendButtonAction.CANCEL;
} else if (conference && !c.getAccount().httpUploadAvailable()) {
if (empty && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
return SendButtonAction.TEXT;
}
} else {
if (empty) {
if (conference && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));
if (!"none".equals(setting) && UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
return SendButtonAction.SEND_LOCATION;
} else {
if ("recent".equals(setting)) {
setting = preferences.getString(ConversationFragment.RECENTLY_USED_QUICK_ACTION, SendButtonAction.TEXT.toString());
return SendButtonAction.valueOfOrDefault(setting);
} else {
return SendButtonAction.valueOfOrDefault(setting);
}
}
}
} else {
return SendButtonAction.TEXT;
}
}
}
public static SendButtonAction getAction(
final Activity activity, final Conversation c, final String text) {
if (activity == null) {
return SendButtonAction.TEXT;
}
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(activity);
final boolean empty = text.isEmpty();
final boolean conference = c.getMode() == Conversation.MODE_MULTI;
if (c.getCorrectingMessage() != null
&& (empty || text.equals(c.getCorrectingMessage().getBody()))) {
return SendButtonAction.CANCEL;
} else if (conference && !c.getAccount().httpUploadAvailable()) {
if (empty && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
return SendButtonAction.TEXT;
}
} else {
if (empty) {
if (conference && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
String setting =
preferences.getString(
"quick_action",
activity.getResources().getString(R.string.quick_action));
if (!"none".equals(setting)
&& UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
return SendButtonAction.SEND_LOCATION;
} else {
if ("recent".equals(setting)) {
setting =
preferences.getString(
ConversationFragment.RECENTLY_USED_QUICK_ACTION,
SendButtonAction.TEXT.toString());
return SendButtonAction.valueOfOrDefault(setting);
} else {
return SendButtonAction.valueOfOrDefault(setting);
}
}
}
} else {
return SendButtonAction.TEXT;
}
}
}
public static int getSendButtonImageResource(Activity activity, SendButtonAction action, Presence.Status status) {
switch (action) {
case TEXT:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_text_online;
case AWAY:
return R.drawable.ic_send_text_away;
case XA:
case DND:
return R.drawable.ic_send_text_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
}
case RECORD_VIDEO:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_videocam_online;
case AWAY:
return R.drawable.ic_send_videocam_away;
case XA:
case DND:
return R.drawable.ic_send_videocam_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_videocam_offline, R.drawable.ic_send_videocam_offline);
}
case TAKE_PHOTO:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_photo_online;
case AWAY:
return R.drawable.ic_send_photo_away;
case XA:
case DND:
return R.drawable.ic_send_photo_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_photo_offline, R.drawable.ic_send_photo_offline);
}
case RECORD_VOICE:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_voice_online;
case AWAY:
return R.drawable.ic_send_voice_away;
case XA:
case DND:
return R.drawable.ic_send_voice_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_voice_offline, R.drawable.ic_send_voice_offline);
}
case SEND_LOCATION:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_location_online;
case AWAY:
return R.drawable.ic_send_location_away;
case XA:
case DND:
return R.drawable.ic_send_location_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_location_offline, R.drawable.ic_send_location_offline);
}
case CANCEL:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_cancel_online;
case AWAY:
return R.drawable.ic_send_cancel_away;
case XA:
case DND:
return R.drawable.ic_send_cancel_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_cancel_offline, R.drawable.ic_send_cancel_offline);
}
case CHOOSE_PICTURE:
switch (status) {
case CHAT:
case ONLINE:
return R.drawable.ic_send_picture_online;
case AWAY:
return R.drawable.ic_send_picture_away;
case XA:
case DND:
return R.drawable.ic_send_picture_dnd;
default:
return getThemeResource(activity, R.attr.ic_send_picture_offline, R.drawable.ic_send_picture_offline);
}
}
return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
}
private static int getThemeResource(Activity activity, int r_attr_name, int r_drawable_def) {
int[] attrs = {r_attr_name};
TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
int res = ta.getResourceId(0, r_drawable_def);
ta.recycle();
return res;
}
public @DrawableRes static int getSendButtonImageResource(final SendButtonAction action) {
return switch (action) {
case TEXT -> R.drawable.ic_send_24dp;
case TAKE_PHOTO -> R.drawable.ic_camera_alt_24dp;
case SEND_LOCATION -> R.drawable.ic_location_pin_24dp;
case CHOOSE_PICTURE -> R.drawable.ic_image_24dp;
case RECORD_VIDEO -> R.drawable.ic_videocam_24dp;
case RECORD_VOICE -> R.drawable.ic_mic_24dp;
case CANCEL -> R.drawable.ic_cancel_24dp;
};
}
public @ColorInt static int getSendButtonColor(final View view, final Presence.Status status) {
final boolean nightMode =
(view.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
return switch (status) {
case OFFLINE -> MaterialColors.getColor(
view, com.google.android.material.R.attr.colorOnSurface);
case ONLINE, CHAT -> MaterialColors.harmonizeWithPrimary(
view.getContext(),
ContextCompat.getColor(
view.getContext(), nightMode ? R.color.green_200 : R.color.green_800));
case AWAY -> MaterialColors.harmonizeWithPrimary(
view.getContext(),
ContextCompat.getColor(
view.getContext(), nightMode ? R.color.amber_200 : R.color.amber_800));
case XA -> MaterialColors.harmonizeWithPrimary(
view.getContext(),
ContextCompat.getColor(
view.getContext(),
nightMode ? R.color.orange_200 : R.color.orange_800));
case DND -> MaterialColors.harmonizeWithPrimary(
view.getContext(),
ContextCompat.getColor(
view.getContext(), nightMode ? R.color.red_200 : R.color.red_800));
};
}
}

View file

@ -1,59 +0,0 @@
/*
* Copyright (c) 2018, Daniel Gultsch All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package eu.siacs.conversations.ui.util;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
public class StyledAttributes {
public static android.graphics.drawable.Drawable getDrawable(Context context, @AttrRes int id) {
TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
android.graphics.drawable.Drawable drawable = typedArray.getDrawable(0);
typedArray.recycle();
return drawable;
}
public static float getFloat(Context context, @AttrRes int id) {
TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
float value = typedArray.getFloat(0,0f);
typedArray.recycle();
return value;
}
public static @ColorInt int getColor(Context context, @AttrRes int attr) {
TypedArray typedArray = context.obtainStyledAttributes(new int[]{attr});
int color = typedArray.getColor(0,0);
typedArray.recycle();
return color;
}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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.
*/
package eu.siacs.conversations.ui.util;
import static java.util.Collections.max;
import static java.util.Collections.min;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.ActionMenuView;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.appbar.MaterialToolbar;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ToolbarUtils {
private static final Comparator<View> VIEW_TOP_COMPARATOR =
new Comparator<View>() {
@Override
public int compare(View view1, View view2) {
return view1.getTop() - view2.getTop();
}
};
private ToolbarUtils() {
// Private constructor to prevent unwanted construction.
}
public static void resetActionBarOnClickListeners(@NonNull MaterialToolbar view) {
final TextView title = getTitleTextView(view);
final TextView subtitle = getSubtitleTextView(view);
if (title != null) {
title.setOnClickListener(null);
}
if (subtitle != null) {
subtitle.setOnClickListener(null);
}
}
public static void setActionBarOnClickListener(
@NonNull MaterialToolbar view, @NonNull final View.OnClickListener onClickListener) {
final TextView title = getTitleTextView(view);
final TextView subtitle = getSubtitleTextView(view);
if (title != null) {
title.setOnClickListener(onClickListener);
}
if (subtitle != null) {
subtitle.setOnClickListener(onClickListener);
}
}
@Nullable
public static TextView getTitleTextView(@NonNull Toolbar toolbar) {
List<TextView> textViews = getTextViewsWithText(toolbar, toolbar.getTitle());
return textViews.isEmpty() ? null : min(textViews, VIEW_TOP_COMPARATOR);
}
@Nullable
public static TextView getSubtitleTextView(@NonNull Toolbar toolbar) {
List<TextView> textViews = getTextViewsWithText(toolbar, toolbar.getSubtitle());
return textViews.isEmpty() ? null : max(textViews, VIEW_TOP_COMPARATOR);
}
private static List<TextView> getTextViewsWithText(
@NonNull Toolbar toolbar, CharSequence text) {
List<TextView> textViews = new ArrayList<>();
for (int i = 0; i < toolbar.getChildCount(); i++) {
View child = toolbar.getChildAt(i);
if (child instanceof TextView textView) {
if (TextUtils.equals(textView.getText(), text)) {
textViews.add(textView);
}
}
}
return textViews;
}
@Nullable
public static ImageView getLogoImageView(@NonNull Toolbar toolbar) {
return getImageView(toolbar, toolbar.getLogo());
}
@Nullable
private static ImageView getImageView(@NonNull Toolbar toolbar, @Nullable Drawable content) {
if (content == null) {
return null;
}
for (int i = 0; i < toolbar.getChildCount(); i++) {
View child = toolbar.getChildAt(i);
if (child instanceof ImageView imageView) {
Drawable drawable = imageView.getDrawable();
if (drawable != null
&& drawable.getConstantState() != null
&& drawable.getConstantState().equals(content.getConstantState())) {
return imageView;
}
}
}
return null;
}
@Nullable
public static View getSecondaryActionMenuItemView(@NonNull Toolbar toolbar) {
ActionMenuView actionMenuView = getActionMenuView(toolbar);
if (actionMenuView != null) {
// Only return the first child of the ActionMenuView if there is more than one child
if (actionMenuView.getChildCount() > 1) {
return actionMenuView.getChildAt(0);
}
}
return null;
}
@Nullable
public static ActionMenuView getActionMenuView(@NonNull Toolbar toolbar) {
for (int i = 0; i < toolbar.getChildCount(); i++) {
View child = toolbar.getChildAt(i);
if (child instanceof ActionMenuView) {
return (ActionMenuView) child;
}
}
return null;
}
@Nullable
public static ImageButton getNavigationIconButton(@NonNull Toolbar toolbar) {
Drawable navigationIcon = toolbar.getNavigationIcon();
if (navigationIcon == null) {
return null;
}
for (int i = 0; i < toolbar.getChildCount(); i++) {
View child = toolbar.getChildAt(i);
if (child instanceof ImageButton imageButton) {
if (imageButton.getDrawable() == navigationIcon) {
return imageButton;
}
}
}
return null;
}
}

Some files were not shown because too many files have changed in this diff Show more