Skip to content

GSoC 2021 custom picture selector #4534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 77 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
ba7cbba
Initialised xmls, made folder and image item.
4D17Y4 May 24, 2021
0ce1a20
xmls done
4D17Y4 Jun 4, 2021
c00617d
xmls completed
4D17Y4 Jun 4, 2021
bb8ebe5
removed unwanted attribute
4D17Y4 Jun 5, 2021
3463a19
Merge branch 'custom-picture-selector' of https://github.com/4D17Y4/a…
nicolas-raoul Jun 5, 2021
dc26621
Created models, adapters and view models (#4441)
4D17Y4 Jun 10, 2021
aed4bc8
[GSOC] Added Image Fetch (#4449)
4D17Y4 Jun 13, 2021
746a660
[GSoC] Image Selection (#4457)
4D17Y4 Jun 17, 2021
7a6b244
[GSoC] Show uploaded images differently. (#4464)
4D17Y4 Jun 21, 2021
8e9d289
[GSoC] Added Uploaded status table in room database. (#4476)
4D17Y4 Jun 29, 2021
67b69c8
Image Helper test (#4485)
4D17Y4 Jun 30, 2021
93dae58
[GSoC] Adapter Tests (#4488)
4D17Y4 Jul 3, 2021
7336881
[GSoC] Master rebase. (#4505)
4D17Y4 Jul 14, 2021
404a79b
[GSoC] Custom Selector Tests (#4494)
4D17Y4 Jul 18, 2021
351fd28
Image Loader Improvements (#4516)
4D17Y4 Jul 21, 2021
2a9f5ed
ImageLoader Test Updated (#4517)
4D17Y4 Jul 24, 2021
a956bc2
[GSoC] Improvement and bug Fixes (#4522)
4D17Y4 Jul 26, 2021
771a731
Saving selector state (#4526)
4D17Y4 Jul 27, 2021
70acd7b
[GSoC] Saved Image Fragment Scroll State (#4528)
4D17Y4 Aug 8, 2021
efc8a6e
Initialised xmls, made folder and image item.
4D17Y4 May 24, 2021
a022a0b
xmls done
4D17Y4 Jun 4, 2021
269719c
xmls completed
4D17Y4 Jun 4, 2021
3cd8707
removed unwanted attribute
4D17Y4 Jun 5, 2021
5cc05ba
Created models, adapters and view models (#4441)
4D17Y4 Jun 10, 2021
133c51e
[GSOC] Added Image Fetch (#4449)
4D17Y4 Jun 13, 2021
6686ad5
[GSoC] Image Selection (#4457)
4D17Y4 Jun 17, 2021
da35c18
[GSoC] Show uploaded images differently. (#4464)
4D17Y4 Jun 21, 2021
9a534a9
[GSoC] Added Uploaded status table in room database. (#4476)
4D17Y4 Jun 29, 2021
f4ff853
Image Helper test (#4485)
4D17Y4 Jun 30, 2021
be522b1
[GSoC] Adapter Tests (#4488)
4D17Y4 Jul 3, 2021
4382cda
[GSoC] Master rebase. (#4505)
4D17Y4 Jul 14, 2021
89fd4f4
[GSoC] Custom Selector Tests (#4494)
4D17Y4 Jul 18, 2021
1a5bb1f
Image Loader Improvements (#4516)
4D17Y4 Jul 21, 2021
af3936a
ImageLoader Test Updated (#4517)
4D17Y4 Jul 24, 2021
9b00c94
[GSoC] Improvement and bug Fixes (#4522)
4D17Y4 Jul 26, 2021
267b6b2
Saving selector state (#4526)
4D17Y4 Jul 27, 2021
658a7ec
[GSoC] Saved Image Fragment Scroll State (#4528)
4D17Y4 Aug 8, 2021
2c8c919
rebase fix
4D17Y4 Aug 9, 2021
3c18b1e
Merge branch 'gsoc21-custom-picture-selector' into master-update
4D17Y4 Aug 9, 2021
bc994d1
Merge pull request #4537 from 4D17Y4/master-update
nicolas-raoul Aug 9, 2021
d8d8038
Tests updated (#4538)
4D17Y4 Aug 10, 2021
a055f3b
orientation fixed (#4540)
4D17Y4 Aug 10, 2021
dfabaf8
refractoring (#4541)
4D17Y4 Aug 10, 2021
79447cf
refractoring (#4545)
4D17Y4 Aug 12, 2021
25156d0
[GSoC] Welcome Dialog (#4546)
4D17Y4 Aug 14, 2021
6811f13
[GSoC] Image preview (#4559)
4D17Y4 Aug 17, 2021
3804716
Merge branch 'master' into gsoc21-custom-picture-selector
4D17Y4 Aug 18, 2021
560662c
Initialised xmls, made folder and image item.
4D17Y4 May 24, 2021
4f394ff
xmls done
4D17Y4 Jun 4, 2021
d6472a1
xmls completed
4D17Y4 Jun 4, 2021
63798c0
removed unwanted attribute
4D17Y4 Jun 5, 2021
2dbda3a
Created models, adapters and view models (#4441)
4D17Y4 Jun 10, 2021
a120030
[GSOC] Added Image Fetch (#4449)
4D17Y4 Jun 13, 2021
c7dae69
[GSoC] Image Selection (#4457)
4D17Y4 Jun 17, 2021
088f66e
[GSoC] Show uploaded images differently. (#4464)
4D17Y4 Jun 21, 2021
1749a7b
[GSoC] Added Uploaded status table in room database. (#4476)
4D17Y4 Jun 29, 2021
9488737
Image Helper test (#4485)
4D17Y4 Jun 30, 2021
e10e666
[GSoC] Adapter Tests (#4488)
4D17Y4 Jul 3, 2021
86ee96c
[GSoC] Master rebase. (#4505)
4D17Y4 Jul 14, 2021
732b343
[GSoC] Custom Selector Tests (#4494)
4D17Y4 Jul 18, 2021
443dcf4
Image Loader Improvements (#4516)
4D17Y4 Jul 21, 2021
36a94fe
ImageLoader Test Updated (#4517)
4D17Y4 Jul 24, 2021
b62247d
[GSoC] Improvement and bug Fixes (#4522)
4D17Y4 Jul 26, 2021
e8f7d0f
Saving selector state (#4526)
4D17Y4 Jul 27, 2021
d78e6de
[GSoC] Saved Image Fragment Scroll State (#4528)
4D17Y4 Aug 8, 2021
cfe128e
rebase fix
4D17Y4 Aug 9, 2021
1b984c8
[GSoC] Master rebase. (#4505)
4D17Y4 Jul 14, 2021
ea29a72
Tests updated (#4538)
4D17Y4 Aug 10, 2021
9333e52
orientation fixed (#4540)
4D17Y4 Aug 10, 2021
2e2b286
refractoring (#4541)
4D17Y4 Aug 10, 2021
029f170
refractoring (#4545)
4D17Y4 Aug 12, 2021
0ebbc9d
[GSoC] Welcome Dialog (#4546)
4D17Y4 Aug 14, 2021
25792e2
[GSoC] Image preview (#4559)
4D17Y4 Aug 17, 2021
50650a1
update database version
4D17Y4 Aug 18, 2021
c0f3d3f
Merge branch 'gsoc21-custom-picture-selector' into master-rebase
4D17Y4 Aug 18, 2021
3f2d929
remove duplicates
4D17Y4 Aug 18, 2021
60c21f3
Merge pull request #4561 from 4D17Y4/master-rebase
nicolas-raoul Aug 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1"
testImplementation 'com.facebook.soloader:soloader:0.9.0'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2"

// Android testing
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
Expand Down Expand Up @@ -142,6 +143,10 @@ dependencies {
def work_version = "2.4.0"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"

//Glide
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}

android {
Expand Down Expand Up @@ -204,7 +209,7 @@ android {
}
}
debug {
minifyEnabled true
minifyEnabled false
testCoverageEnabled project.hasProperty('coverage')
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
testProguardFile 'test-proguard-rules.txt'
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@
<activity android:name=".quiz.QuizResultActivity"
android:label="@string/result"/>

<activity
android:name=".customselector.ui.selector.CustomSelectorActivity"
android:label="@string/title_activity_custom_selector"
android:configChanges="screenSize|keyboard|orientation"
android:parentActivityName=".contributions.MainActivity" />

<activity
android:name=".category.CategoryDetailsActivity"
android:label="@string/title_activity_featured_images"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ data class Contribution constructor(
var dataLength: Long = 0,
var dateCreated: Date? = null,
var dateModified: Date? = null,
var hasInvalidLocation : Int = 0
var hasInvalidLocation : Int = 0,
var contentUri: Uri? = null
) : Parcelable {

fun completeWith(media: Media): Contribution {
Expand All @@ -64,7 +65,8 @@ data class Contribution constructor(
decimalCoords = item.gpsCoords.decimalCoords,
dateCreatedSource = "",
depictedItems = depictedItems,
wikidataPlace = from(item.place)
wikidataPlace = from(item.place),
contentUri = item.contentUri
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ public void initiateGalleryPick(final Activity activity, final boolean allowMult
initiateGalleryUpload(activity, allowMultipleUploads);
}

/**
* Initiate gallery picker with permission
*/
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
setPickerConfiguration(activity,true);

PermissionUtils.checkPermissionsAndPerformAction(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
() -> FilePicker.openCustomSelector(activity, 0),
R.string.storage_permission_title,
R.string.write_storage_permission_rationale);
}


/**
* Open chooser for gallery uploads
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
Expand All @@ -29,13 +30,16 @@
import androidx.recyclerview.widget.SimpleItemAnimator;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.media.MediaClient;
import fr.free.nrw.commons.utils.SystemThemeUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import java.util.Locale;
import javax.inject.Inject;
Expand All @@ -52,7 +56,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
WikipediaInstructionsDialogFragment.Callback {

private static final String RV_STATE = "rv_scroll_state";

@BindView(R.id.contributionsList)
RecyclerView rvContributionsList;
@BindView(R.id.loadingContributionsProgressBar)
Expand All @@ -67,6 +71,11 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
TextView noContributionsYet;
@BindView(R.id.fab_layout)
LinearLayout fab_layout;
@BindView(R.id.fab_custom_gallery)
FloatingActionButton fabCustomGallery;

@Inject
SystemThemeUtils systemThemeUtils;

@Inject
ContributionController controller;
Expand Down Expand Up @@ -260,23 +269,35 @@ private void setListeners() {
});
}

/**
* Launch Custom Selector.
*/
@OnClick(R.id.fab_custom_gallery)
void launchCustomSelector(){
controller.initiateCustomGalleryPickWithPermission(getActivity());
}

private void animateFAB(final boolean isFabOpen) {
this.isFabOpen = !isFabOpen;
if (fabPlus.isShown()) {
if (isFabOpen) {
fabPlus.startAnimation(rotate_backward);
fabCamera.startAnimation(fab_close);
fabGallery.startAnimation(fab_close);
fabCamera.hide();
fabGallery.hide();
} else {
fabPlus.startAnimation(rotate_forward);
fabCamera.startAnimation(fab_open);
fabGallery.startAnimation(fab_open);
fabCamera.show();
fabGallery.show();
}
this.isFabOpen = !isFabOpen;
if (isFabOpen) {
fabPlus.startAnimation(rotate_backward);
fabCamera.startAnimation(fab_close);
fabGallery.startAnimation(fab_close);
fabCustomGallery.startAnimation(fab_close);
fabCamera.hide();
fabGallery.hide();
fabCustomGallery.hide();
} else {
fabPlus.startAnimation(rotate_forward);
fabCamera.startAnimation(fab_open);
fabGallery.startAnimation(fab_open);
fabCustomGallery.startAnimation(fab_open);
fabCamera.show();
fabGallery.show();
fabCustomGallery.show();
}
this.isFabOpen = !isFabOpen;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package fr.free.nrw.commons.customselector.database

import androidx.room.*
import java.util.*

/**
* UploadedStatusDao for Custom Selector.
*/
@Dao
abstract class UploadedStatusDao {

/**
* Insert into uploaded status.
*/
@Insert( onConflict = OnConflictStrategy.REPLACE )
abstract suspend fun insert(uploadedStatus: UploadedStatus)

/**
* Update uploaded status entry.
*/
@Update
abstract suspend fun update(uploadedStatus: UploadedStatus)

/**
* Delete uploaded status entry.
*/
@Delete
abstract suspend fun delete(uploadedStatus: UploadedStatus)

/**
* Query uploaded status with image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE imageSHA1 = (:imageSHA1) ")
abstract suspend fun getFromImageSHA1(imageSHA1 : String) : UploadedStatus?

/**
* Query uploaded status with modified image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE modifiedImageSHA1 = (:modifiedImageSHA1) ")
abstract suspend fun getFromModifiedImageSHA1(modifiedImageSHA1 : String) : UploadedStatus?

/**
* Asynchronous insert into uploaded status table.
*/
suspend fun insertUploaded(uploadedStatus: UploadedStatus) {
uploadedStatus.lastUpdated = Calendar.getInstance().time
insert(uploadedStatus)
}

/**
* Asynchronous image sha1 query.
*/
suspend fun getUploadedFromImageSHA1(imageSHA1: String):UploadedStatus? {
return getFromImageSHA1(imageSHA1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package fr.free.nrw.commons.customselector.database

import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import java.util.*

/**
* Entity class for Uploaded Status.
*/
@Entity(tableName = "uploaded_table", indices = [Index(value = ["modifiedImageSHA1"], unique = true)])
data class UploadedStatus(

/**
* Original image sha1.
*/
@PrimaryKey
val imageSHA1 : String,

/**
* Modified image sha1 (after exif changes).
*/
val modifiedImageSHA1 : String,

/**
* imageSHA1 query result from API.
*/
var imageResult : Boolean,

/**
* modifiedImageSHA1 query result from API.
*/
var modifiedImageResult : Boolean,

/**
* lastUpdated for data validation.
*/
var lastUpdated : Date? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package fr.free.nrw.commons.customselector.helper

import fr.free.nrw.commons.customselector.model.Folder
import fr.free.nrw.commons.customselector.model.Image

/**
* Image Helper object, includes all the static functions required by custom selector.
*/
object ImageHelper {

/**
* Returns the list of folders from given image list.
*/
fun folderListFromImages(images: List<Image>): ArrayList<Folder> {
val folderMap: MutableMap<Long, Folder> = LinkedHashMap()
for (image in images) {
val bucketId = image.bucketId
val bucketName = image.bucketName
var folder = folderMap[bucketId]
if (folder == null) {
folder = Folder(bucketId, bucketName)
folderMap[bucketId] = folder
}
folder.images.add(image)
}
return ArrayList(folderMap.values)
}

/**
* Filters the images based on the given bucketId (folder)
*/
fun filterImages(images: ArrayList<Image>, bukketId: Long?): ArrayList<Image> {
if (bukketId == null) return images

val filteredImages = arrayListOf<Image>()
for (image in images) {
if (image.bucketId == bukketId) {
filteredImages.add(image)
}
}
return filteredImages
}

/**
* getIndex: Returns the index of image in given list.
*/
fun getIndex(list: ArrayList<Image>, image: Image): Int {
return list.indexOf(image)
}

/**
* getIndex: Returns the index of image in given list.
*/
fun getIndexFromId(list: ArrayList<Image>, imageId: Long): Int {
for(i in list){
if(i.id == imageId)
return list.indexOf(i)
}
return 0;
}

/**
* Gets the list of indices from the master list.
*/
fun getIndexList(list: ArrayList<Image>, masterList: ArrayList<Image>): ArrayList<Int> {

// Can be optimised as masterList is sorted by time.

val indexes = arrayListOf<Int>()
for(image in list) {
val index = getIndex(masterList, image)
if (index == -1) {
continue
}
indexes.add(index)
}
return indexes
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package fr.free.nrw.commons.customselector.listeners

/**
* Custom Selector Folder Click Listener
*/
interface FolderClickListener {

/**
* onFolderClick
* @param folderId : folder id of the folder.
* @param folderName : folder name of the folder.
* @param lastItemId : last scroll position in the folder.
*/
fun onFolderClick(folderId: Long, folderName: String, lastItemId: Long)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package fr.free.nrw.commons.customselector.listeners

import fr.free.nrw.commons.customselector.model.Image

/**
* Custom Selector Image Loader Listener
* responds to the device image query.
*/
interface ImageLoaderListener {

/**
* On image loaded
* @param images : queried device images.
*/
fun onImageLoaded(images: ArrayList<Image>)

/**
* On failed
* @param throwable : throwable exception on failure.
*/
fun onFailed(throwable: Throwable)
}
Loading