Skip to content

Commit a2d66c1

Browse files
authored
Merge pull request #118 from Arctosoft/develop
Develop
2 parents 8cf5b61 + 0ca9e66 commit a2d66c1

21 files changed

+292
-40
lines changed

ENCRYPTION.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ The following filename suffixes are used:
2020
- `-n.valv` for note files
2121
- `-t.valv` for thumbnail files
2222

23-
The number represents the file structure version (for future expansion/changes).
24-
2523
Filenames are generated randomly and are `32 chars + SUFFIX_LENGTH` long.
2624
Every media file has a corresponding thumbnail with the same name. For example, an image file named
2725

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ android {
1111
applicationId = "se.arctosoft.vault"
1212
minSdk = 28
1313
targetSdk = 35
14-
versionCode = 34
15-
versionName = "2.1.1"
14+
versionCode = 35
15+
versionName = "2.2.0"
1616

1717
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
1818
}

app/src/main/java/se/arctosoft/vault/DirectoryAllFragment.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package se.arctosoft.vault;
22

33
import android.content.Context;
4+
import android.content.Intent;
45
import android.net.Uri;
56
import android.os.Bundle;
67
import android.util.Log;
@@ -13,11 +14,11 @@
1314
import androidx.fragment.app.FragmentManager;
1415

1516
import java.util.ArrayList;
16-
import java.util.LinkedList;
1717
import java.util.List;
1818

1919
import se.arctosoft.vault.data.GalleryFile;
2020
import se.arctosoft.vault.data.Password;
21+
import se.arctosoft.vault.data.UniqueLinkedList;
2122
import se.arctosoft.vault.utils.FileStuff;
2223
import se.arctosoft.vault.utils.Settings;
2324

@@ -48,6 +49,9 @@ public void handleOnBackPressed() {
4849
FragmentActivity activity = requireActivity();
4950
Password.lock(activity);
5051
activity.finish();
52+
if (!settings.exitOnLock()) {
53+
startActivity(new Intent(context, MainActivity.class));
54+
}
5155
}
5256
}
5357
};
@@ -122,7 +126,7 @@ private void findAllFiles() {
122126
activity.runOnUiThread(this::setLoadingAllWithProgress);
123127

124128
List<GalleryFile> folders = new ArrayList<>();
125-
List<GalleryFile> files = new LinkedList<>();
129+
List<GalleryFile> files = new UniqueLinkedList<>();
126130
long start = System.currentTimeMillis();
127131
List<GalleryFile> filesToSearch = new ArrayList<>();
128132
for (Uri uri : uriFiles) {
@@ -226,7 +230,7 @@ private synchronized void incrementFolders(int amount) {
226230
@NonNull
227231
private List<GalleryFile> findAllFilesInFolder(Uri uri) {
228232
Log.e(TAG, "findAllFilesInFolder: find all files in " + uri.getLastPathSegment());
229-
List<GalleryFile> files = new ArrayList<>();
233+
List<GalleryFile> files = new UniqueLinkedList<>();
230234
FragmentActivity activity = getActivity();
231235
if (activity == null || !isSafe()) {
232236
return files;

app/src/main/java/se/arctosoft/vault/DirectoryBaseFragment.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package se.arctosoft.vault;
1919

2020
import android.annotation.SuppressLint;
21+
import android.content.Intent;
2122
import android.content.res.Configuration;
2223
import android.net.Uri;
2324
import android.os.Bundle;
@@ -336,17 +337,14 @@ void findFilesIn(Uri directoryUri) {
336337
galleryViewModel.setInitialised(true);
337338
galleryGridAdapter.notifyItemRangeInserted(0, galleryFiles.size());
338339
galleryPagerAdapter.notifyItemRangeInserted(0, galleryFiles.size());
340+
initFastScroll();
339341
}
340342
});
341343
}).start();
342344
}
343345

344346
void setupGrid() {
345-
if (galleryViewModel.isInitialised()) {
346-
binding.recyclerView.setFastScrollEnabled(galleryViewModel.getGalleryFiles().size() > MIN_FILES_FOR_FAST_SCROLL);
347-
} else {
348-
binding.recyclerView.setFastScrollEnabled(false);
349-
}
347+
initFastScroll();
350348
int spanCount = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 6 : 3;
351349
RecyclerView.LayoutManager layoutManager = new StaggeredGridLayoutManager(spanCount, RecyclerView.VERTICAL);
352350
binding.recyclerView.setLayoutManager(layoutManager);
@@ -358,6 +356,14 @@ void setupGrid() {
358356
galleryGridAdapter.setOnSelectionModeChanged(this::onSelectionModeChanged);
359357
}
360358

359+
private void initFastScroll() {
360+
if (galleryViewModel.isInitialised()) {
361+
binding.recyclerView.setFastScrollEnabled(galleryViewModel.getGalleryFiles().size() > MIN_FILES_FOR_FAST_SCROLL);
362+
} else {
363+
binding.recyclerView.setFastScrollEnabled(false);
364+
}
365+
}
366+
361367
abstract void onSelectionModeChanged(boolean inSelectionMode);
362368

363369
void setupViewpager() {
@@ -536,6 +542,9 @@ public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
536542
FragmentActivity activity = getActivity();
537543
if (activity != null) {
538544
activity.finish();
545+
if (!settings.exitOnLock()) {
546+
startActivity(new Intent(requireContext(), MainActivity.class));
547+
}
539548
}
540549
return true;
541550
} else if (id == R.id.order_by_newest_first) {
@@ -613,6 +622,22 @@ public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
613622
public void onStart() {
614623
super.onStart();
615624
requireActivity().addMenuProvider(this, getViewLifecycleOwner());
625+
Uri clickedDirectoryUri = galleryViewModel.getClickedDirectoryUri();
626+
if (clickedDirectoryUri != null) {
627+
galleryViewModel.setClickedDirectoryUri(null);
628+
synchronized (LOCK) {
629+
List<GalleryFile> galleryFiles = galleryViewModel.getGalleryFiles();
630+
for (int i = 0; i < galleryFiles.size(); i++) {
631+
GalleryFile galleryFile = galleryFiles.get(i);
632+
if (galleryFile.isDirectory() && galleryFile.getUri() == clickedDirectoryUri) {
633+
galleryFile.resetFilesInDirectory();
634+
galleryGridAdapter.notifyItemChanged(i);
635+
galleryPagerAdapter.notifyItemChanged(i);
636+
break;
637+
}
638+
}
639+
}
640+
}
616641
}
617642

618643
@Override

app/src/main/java/se/arctosoft/vault/DirectoryFragment.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ public void handleOnBackPressed() {
8787
FragmentActivity activity = requireActivity();
8888
Password.lock(activity);
8989
activity.finish();
90+
if (!settings.exitOnLock()) {
91+
startActivity(new Intent(context, MainActivity.class));
92+
}
9093
}
9194
}
9295
};

app/src/main/java/se/arctosoft/vault/SettingsFragment.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
3535
SwitchPreferenceCompat useDiskCache = findPreference(Settings.PREF_ENCRYPTION_USE_DISK_CACHE);
3636
SwitchPreferenceCompat secure = findPreference(Settings.PREF_APP_SECURE);
3737
SwitchPreferenceCompat deleteByDefault = findPreference(Settings.PREF_ENCRYPTION_DELETE_BY_DEFAULT);
38+
SwitchPreferenceCompat showDecryptableOnly = findPreference(Settings.PREF_ENCRYPTION_DISPLAY_DECRYPTABLE_ONLY);
39+
SwitchPreferenceCompat exitOnLock = findPreference(Settings.PREF_APP_EXIT_ON_LOCK);
3840

3941
FragmentActivity activity = requireActivity();
4042
Settings settings = Settings.getInstance(activity);
@@ -63,6 +65,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
6365
} else {
6466
requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
6567
}
68+
settings.setSecureFlag((boolean) newValue);
6669
return true;
6770
});
6871

@@ -76,6 +79,16 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
7679
return true;
7780
});
7881

82+
showDecryptableOnly.setOnPreferenceChangeListener((preference, newValue) -> {
83+
settings.setDisplayDecryptableFilesOnly((boolean) newValue);
84+
return true;
85+
});
86+
87+
exitOnLock.setOnPreferenceChangeListener((preference, newValue) -> {
88+
settings.setExitOnLock((boolean) newValue);
89+
return true;
90+
});
91+
7992
editFolders.setOnPreferenceClickListener(preference -> {
8093
Dialogs.showEditIncludedFolders(activity, settings, selectedToRemove -> {
8194
settings.removeGalleryDirectories(selectedToRemove);

app/src/main/java/se/arctosoft/vault/adapters/GalleryGridAdapter.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,12 @@ private void readText(FragmentActivity context, GalleryFile galleryFile, Gallery
234234
new Thread(() -> {
235235
String text = Encryption.readEncryptedTextFromUri(galleryFile.getUri(), context, galleryFile.getVersion(), password.getPassword());
236236
galleryFile.setText(text);
237-
context.runOnUiThread(() -> galleryViewModel.getOnAdapterItemChanged().onChanged(holder.getBindingAdapterPosition()));
237+
context.runOnUiThread(() -> {
238+
int pos = holder.getBindingAdapterPosition();
239+
if (pos >= 0) {
240+
galleryViewModel.getOnAdapterItemChanged().onChanged(pos);
241+
}
242+
});
238243
}).start();
239244
}
240245

@@ -279,6 +284,7 @@ private void setClickListener(@NonNull GalleryGridViewHolder holder, FragmentAct
279284
} else {
280285
bundle.putString(DirectoryFragment.ARGUMENT_DIRECTORY, galleryFile.getUri().toString());
281286
}
287+
galleryViewModel.setClickedDirectoryUri(galleryFile.getUri());
282288
Navigation.findNavController(holder.binding.layout).navigate(R.id.action_directory_self, bundle);
283289
} else {
284290
if (onFileCLicked != null) {

app/src/main/java/se/arctosoft/vault/adapters/GalleryPagerAdapter.java

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
package se.arctosoft.vault.adapters;
2020

21+
import android.content.ContentResolver;
2122
import android.content.Intent;
2223
import android.graphics.Color;
2324
import android.graphics.PointF;
@@ -41,6 +42,7 @@
4142
import androidx.core.view.ViewCompat;
4243
import androidx.core.view.WindowInsetsCompat;
4344
import androidx.documentfile.provider.DocumentFile;
45+
import androidx.exifinterface.media.ExifInterface;
4446
import androidx.fragment.app.FragmentActivity;
4547
import androidx.media3.common.MediaItem;
4648
import androidx.media3.common.PlaybackException;
@@ -55,9 +57,13 @@
5557
import com.bumptech.glide.Glide;
5658
import com.google.android.material.color.MaterialColors;
5759

60+
import org.json.JSONException;
61+
5862
import java.io.File;
5963
import java.io.FileNotFoundException;
64+
import java.io.IOException;
6065
import java.lang.ref.WeakReference;
66+
import java.security.GeneralSecurityException;
6167
import java.util.HashMap;
6268
import java.util.List;
6369
import java.util.Map;
@@ -235,6 +241,7 @@ private void setupDirectoryView(@NonNull GalleryPagerViewHolder holder, Fragment
235241
} else {
236242
bundle.putString(DirectoryFragment.ARGUMENT_DIRECTORY, galleryFile.getUri().toString());
237243
}
244+
galleryViewModel.setClickedDirectoryUri(galleryFile.getUri());
238245
Navigation.findNavController(((GalleryPagerViewHolder.GalleryPagerDirectoryViewHolder) holder).binding.getRoot()).navigate(R.id.action_directory_self, bundle);
239246
});
240247
GalleryFile firstFile = galleryFile.getFirstFile();
@@ -378,10 +385,11 @@ public void onCenterChanged(PointF newCenter, int origin) {
378385

379386
}
380387
});
388+
loadImage(galleryFile, (GalleryPagerViewHolder.GalleryPagerImageViewHolder) holder, context);
381389
} else if (holder instanceof GalleryPagerViewHolder.GalleryPagerGifViewHolder) {
382390
((GalleryPagerViewHolder.GalleryPagerGifViewHolder) holder).binding.gifImageView.setOnClickListener(v -> onItemPressed(context));
391+
loadGif(galleryFile, (GalleryPagerViewHolder.GalleryPagerGifViewHolder) holder, context);
383392
}
384-
loadImage(galleryFile.getUri(), holder, context, galleryFile.getVersion());
385393
}
386394

387395
private void onItemPressed(FragmentActivity context) {
@@ -410,18 +418,67 @@ private void setFullscreen(@NonNull FragmentActivity context, boolean fullscreen
410418
notifyItemRangeChanged(0, galleryFiles.size(), isFullscreen);
411419
}
412420

413-
private void loadImage(Uri uri, GalleryPagerViewHolder holder, FragmentActivity context, int version) {
414-
if (holder instanceof GalleryPagerViewHolder.GalleryPagerImageViewHolder) {
415-
((GalleryPagerViewHolder.GalleryPagerImageViewHolder) holder).binding.imageView.setImage(ImageSource.uri(uri, password.getPassword(), version));
416-
} else if (holder instanceof GalleryPagerViewHolder.GalleryPagerGifViewHolder) {
417-
Glide.with(context)
418-
//.asGif()
419-
.load(uri)
420-
.apply(GlideStuff.getRequestOptions(useDiskCache))
421-
.into(((GalleryPagerViewHolder.GalleryPagerGifViewHolder) holder).binding.gifImageView);
421+
private void loadImage(GalleryFile galleryFile, GalleryPagerViewHolder.GalleryPagerImageViewHolder holder, FragmentActivity context) {
422+
if (galleryFile.getOrientation() != -1) {
423+
holder.binding.imageView.setOrientation(galleryFile.getOrientation());
424+
holder.binding.imageView.setImage(ImageSource.uri(galleryFile.getUri(), password.getPassword(), galleryFile.getVersion()));
425+
} else {
426+
new Thread(() -> {
427+
Encryption.Streams streams = null;
428+
int orientation = -1;
429+
try {
430+
ContentResolver contentResolver = context.getContentResolver();
431+
streams = Encryption.getCipherInputStream(contentResolver.openInputStream(galleryFile.getUri()), password.getPassword(), false, galleryFile.getVersion());
432+
ExifInterface exifInterface = new ExifInterface(streams.getInputStream());
433+
orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
434+
if (orientation == ExifInterface.ORIENTATION_UNDEFINED) {
435+
orientation = -1;
436+
} else {
437+
orientation = exifToDegrees(orientation);
438+
}
439+
} catch (GeneralSecurityException | InvalidPasswordException | JSONException |
440+
IOException e) {
441+
e.printStackTrace();
442+
context.runOnUiThread(() -> {
443+
int i = holder.getBindingAdapterPosition();
444+
if (i >= 0) {
445+
removeFileAt(i, context);
446+
}
447+
});
448+
} finally {
449+
if (streams != null) {
450+
streams.close();
451+
}
452+
}
453+
454+
galleryFile.setOrientation(orientation);
455+
context.runOnUiThread(() -> {
456+
holder.binding.imageView.setOrientation(galleryFile.getOrientation());
457+
holder.binding.imageView.setImage(ImageSource.uri(galleryFile.getUri(), password.getPassword(), galleryFile.getVersion()));
458+
});
459+
}).start();
422460
}
423461
}
424462

463+
private int exifToDegrees(int orientation) {
464+
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
465+
return 90;
466+
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
467+
return 180;
468+
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
469+
return 270;
470+
}
471+
return 0;
472+
}
473+
474+
private void loadGif(GalleryFile galleryFile, GalleryPagerViewHolder.GalleryPagerGifViewHolder holder, FragmentActivity context) {
475+
Glide.with(context)
476+
//.asGif()
477+
.load(galleryFile.getUri())
478+
.apply(GlideStuff.getRequestOptions(useDiskCache))
479+
.into(holder.binding.gifImageView);
480+
}
481+
425482
private void showButtons(GalleryPagerViewHolder holder, boolean show) {
426483
if (isFullscreen) {
427484
show = false;

0 commit comments

Comments
 (0)