per conversation custom backgrounds
This commit is contained in:
parent
4453ad71ac
commit
481f5ebfc1
|
@ -70,6 +70,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
@ -80,6 +81,7 @@ import com.google.common.collect.ImmutableList;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -135,11 +137,13 @@ import eu.siacs.conversations.ui.util.ScrollState;
|
|||
import eu.siacs.conversations.ui.util.SendButtonAction;
|
||||
import eu.siacs.conversations.ui.util.SendButtonTool;
|
||||
import eu.siacs.conversations.ui.util.ShareUtil;
|
||||
import eu.siacs.conversations.ui.util.StyledAttributes;
|
||||
import eu.siacs.conversations.ui.util.ViewUtil;
|
||||
import eu.siacs.conversations.ui.widget.EditMessage;
|
||||
import eu.siacs.conversations.ui.widget.HighlighterView;
|
||||
import eu.siacs.conversations.ui.widget.TabLayout;
|
||||
import eu.siacs.conversations.utils.AccountUtils;
|
||||
import eu.siacs.conversations.utils.ChatBackgroundHelper;
|
||||
import eu.siacs.conversations.utils.Compatibility;
|
||||
import eu.siacs.conversations.utils.Emoticons;
|
||||
import eu.siacs.conversations.utils.GeoHelper;
|
||||
|
@ -1321,6 +1325,12 @@ public class ConversationFragment extends XmppFragment
|
|||
} else {
|
||||
this.postponedActivityResult.push(activityResult);
|
||||
}
|
||||
|
||||
ChatBackgroundHelper.onActivityResult(activity, requestCode, resultCode, data, conversation.getUuid());
|
||||
|
||||
if (requestCode == ChatBackgroundHelper.REQUEST_IMPORT_BACKGROUND) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void unblockConversation(final Blockable conversation) {
|
||||
|
@ -1367,6 +1377,7 @@ public class ConversationFragment extends XmppFragment
|
|||
final MenuItem menuOngoingCall = menu.findItem(R.id.action_ongoing_call);
|
||||
final MenuItem menuVideoCall = menu.findItem(R.id.action_video_call);
|
||||
final MenuItem menuTogglePinned = menu.findItem(R.id.action_toggle_pinned);
|
||||
final MenuItem deleteCustomBg = menu.findItem(R.id.action_delete_custom_bg);
|
||||
|
||||
if (conversation != null) {
|
||||
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
||||
|
@ -1417,6 +1428,8 @@ public class ConversationFragment extends XmppFragment
|
|||
} else {
|
||||
menuTogglePinned.setTitle(R.string.add_to_favorites);
|
||||
}
|
||||
|
||||
deleteCustomBg.setVisible(ChatBackgroundHelper.getBgFile(activity, conversation.getUuid()).exists());
|
||||
}
|
||||
|
||||
Fragment secondaryFragment = activity.getFragmentManager().findFragmentById(R.id.secondary_fragment);
|
||||
|
@ -2032,6 +2045,27 @@ public class ConversationFragment extends XmppFragment
|
|||
case R.id.action_throttle:
|
||||
throttleNoisyNoftificationsDialog(conversation);
|
||||
break;
|
||||
case R.id.action_set_custom_bg:
|
||||
if (activity.hasStoragePermission(ChatBackgroundHelper.REQUEST_IMPORT_BACKGROUND)) {
|
||||
ChatBackgroundHelper.openBGPicker(this);
|
||||
}
|
||||
break;
|
||||
case R.id.action_delete_custom_bg:
|
||||
try {
|
||||
File bgfile = ChatBackgroundHelper.getBgFile(activity, conversation.getUuid());
|
||||
if (bgfile.exists()) {
|
||||
bgfile.delete();
|
||||
Toast.makeText(activity, R.string.delete_background_success,Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toast.makeText(activity, R.string.no_background_set,Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
refresh();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(activity, R.string.delete_background_failed,Toast.LENGTH_LONG).show();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
break;
|
||||
case R.id.action_block:
|
||||
case R.id.action_unblock:
|
||||
final Activity activity = getActivity();
|
||||
|
@ -2416,6 +2450,8 @@ public class ConversationFragment extends XmppFragment
|
|||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
ChatBackgroundHelper.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
}
|
||||
if (writeGranted(grantResults, permissions)) {
|
||||
if (activity != null && activity.xmppConnectionService != null) {
|
||||
|
@ -2429,6 +2465,18 @@ public class ConversationFragment extends XmppFragment
|
|||
}
|
||||
}
|
||||
|
||||
private void updateChatBG() {
|
||||
if (activity != null) {
|
||||
Uri uri = ChatBackgroundHelper.getBgUri(activity, conversation.getUuid());
|
||||
if (uri != null) {
|
||||
binding.backgroundImage.setImageURI(uri);
|
||||
binding.backgroundImage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.backgroundImage.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startDownloadable(Message message) {
|
||||
if (!hasPermissions(REQUEST_START_DOWNLOAD, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
this.mPendingDownloadableMessage = message;
|
||||
|
@ -2648,6 +2696,7 @@ public class ConversationFragment extends XmppFragment
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
binding.messagesView.post(this::fireReadEvent);
|
||||
updateChatBG();
|
||||
}
|
||||
|
||||
private void fireReadEvent() {
|
||||
|
@ -2982,6 +3031,8 @@ public class ConversationFragment extends XmppFragment
|
|||
findAndReInitByUuidOrArchive(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
updateChatBG();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3514,6 +3565,7 @@ public class ConversationFragment extends XmppFragment
|
|||
"ConversationFragment.refresh() skipped updated because view binding was null");
|
||||
return;
|
||||
}
|
||||
updateChatBG();
|
||||
if (this.conversation != null
|
||||
&& this.activity != null
|
||||
&& this.activity.xmppConnectionService != null) {
|
||||
|
|
|
@ -6,6 +6,10 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
@ -22,12 +26,19 @@ import android.widget.Toast;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyStoreException;
|
||||
|
@ -48,6 +59,7 @@ 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.ChatBackgroundHelper;
|
||||
import eu.siacs.conversations.utils.GeoHelper;
|
||||
import eu.siacs.conversations.utils.ThemeHelper;
|
||||
import eu.siacs.conversations.utils.TimeFrameUtils;
|
||||
|
@ -362,6 +374,37 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
|
|||
privacyCategory.removePreference(omemoPreference);
|
||||
}
|
||||
}
|
||||
|
||||
final Preference importBackgroundPreference = mSettingsFragment.findPreference("import_background");
|
||||
if (importBackgroundPreference != null) {
|
||||
importBackgroundPreference.setSummary(getString(R.string.pref_chat_background_summary));
|
||||
importBackgroundPreference.setOnPreferenceClickListener(preference -> {
|
||||
if (hasStoragePermission(ChatBackgroundHelper.REQUEST_IMPORT_BACKGROUND)) {
|
||||
ChatBackgroundHelper.openBGPicker(this);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
final Preference deleteBackgroundPreference = mSettingsFragment.findPreference("delete_background");
|
||||
if (deleteBackgroundPreference != null) {
|
||||
deleteBackgroundPreference.setSummary(getString(R.string.pref_delete_background_summary));
|
||||
deleteBackgroundPreference.setOnPreferenceClickListener(preference -> {
|
||||
try {
|
||||
File bgfile = ChatBackgroundHelper.getBgFile(this, null);
|
||||
if (bgfile.exists()) {
|
||||
bgfile.delete();
|
||||
Toast.makeText(this,R.string.delete_background_success,Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toast.makeText(this,R.string.no_background_set,Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this,R.string.delete_background_failed,Toast.LENGTH_LONG).show();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void changeOmemoSettingSummary() {
|
||||
|
@ -588,6 +631,13 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
|
|||
SettingsUtils.applyScreenshotPreventionSetting(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
ChatBackgroundHelper.onActivityResult(this, requestCode, resultCode, data, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(
|
||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
|
@ -597,6 +647,8 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
|
|||
if (requestCode == REQUEST_CREATE_BACKUP) {
|
||||
createBackup();
|
||||
}
|
||||
|
||||
ChatBackgroundHelper.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this,
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
package eu.siacs.conversations.utils;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import org.checkerframework.checker.units.qual.N;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
|
||||
public class ChatBackgroundHelper {
|
||||
public static final int REQUEST_IMPORT_BACKGROUND = 0xbf8704;
|
||||
|
||||
public static void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data, @Nullable String conversationUUID) {
|
||||
if(requestCode == REQUEST_IMPORT_BACKGROUND) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Uri bguri = data.getData();
|
||||
onPickFile(activity, bguri, conversationUUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onRequestPermissionsResult(Activity activity,
|
||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == REQUEST_IMPORT_BACKGROUND) {
|
||||
openBGPicker(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onRequestPermissionsResult(Fragment fragment,
|
||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == REQUEST_IMPORT_BACKGROUND) {
|
||||
openBGPicker(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
public static File getBgFile(Activity activity, @Nullable String conversationUUID) {
|
||||
if (conversationUUID == null) {
|
||||
return new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg.jpg");
|
||||
} else {
|
||||
return new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg_" + conversationUUID + ".jpg");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Uri getBgUri(Activity activity, String conversationUUID) {
|
||||
File chatBgfileUri = new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg_" + conversationUUID + ".jpg");
|
||||
File bgfileUri = new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg.jpg");
|
||||
if (chatBgfileUri.exists()) {
|
||||
return Uri.fromFile(chatBgfileUri);
|
||||
} else if (bgfileUri.exists()) {
|
||||
return Uri.fromFile(bgfileUri);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void openBGPicker(Activity activity) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("image/*");
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
|
||||
activity.startActivityForResult(Intent.createChooser(intent, "Select image"), REQUEST_IMPORT_BACKGROUND);
|
||||
}
|
||||
|
||||
public static void openBGPicker(Fragment fragment) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("image/*");
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
|
||||
fragment.startActivityForResult(Intent.createChooser(intent, "Select image"), REQUEST_IMPORT_BACKGROUND);
|
||||
}
|
||||
|
||||
private static void onPickFile(Activity activity, Uri uri, @Nullable String conversationUUID) {
|
||||
if (uri != null) {
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
try {
|
||||
File bgfolder = new File(activity.getFilesDir() + File.separator + "backgrounds");
|
||||
File bgfile;
|
||||
|
||||
if (conversationUUID != null) {
|
||||
bgfile = new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg_" + conversationUUID + ".jpg");
|
||||
} else {
|
||||
bgfile = new File(activity.getFilesDir() + File.separator + "backgrounds" + File.separator + "bg.jpg");
|
||||
}
|
||||
//create output directory if it doesn't exist
|
||||
if (!bgfolder.exists()) {
|
||||
bgfolder.mkdirs();
|
||||
}
|
||||
|
||||
in = activity.getContentResolver().openInputStream(uri);
|
||||
out = new FileOutputStream(bgfile);
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
in.close();
|
||||
in = null;
|
||||
// write the output file
|
||||
out.flush();
|
||||
out.close();
|
||||
out = null;
|
||||
compressImage(activity, bgfile, uri, 0);
|
||||
Toast.makeText(activity, R.string.custom_background_set,Toast.LENGTH_LONG).show();
|
||||
} catch (IOException exception) {
|
||||
Toast.makeText(activity,R.string.create_background_failed,Toast.LENGTH_LONG).show();
|
||||
Log.d(Config.LOGTAG, "Could not create background" + exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void compressImage(Activity activity, File f, Uri image, int sampleSize) throws IOException {
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
int IMAGE_QUALITY = 65;
|
||||
int ImageSize = (int) (0.08 * 1024 * 1024);
|
||||
try {
|
||||
if (!f.exists() && !f.createNewFile()) {
|
||||
throw new IOException(String.valueOf(R.string.error_unable_to_create_temporary_file));
|
||||
}
|
||||
is = activity.getContentResolver().openInputStream(image);
|
||||
if (is == null) {
|
||||
throw new IOException(String.valueOf(R.string.error_not_an_image_file));
|
||||
}
|
||||
final Bitmap originalBitmap;
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
final int inSampleSize = (int) Math.pow(2, sampleSize);
|
||||
Log.d(Config.LOGTAG, "reading bitmap with sample size " + inSampleSize);
|
||||
options.inSampleSize = inSampleSize;
|
||||
originalBitmap = BitmapFactory.decodeStream(is, null, options);
|
||||
is.close();
|
||||
if (originalBitmap == null) {
|
||||
throw new IOException("Source file was not an image");
|
||||
}
|
||||
if (!"image/jpeg".equals(options.outMimeType) && hasAlpha(originalBitmap)) {
|
||||
originalBitmap.recycle();
|
||||
throw new IOException("Source file had alpha channel");
|
||||
}
|
||||
int size;
|
||||
int resolution = 1920;
|
||||
if (resolution == 0) {
|
||||
int height = originalBitmap.getHeight();
|
||||
int width = originalBitmap.getWidth();
|
||||
size = height > width ? height : width;
|
||||
} else {
|
||||
size = resolution;
|
||||
}
|
||||
Bitmap scaledBitmap = resize(originalBitmap, size);
|
||||
final int rotation = getRotation(activity, image);
|
||||
scaledBitmap = rotate(scaledBitmap, rotation);
|
||||
boolean targetSizeReached = false;
|
||||
int quality = IMAGE_QUALITY;
|
||||
while (!targetSizeReached) {
|
||||
os = new FileOutputStream(f);
|
||||
boolean success = scaledBitmap.compress(Config.IMAGE_FORMAT, quality, os);
|
||||
if (!success) {
|
||||
throw new IOException(String.valueOf(R.string.error_compressing_image));
|
||||
}
|
||||
os.flush();
|
||||
targetSizeReached = (f.length() <= ImageSize && ImageSize != 0) || quality <= 50;
|
||||
quality -= 5;
|
||||
}
|
||||
scaledBitmap.recycle();
|
||||
} catch (final FileNotFoundException e) {
|
||||
cleanup(f);
|
||||
throw new IOException(String.valueOf(R.string.error_file_not_found));
|
||||
} catch (final IOException e) {
|
||||
cleanup(f);
|
||||
throw new IOException(String.valueOf(R.string.error_io_exception));
|
||||
} catch (SecurityException e) {
|
||||
cleanup(f);
|
||||
throw new IOException(String.valueOf(R.string.error_security_exception_during_image_copy));
|
||||
} catch (final OutOfMemoryError e) {
|
||||
++sampleSize;
|
||||
if (sampleSize <= 3) {
|
||||
compressImage(activity, f, image, sampleSize);
|
||||
} else {
|
||||
throw new IOException(String.valueOf(R.string.error_out_of_memory));
|
||||
}
|
||||
} finally {
|
||||
close(os);
|
||||
close(is);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getRotation(Activity activity, final Uri image) {
|
||||
try (final InputStream is = activity.getContentResolver().openInputStream(image)) {
|
||||
return is == null ? 0 : getRotation(is);
|
||||
} catch (final Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getRotation(final InputStream inputStream) throws IOException {
|
||||
final ExifInterface exif = new ExifInterface(inputStream);
|
||||
final int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
return 180;
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
return 90;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap rotate(final Bitmap bitmap, final int degree) {
|
||||
if (degree == 0) {
|
||||
return bitmap;
|
||||
}
|
||||
final int w = bitmap.getWidth();
|
||||
final int h = bitmap.getHeight();
|
||||
final Matrix matrix = new Matrix();
|
||||
matrix.postRotate(degree);
|
||||
final Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
|
||||
if (!bitmap.isRecycled()) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void close(final Closeable stream) {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
Log.d(Config.LOGTAG, "unable to close stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cleanup(final File file) {
|
||||
try {
|
||||
file.delete();
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap resize(final Bitmap originalBitmap, int size) throws IOException {
|
||||
int w = originalBitmap.getWidth();
|
||||
int h = originalBitmap.getHeight();
|
||||
if (w <= 0 || h <= 0) {
|
||||
throw new IOException("Decoded bitmap reported bounds smaller 0");
|
||||
} else if (Math.max(w, h) > size) {
|
||||
int scalledW;
|
||||
int scalledH;
|
||||
if (w <= h) {
|
||||
scalledW = Math.max((int) (w / ((double) h / size)), 1);
|
||||
scalledH = size;
|
||||
} else {
|
||||
scalledW = size;
|
||||
scalledH = Math.max((int) (h / ((double) w / size)), 1);
|
||||
}
|
||||
final Bitmap result = Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true);
|
||||
if (!originalBitmap.isRecycled()) {
|
||||
originalBitmap.recycle();
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return originalBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasAlpha(final Bitmap bitmap) {
|
||||
final int w = bitmap.getWidth();
|
||||
final int h = bitmap.getHeight();
|
||||
final int yStep = Math.max(1, w / 100);
|
||||
final int xStep = Math.max(1, h / 100);
|
||||
for (int x = 0; x < w; x += xStep) {
|
||||
for (int y = 0; y < h; y += yStep) {
|
||||
if (Color.alpha(bitmap.getPixel(x, y)) < 255) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,13 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?attr/color_background_secondary">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/background_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="@color/grey700_25"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<eu.siacs.conversations.ui.widget.TabLayout
|
||||
android:visibility="gone"
|
||||
android:id="@+id/tab_layout"
|
||||
|
@ -25,8 +32,7 @@
|
|||
android:id="@+id/conversation_view_pager"
|
||||
android:layout_below="@id/tab_layout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="?attr/color_background_secondary">
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
|
@ -39,7 +45,6 @@
|
|||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?attr/color_background_secondary"
|
||||
android:divider="@null"
|
||||
android:listSelector="@android:color/transparent"
|
||||
android:stackFromBottom="true"
|
||||
|
@ -284,7 +289,6 @@
|
|||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?attr/color_background_secondary"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"></ListView>
|
||||
|
||||
|
|
|
@ -147,6 +147,18 @@
|
|||
android:orderInCategory="75"
|
||||
android:title="@string/refresh_feature_discovery"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_set_custom_bg"
|
||||
android:orderInCategory="76"
|
||||
android:title="@string/custom_background"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_delete_custom_bg"
|
||||
android:orderInCategory="77"
|
||||
android:title="@string/delete_background"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<color name="grey500">#ff9e9e9e</color>
|
||||
<color name="grey700">#ff616161</color>
|
||||
<color name="grey700_40">#66616161</color>
|
||||
<color name="grey700_25">#40616161</color>
|
||||
<color name="grey800">#ff424242</color>
|
||||
<color name="grey900">#ff282828</color>
|
||||
<color name="red500">#fff44336</color>
|
||||
|
|
|
@ -1090,4 +1090,13 @@
|
|||
<string name="retract_message_alert_title">Do you really want to retract this message?</string>
|
||||
<string name="chats">Chats</string>
|
||||
<string name="accounts">Accounts</string>
|
||||
<string name="custom_background">Custom background</string>
|
||||
<string name="pref_chat_background_summary">Choose an own image file as chat background.</string>
|
||||
<string name="delete_background">Remove chat background</string>
|
||||
<string name="pref_delete_background_summary">Remove your custom background image from the chat</string>
|
||||
<string name="create_background_failed">Failed to create background</string>
|
||||
<string name="custom_background_set">Custom background set</string>
|
||||
<string name="delete_background_failed">Couldn\'t remove background image</string>
|
||||
<string name="delete_background_success">Background image removed</string>
|
||||
<string name="no_background_set">No custom background set</string>
|
||||
</resources>
|
||||
|
|
|
@ -232,6 +232,14 @@
|
|||
android:key="font_size"
|
||||
android:summary="@string/pref_font_size_summary"
|
||||
android:title="@string/pref_font_size" />
|
||||
<Preference
|
||||
android:key="import_background"
|
||||
android:summary="@string/pref_chat_background_summary"
|
||||
android:title="@string/custom_background" />
|
||||
<Preference
|
||||
android:key="delete_background"
|
||||
android:summary="@string/pref_delete_background_summary"
|
||||
android:title="@string/delete_background" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="backup_category"
|
||||
|
|
Loading…
Reference in a new issue