mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Implement UI for setting profile pictures
This commit is contained in:
committed by
Torsten Grote
parent
f819930570
commit
43c6ae4258
@@ -6,4 +6,7 @@ package org.briarproject.bramble.api;
|
||||
public interface FeatureFlags {
|
||||
|
||||
boolean shouldEnableImageAttachments();
|
||||
|
||||
boolean shouldEnableProfilePictures();
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,17 @@ public class BrambleCoreIntegrationTestModule {
|
||||
|
||||
@Provides
|
||||
FeatureFlags provideFeatureFlags() {
|
||||
return () -> true;
|
||||
return new FeatureFlags() {
|
||||
|
||||
@Override
|
||||
public boolean shouldEnableImageAttachments() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldEnableProfilePictures() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.briarproject.briar.android.forum.ForumModule;
|
||||
import org.briarproject.briar.android.keyagreement.ContactExchangeModule;
|
||||
import org.briarproject.briar.android.login.LoginModule;
|
||||
import org.briarproject.briar.android.navdrawer.NavDrawerModule;
|
||||
import org.briarproject.briar.android.settings.SettingsModule;
|
||||
import org.briarproject.briar.android.privategroup.list.GroupListModule;
|
||||
import org.briarproject.briar.android.reporting.DevReportModule;
|
||||
import org.briarproject.briar.android.test.TestAvatarCreatorImpl;
|
||||
@@ -70,6 +71,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||
LoginModule.class,
|
||||
NavDrawerModule.class,
|
||||
ViewModelModule.class,
|
||||
SettingsModule.class,
|
||||
DevReportModule.class,
|
||||
ContactListModule.class,
|
||||
// below need to be within same scope as ViewModelProvider.Factory
|
||||
@@ -255,6 +257,17 @@ public class AppModule {
|
||||
|
||||
@Provides
|
||||
FeatureFlags provideFeatureFlags() {
|
||||
return () -> IS_DEBUG_BUILD;
|
||||
return new FeatureFlags() {
|
||||
|
||||
@Override
|
||||
public boolean shouldEnableImageAttachments() {
|
||||
return IS_DEBUG_BUILD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldEnableProfilePictures() {
|
||||
return IS_DEBUG_BUILD;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ import org.briarproject.briar.android.privategroup.reveal.RevealContactsFragment
|
||||
import org.briarproject.briar.android.reporting.CrashFragment;
|
||||
import org.briarproject.briar.android.reporting.CrashReportActivity;
|
||||
import org.briarproject.briar.android.reporting.ReportFormFragment;
|
||||
import org.briarproject.briar.android.settings.ConfirmAvatarDialogFragment;
|
||||
import org.briarproject.briar.android.settings.SettingsActivity;
|
||||
import org.briarproject.briar.android.settings.SettingsFragment;
|
||||
import org.briarproject.briar.android.sharing.BlogInvitationActivity;
|
||||
@@ -239,4 +240,6 @@ public interface ActivityComponent {
|
||||
|
||||
void inject(CrashFragment crashFragment);
|
||||
|
||||
void inject(ConfirmAvatarDialogFragment fragment);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,5 +16,6 @@ public interface RequestCodes {
|
||||
int REQUEST_KEYGUARD_UNLOCK = 12;
|
||||
int REQUEST_ATTACH_IMAGE = 13;
|
||||
int REQUEST_SAVE_ATTACHMENT = 14;
|
||||
int REQUEST_AVATAR_IMAGE = 15;
|
||||
|
||||
}
|
||||
|
||||
@@ -105,10 +105,10 @@ class AttachmentCreationTask {
|
||||
if (is == null) throw new IOException();
|
||||
is = imageCompressor
|
||||
.compressImage(is, contentType);
|
||||
contentType = "image/jpeg";
|
||||
long timestamp = System.currentTimeMillis();
|
||||
AttachmentHeader h = messagingManager
|
||||
.addLocalAttachment(groupId, timestamp, contentType, is);
|
||||
.addLocalAttachment(groupId, timestamp,
|
||||
ImageCompressor.MIME_TYPE, is);
|
||||
tryToClose(is, LOG, WARNING);
|
||||
logDuration(LOG, "Storing attachment", start);
|
||||
return h;
|
||||
|
||||
@@ -8,10 +8,15 @@ import java.io.InputStream;
|
||||
|
||||
public interface ImageCompressor {
|
||||
|
||||
/**
|
||||
* The MIME type of compressed images
|
||||
*/
|
||||
String MIME_TYPE = "image/jpeg";
|
||||
|
||||
/**
|
||||
* Load an image from {@code is}, compress it and return an InputStream
|
||||
* from which the resulting image can be read. The image will be compressed
|
||||
* such that it fits into a message.
|
||||
* as a JPEG image such that it fits into a message.
|
||||
*
|
||||
* @param is the stream to read the source image from
|
||||
* @param contentType the mimetype of the source image such as "image/jpeg"
|
||||
@@ -23,8 +28,8 @@ public interface ImageCompressor {
|
||||
|
||||
/**
|
||||
* Compress an image and return an InputStream from which the resulting
|
||||
* image can be read. The image will be compressed such that it fits into
|
||||
* a message.
|
||||
* image can be read. The image will be compressed as a JPEG image such that
|
||||
* it fits into a message.
|
||||
*
|
||||
* @param bitmap the source image
|
||||
* @return a stream from which the resulting image can be read
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.briarproject.briar.android.settings;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.BaseActivity;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class ConfirmAvatarDialogFragment extends DialogFragment {
|
||||
|
||||
final static String TAG = ConfirmAvatarDialogFragment.class.getName();
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
private SettingsViewModel settingsViewModel;
|
||||
|
||||
private static final String ARG_URI = "uri";
|
||||
private Uri uri;
|
||||
|
||||
static ConfirmAvatarDialogFragment newInstance(Uri uri) {
|
||||
ConfirmAvatarDialogFragment f = new ConfirmAvatarDialogFragment();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_URI, uri.toString());
|
||||
f.setArguments(args);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context ctx) {
|
||||
super.onAttach(ctx);
|
||||
((BaseActivity) requireActivity()).getActivityComponent().inject(this);
|
||||
}
|
||||
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = requireArguments();
|
||||
String argUri = requireNonNull(args.getString(ARG_URI));
|
||||
uri = Uri.parse(argUri);
|
||||
|
||||
FragmentActivity activity = requireActivity();
|
||||
|
||||
ViewModelProvider provider =
|
||||
new ViewModelProvider(activity, viewModelFactory);
|
||||
settingsViewModel = provider.get(SettingsViewModel.class);
|
||||
settingsViewModel.onCreate();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
|
||||
LayoutInflater factory = LayoutInflater.from(getContext());
|
||||
final View view =
|
||||
factory.inflate(R.layout.fragment_confirm_avatar_dialog, null);
|
||||
builder.setView(view);
|
||||
|
||||
builder.setTitle(R.string.dialog_confirm_profile_picture_title)
|
||||
.setMessage(R.string.dialog_confirm_profile_picture_question);
|
||||
builder.setNegativeButton(R.string.cancel, null);
|
||||
builder.setPositiveButton(R.string.dialog_confirm_profile_picture_set,
|
||||
(dialog, id) -> {
|
||||
settingsViewModel.setAvatar(uri);
|
||||
});
|
||||
|
||||
ImageView imageView = view.findViewById(R.id.image);
|
||||
imageView.setImageResource(R.drawable.contact_connected);
|
||||
imageView.setImageURI(uri);
|
||||
|
||||
settingsViewModel.getOwnIdentityInfo().observe(activity, us -> {
|
||||
TextView textViewUserName = view.findViewById(R.id.username);
|
||||
textViewUserName.setText(us.getLocalAuthor().getName());
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.briar.android.settings;
|
||||
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.api.identity.AuthorInfo;
|
||||
|
||||
@NotNullByDefault
|
||||
class OwnIdentityInfo {
|
||||
|
||||
private final LocalAuthor localAuthor;
|
||||
private final AuthorInfo authorInfo;
|
||||
|
||||
OwnIdentityInfo(LocalAuthor localAuthor, AuthorInfo authorInfo) {
|
||||
this.localAuthor = localAuthor;
|
||||
this.authorInfo = authorInfo;
|
||||
}
|
||||
|
||||
LocalAuthor getLocalAuthor() {
|
||||
return localAuthor;
|
||||
}
|
||||
|
||||
AuthorInfo getAuthorInfo() {
|
||||
return authorInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,37 @@
|
||||
package org.briarproject.briar.android.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.bramble.api.FeatureFlags;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
import org.briarproject.briar.android.view.AuthorView;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_AVATAR_IMAGE;
|
||||
|
||||
public class SettingsActivity extends BriarActivity {
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
private SettingsViewModel settingsViewModel;
|
||||
|
||||
@Inject
|
||||
FeatureFlags featureFlags;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
@@ -22,6 +43,32 @@ public class SettingsActivity extends BriarActivity {
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_settings);
|
||||
|
||||
if (featureFlags.shouldEnableProfilePictures()) {
|
||||
ViewModelProvider provider =
|
||||
new ViewModelProvider(this, viewModelFactory);
|
||||
settingsViewModel = provider.get(SettingsViewModel.class);
|
||||
settingsViewModel.onCreate();
|
||||
|
||||
settingsViewModel.getOwnIdentityInfo().observe(this, us -> {
|
||||
TextView textViewUserName = findViewById(R.id.username);
|
||||
textViewUserName.setText(us.getLocalAuthor().getName());
|
||||
|
||||
CircleImageView imageViewAvatar =
|
||||
findViewById(R.id.avatarImage);
|
||||
AuthorView
|
||||
.setAvatar(imageViewAvatar, us.getLocalAuthor().getId(),
|
||||
us.getAuthorInfo());
|
||||
});
|
||||
|
||||
View avatarGroup = findViewById(R.id.avatarGroup);
|
||||
avatarGroup.setOnClickListener(e -> {
|
||||
selectAvatarImage();
|
||||
});
|
||||
} else {
|
||||
View view = findViewById(R.id.avatarGroup);
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -37,4 +84,31 @@ public class SettingsActivity extends BriarActivity {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void selectAvatarImage() {
|
||||
Intent intent = UiUtils.createSelectImageIntent(false);
|
||||
startActivityForResult(intent, REQUEST_AVATAR_IMAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int request, int result,
|
||||
@Nullable Intent data) {
|
||||
super.onActivityResult(request, result, data);
|
||||
|
||||
if (request == REQUEST_AVATAR_IMAGE && result == RESULT_OK) {
|
||||
onAvatarImageReceived(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void onAvatarImageReceived(@Nullable Intent resultData) {
|
||||
if (resultData == null) return;
|
||||
Uri uri = resultData.getData();
|
||||
if (uri == null) return;
|
||||
|
||||
ConfirmAvatarDialogFragment dialog =
|
||||
ConfirmAvatarDialogFragment.newInstance(uri);
|
||||
dialog.show(getSupportFragmentManager(),
|
||||
ConfirmAvatarDialogFragment.TAG);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.briarproject.briar.android.settings;
|
||||
|
||||
import org.briarproject.briar.android.viewmodel.ViewModelKey;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoMap;
|
||||
|
||||
@Module
|
||||
public abstract class SettingsModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(SettingsViewModel.class)
|
||||
abstract ViewModel bindSettingsViewModel(
|
||||
SettingsViewModel settingsViewModel);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.briarproject.briar.android.settings;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.util.LogUtils;
|
||||
import org.briarproject.briar.android.attachment.ImageCompressor;
|
||||
import org.briarproject.briar.api.avatar.AvatarManager;
|
||||
import org.briarproject.briar.api.identity.AuthorInfo;
|
||||
import org.briarproject.briar.api.identity.AuthorManager;
|
||||
import org.jsoup.UnsupportedMimeTypeException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageContentTypes;
|
||||
|
||||
@NotNullByDefault
|
||||
public class SettingsViewModel extends AndroidViewModel {
|
||||
|
||||
private final static Logger LOG =
|
||||
getLogger(SettingsViewModel.class.getName());
|
||||
|
||||
private final IdentityManager identityManager;
|
||||
private final AvatarManager avatarManager;
|
||||
private final AuthorManager authorManager;
|
||||
private final ImageCompressor imageCompressor;
|
||||
@DatabaseExecutor
|
||||
private final Executor dbExecutor;
|
||||
|
||||
private final MutableLiveData<OwnIdentityInfo> ownIdentityInfo =
|
||||
new MutableLiveData<>();
|
||||
|
||||
@Inject
|
||||
SettingsViewModel(Application application,
|
||||
IdentityManager identityManager,
|
||||
AvatarManager avatarManager,
|
||||
AuthorManager authorManager,
|
||||
ImageCompressor imageCompressor,
|
||||
@DatabaseExecutor Executor dbExecutor) {
|
||||
super(application);
|
||||
this.identityManager = identityManager;
|
||||
this.imageCompressor = imageCompressor;
|
||||
this.avatarManager = avatarManager;
|
||||
this.authorManager = authorManager;
|
||||
this.dbExecutor = dbExecutor;
|
||||
}
|
||||
|
||||
void onCreate() {
|
||||
if (ownIdentityInfo.getValue() == null) loadOwnIdentityInfo();
|
||||
}
|
||||
|
||||
LiveData<OwnIdentityInfo> getOwnIdentityInfo() {
|
||||
return ownIdentityInfo;
|
||||
}
|
||||
|
||||
private void loadOwnIdentityInfo() {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor();
|
||||
AuthorInfo authorInfo = authorManager.getMyAuthorInfo();
|
||||
ownIdentityInfo
|
||||
.postValue(
|
||||
new OwnIdentityInfo(localAuthor, authorInfo));
|
||||
} catch (DbException e) {
|
||||
LogUtils.logException(LOG, Level.WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setAvatar(Uri uri) {
|
||||
dbExecutor.execute(() -> {
|
||||
try {
|
||||
trySetAvatar(uri);
|
||||
} catch (IOException | DbException e) {
|
||||
LogUtils.logException(LOG, Level.WARNING, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void trySetAvatar(Uri uri) throws IOException, DbException {
|
||||
ContentResolver contentResolver =
|
||||
getApplication().getContentResolver();
|
||||
String contentType = contentResolver.getType(uri);
|
||||
if (contentType == null) throw new IOException("null content type");
|
||||
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
|
||||
String uriString = uri.toString();
|
||||
throw new UnsupportedMimeTypeException("", contentType, uriString);
|
||||
}
|
||||
InputStream is = contentResolver.openInputStream(uri);
|
||||
if (is == null) throw new IOException(
|
||||
"ContentResolver returned null when opening InputStream");
|
||||
is = imageCompressor
|
||||
.compressImage(is, contentType);
|
||||
avatarManager.addAvatar(ImageCompressor.MIME_TYPE, is);
|
||||
loadOwnIdentityInfo();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,7 +57,12 @@ import androidx.lifecycle.Observer;
|
||||
|
||||
import static android.content.Context.KEYGUARD_SERVICE;
|
||||
import static android.content.Context.POWER_SERVICE;
|
||||
import static android.content.Intent.ACTION_GET_CONTENT;
|
||||
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
|
||||
import static android.content.Intent.CATEGORY_DEFAULT;
|
||||
import static android.content.Intent.CATEGORY_OPENABLE;
|
||||
import static android.content.Intent.EXTRA_ALLOW_MULTIPLE;
|
||||
import static android.content.Intent.EXTRA_MIME_TYPES;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.os.Build.MANUFACTURER;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
@@ -89,6 +94,7 @@ import static androidx.core.graphics.drawable.DrawableCompat.setTint;
|
||||
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_RTL;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageContentTypes;
|
||||
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME;
|
||||
@@ -250,6 +256,18 @@ public class UiUtils {
|
||||
};
|
||||
}
|
||||
|
||||
public static Intent createSelectImageIntent(boolean allowMultiple) {
|
||||
Intent intent = new Intent(SDK_INT >= 19 ?
|
||||
ACTION_OPEN_DOCUMENT : ACTION_GET_CONTENT);
|
||||
intent.setType("image/*");
|
||||
intent.addCategory(CATEGORY_OPENABLE);
|
||||
if (SDK_INT >= 19)
|
||||
intent.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||
if (allowMultiple && SDK_INT >= 18)
|
||||
intent.putExtra(EXTRA_ALLOW_MULTIPLE, true);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static void showOnboardingDialog(Context ctx, String text) {
|
||||
new AlertDialog.Builder(ctx, R.style.OnboardingDialogTheme)
|
||||
.setMessage(text)
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.attachment.AttachmentItemResult;
|
||||
import org.briarproject.briar.android.attachment.AttachmentManager;
|
||||
import org.briarproject.briar.android.attachment.AttachmentResult;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -29,18 +30,12 @@ import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
||||
|
||||
import static android.content.Intent.ACTION_GET_CONTENT;
|
||||
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
|
||||
import static android.content.Intent.CATEGORY_OPENABLE;
|
||||
import static android.content.Intent.EXTRA_ALLOW_MULTIPLE;
|
||||
import static android.content.Intent.EXTRA_MIME_TYPES;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.view.View.GONE;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static androidx.core.content.ContextCompat.getColor;
|
||||
import static androidx.customview.view.AbsSavedState.EMPTY_STATE;
|
||||
import static androidx.lifecycle.Lifecycle.State.DESTROYED;
|
||||
import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageContentTypes;
|
||||
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
||||
|
||||
@@ -127,14 +122,7 @@ public class TextAttachmentController extends TextSendController
|
||||
}
|
||||
|
||||
private Intent getAttachFileIntent() {
|
||||
Intent intent = new Intent(SDK_INT >= 19 ?
|
||||
ACTION_OPEN_DOCUMENT : ACTION_GET_CONTENT);
|
||||
intent.setType("image/*");
|
||||
intent.addCategory(CATEGORY_OPENABLE);
|
||||
if (SDK_INT >= 19)
|
||||
intent.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||
if (SDK_INT >= 18) intent.putExtra(EXTRA_ALLOW_MULTIPLE, true);
|
||||
return intent;
|
||||
return UiUtils.createSelectImageIntent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment"
|
||||
android:name="org.briarproject.briar.android.settings.SettingsFragment"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment"
|
||||
android:name="org.briarproject.briar.android.settings.SettingsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/avatarGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_scrollFlags="scroll">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/avatarImage"
|
||||
style="@style/BriarAvatar"
|
||||
android:layout_width="@dimen/listitem_picture_size"
|
||||
android:layout_height="@dimen/listitem_picture_size"
|
||||
android:layout_gravity="bottom|left|start"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:paddingStart="@dimen/margin_medium"
|
||||
android:paddingEnd="@dimen/margin_medium"
|
||||
android:textColor="@color/briar_text_primary_inverse"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/avatarExplanation"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatarImage"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="username" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/avatarExplanation"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:paddingStart="@dimen/margin_medium"
|
||||
android:paddingEnd="@dimen/margin_medium"
|
||||
android:text="@string/change_profile_picture"
|
||||
android:textColor="@color/briar_text_secondary_inverse"
|
||||
android:textSize="@dimen/text_size_small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/avatarImage"
|
||||
app:layout_constraintTop_toBottomOf="@+id/username"
|
||||
tools:text="Change your profile picture" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="?dialogPreferredPadding">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/image"
|
||||
style="@style/BriarAvatar"
|
||||
android:layout_width="@dimen/listitem_picture_size"
|
||||
android:layout_height="@dimen/listitem_picture_size"
|
||||
android:layout_gravity="bottom|left|start"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:layout_marginLeft="@dimen/margin_medium"
|
||||
android:gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/image"
|
||||
app:layout_constraintStart_toEndOf="@+id/image"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
tools:text="username" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/remark"
|
||||
android:layout_marginTop="@dimen/listitem_vertical_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_confirm_profile_picture_remark"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/image" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout >
|
||||
@@ -453,6 +453,13 @@
|
||||
<string name="blogs_rss_feeds_manage_empty_state">No RSS feeds to show\n\nTap the + icon to import a feed</string>
|
||||
<string name="blogs_rss_feeds_manage_error">There was a problem loading your feeds. Please try again later.</string>
|
||||
|
||||
<!-- Settings Profile Picture -->
|
||||
<string name="change_profile_picture">Tap to change your profile picture</string>
|
||||
<string name="dialog_confirm_profile_picture_title">Please confirm</string>
|
||||
<string name="dialog_confirm_profile_picture_question">Do you want to use this image as your profile picture?</string>
|
||||
<string name="dialog_confirm_profile_picture_remark">Only your contacts can see your profile image</string>
|
||||
<string name="dialog_confirm_profile_picture_set">Set picture</string>
|
||||
|
||||
<!-- Settings Display -->
|
||||
<string name="pref_language_title">Language & region</string>
|
||||
<string name="pref_language_changed">This setting will take effect when you restart Briar. Please sign out and restart Briar.</string>
|
||||
|
||||
@@ -88,5 +88,8 @@ internal class HeadlessModule(private val appDir: File) {
|
||||
internal fun provideObjectMapper() = ObjectMapper()
|
||||
|
||||
@Provides
|
||||
internal fun provideFeatureFlags() = FeatureFlags { false }
|
||||
internal fun provideFeatureFlags() = object : FeatureFlags {
|
||||
override fun shouldEnableImageAttachments() = false
|
||||
override fun shouldEnableProfilePictures() = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,10 @@ internal class HeadlessTestModule(private val appDir: File) {
|
||||
internal fun provideObjectMapper() = ObjectMapper()
|
||||
|
||||
@Provides
|
||||
internal fun provideFeatureFlags() = FeatureFlags { false }
|
||||
internal fun provideFeatureFlags() = object : FeatureFlags {
|
||||
override fun shouldEnableImageAttachments() = false
|
||||
override fun shouldEnableProfilePictures() = false
|
||||
}
|
||||
|
||||
@Provides
|
||||
internal fun provideTestAvatarCreator() = TestAvatarCreator { null }
|
||||
|
||||
Reference in New Issue
Block a user