Skip to content

Commit 6686ad5

Browse files
4D17Y4translatewikiobsidian-zeroaq45654amire80
committed
[GSoC] Image Selection (commons-app#4457)
* Localisation updates from https://translatewiki.net. * Fixes commons-app#4357 After switching to different account, contributions screen shows pictures of previous account (commons-app#4421) * Update UploadMediaDetailFragment.java * Update LoginActivity.java Clear CompositeDisposable after logging in successfully. It may help solve the problem of saving the contribution to the previous account * Revert "Update UploadMediaDetailFragment.java" This reverts commit b1b4257. Co-authored-by: Obsidian_zero <1198474846@qq.com> * Remove unnecessary whitespace from a message (commons-app#4439) * Merge v3.0.1 into master (commons-app#4446) * Versioning and changelog for v3.0.0 (commons-app#4152) * Versioning for v3.0.0 * Update changelog.md * Handled migration 8-9-10 in BookmarksLocationDao (commons-app#4154) * #Fixes commons-app#4141 - Handled migrations for BookmarkLocationsDao from 8-9-10 * #Fixes commons-app#4141 - Handled migrations for BookmarkLocationsDao from 8-9-10 * Fixes commons-app#4179 (commons-app#4180) * Handled null pointer exception in MainActivity->ContributionsFragment#backButtonClicked() * Updated >ContributionsFragment#backButtonClicked() to handle back press properly * Fixes commons-app#4179 (commons-app#4181) * Handled possible null check on MediaDetails in BookmarkListRootFragment#backPressed() * Cherrypick for hotfix3.1 (commons-app#4205) * Fixes commons-app#4159 On Explore Tab, All Available Options on toolbar in media detail view are only targeting the first media in the list. Fixes commons-app#4159 On Explore Tab, All Available Options on toolbar in media detail view are only targeting the first media in the list. * fixed bug: App crashes on viewing review in Review Fragment commons-app#4132 (commons-app#4146) * fixed bug:app crashes on viewing review in Review Fragment commons-app#4135 * Fixed the issue with back button in contribution tab. (commons-app#4177) Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com> * Fixed the issue with back navigation button on toolbar in explore tab. (commons-app#4175) * Fix (commons-app#4148) Issues on theme change * fixed themeChange crashes * fixed comments * Overlooked the title bar Co-authored-by: Pratham Pahariya <54663429+Pratham2305@users.noreply.github.com> Co-authored-by: Shabir Ahmad <56585337+shabar-shab@users.noreply.github.com> Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com> Co-authored-by: Aditya-Srivastav <54016427+4D17Y4@users.noreply.github.com> * Fixes commons-app#4173 (commons-app#4396) * Fix commons-app#4147 Pre-fill desc in Nearby uploads with Wikidata item's label + description (commons-app#4390) * Update query to fetch descriptions * Make description added to NearbyResultItem * Make string operations to display description and label in a combined way * Fix reviews, remove long description from list and swap label and description texts * Fix repeated information issue * Fix double information issue * fix style issues * Remove douplicated information * Changes made (commons-app#4354) * Remove nonexistent method * Fix commons-app#4283 IllegalStateException (commons-app#4440) * Fix commons-app#4283 IllegalStateException * Fix flickering issue * Versioning for v3.0.1 * Update changelog.md Co-authored-by: Ashish <ashishkumar468@gmail.com> Co-authored-by: neslihanturan <tur.neslihan@gmail.com> Co-authored-by: Pratham Pahariya <54663429+Pratham2305@users.noreply.github.com> Co-authored-by: Shabir Ahmad <56585337+shabar-shab@users.noreply.github.com> Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com> Co-authored-by: Aditya-Srivastav <54016427+4D17Y4@users.noreply.github.com> Co-authored-by: Madhur Gupta <30932899+madhurgupta10@users.noreply.github.com> Co-authored-by: Vinayak Aggarwal <56196007+vinayak0505@users.noreply.github.com> * Localisation updates from https://translatewiki.net. * Added basic Fetch * added permission request * Folder count rectified * Loaded thumbnail * disabled overlay * Added sha1 function * Documented the code * Added a feature for editing coordinates (commons-app#4418) * not * Place Picker added * Pick location and API call linked * minor warnings resolved * Code conventions followed * issue fixed * Wikitext edited properly * minor modification * Location Picker added * Bottom sheet removed * Location picker fully implemented * credit added * credit added * issues fixed * issues fixed * minor issue fixed * Some build issues occured merging release v3.0 are fixed. One paranthesis issue is solved, a method about UploadService is removed, since we don't use it anymore. (commons-app#4451) * Localisation updates from https://translatewiki.net. * Fixes 4344 - Duplicate Uploads (commons-app#4442) * Fixes 4344 - Update the retention policy of the Work Manager to ExistingWorkPolicy.APPEND_OR_REPLACE- which would append the new work to the end of existing one. This helps remove the while loop in UploadWorker which was meant to handle the cases where a new worker would be created for retries. The while loop seemed to have race conditions uploading duplicate entries. * Update states to IN_PROGRESS before uploads are processed * Image selection added * Forwarded activity result to upload wizard * Initialised xmls, made folder and image item. * xmls done * xmls completed * removed unwanted attribute * Created models, adapters and view models (commons-app#4441) * created models, adapters and view models * Added Image Fragment * back button linked * Documentation and refractor * spaces * Butterknife annotation * DiffUtil * Added Examples * Extended Custom selector From Base Activity * made view model injectable * Added basic Fetch * added permission request * Folder count rectified * Loaded thumbnail * disabled overlay * Added sha1 function * Documented the code * Image selection added * Forwarded activity result to upload wizard * [GSOC] Added Image Fetch (commons-app#4449) * Added basic Fetch * added permission request * Folder count rectified * Loaded thumbnail * disabled overlay * Added sha1 function * Documented the code * fixed merge errors * Documented the remaining function Co-authored-by: translatewiki.net <l10n-bot@translatewiki.net> Co-authored-by: obsidian-zero <63155026+obsidian-zero@users.noreply.github.com> Co-authored-by: Obsidian_zero <1198474846@qq.com> Co-authored-by: Amir E. Aharoni <amir.aharoni@mail.huji.ac.il> Co-authored-by: Josephine Lim <josephinelim86@gmail.com> Co-authored-by: Ashish <ashishkumar468@gmail.com> Co-authored-by: neslihanturan <tur.neslihan@gmail.com> Co-authored-by: Pratham Pahariya <54663429+Pratham2305@users.noreply.github.com> Co-authored-by: Shabir Ahmad <56585337+shabar-shab@users.noreply.github.com> Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com> Co-authored-by: Madhur Gupta <30932899+madhurgupta10@users.noreply.github.com> Co-authored-by: Vinayak Aggarwal <56196007+vinayak0505@users.noreply.github.com> Co-authored-by: Ayan Sarkar <71203077+Ayan-10@users.noreply.github.com>
1 parent 133c51e commit 6686ad5

File tree

9 files changed

+226
-61
lines changed

9 files changed

+226
-61
lines changed

app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java

+2-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import android.content.Intent;
99
import androidx.annotation.NonNull;
1010
import fr.free.nrw.commons.R;
11-
import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorActivity;
1211
import fr.free.nrw.commons.filepicker.DefaultCallback;
1312
import fr.free.nrw.commons.filepicker.FilePicker;
1413
import fr.free.nrw.commons.filepicker.FilePicker.ImageSource;
@@ -63,16 +62,11 @@ public void initiateGalleryPick(final Activity activity, final boolean allowMult
6362
* Initiate gallery picker with permission
6463
*/
6564
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
66-
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
67-
Intent intent = new Intent(activity,CustomSelectorActivity.class);
68-
if (!useExtStorage) {
69-
activity.startActivity(intent);
70-
return;
71-
}
65+
setPickerConfiguration(activity,true);
7266

7367
PermissionUtils.checkPermissionsAndPerformAction(activity,
7468
Manifest.permission.WRITE_EXTERNAL_STORAGE,
75-
() -> activity.startActivity(intent),
69+
() -> FilePicker.openCustomSelector(activity, 0),
7670
R.string.storage_permission_title,
7771
R.string.write_storage_permission_rationale);
7872
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java

+27-27
Original file line numberDiff line numberDiff line change
@@ -265,34 +265,34 @@ private void setListeners() {
265265
});
266266
}
267267

268-
@OnClick(R.id.fab_custom_gallery)
269-
void launchCustomSelector(){
270-
controller.initiateCustomGalleryPickWithPermission(getActivity());
271-
}
272-
273-
private void animateFAB(final boolean isFabOpen) {
274-
this.isFabOpen = !isFabOpen;
275-
if (fabPlus.isShown()) {
276-
if (isFabOpen) {
277-
fabPlus.startAnimation(rotate_backward);
278-
fabCamera.startAnimation(fab_close);
279-
fabGallery.startAnimation(fab_close);
280-
fabCustomGallery.startAnimation(fab_close);
281-
fabCamera.hide();
282-
fabGallery.hide();
283-
fabCustomGallery.hide();
284-
} else {
285-
fabPlus.startAnimation(rotate_forward);
286-
fabCamera.startAnimation(fab_open);
287-
fabGallery.startAnimation(fab_open);
288-
fabCustomGallery.startAnimation(fab_open);
289-
fabCamera.show();
290-
fabGallery.show();
291-
fabCustomGallery.show();
292-
}
293-
this.isFabOpen = !isFabOpen;
268+
@OnClick(R.id.fab_custom_gallery)
269+
void launchCustomSelector(){
270+
controller.initiateCustomGalleryPickWithPermission(getActivity());
271+
}
272+
273+
private void animateFAB(final boolean isFabOpen) {
274+
this.isFabOpen = !isFabOpen;
275+
if (fabPlus.isShown()) {
276+
if (isFabOpen) {
277+
fabPlus.startAnimation(rotate_backward);
278+
fabCamera.startAnimation(fab_close);
279+
fabGallery.startAnimation(fab_close);
280+
fabCustomGallery.startAnimation(fab_close);
281+
fabCamera.hide();
282+
fabGallery.hide();
283+
fabCustomGallery.hide();
284+
} else {
285+
fabPlus.startAnimation(rotate_forward);
286+
fabCamera.startAnimation(fab_open);
287+
fabGallery.startAnimation(fab_open);
288+
fabCustomGallery.startAnimation(fab_open);
289+
fabCamera.show();
290+
fabGallery.show();
291+
fabCustomGallery.show();
292+
}
293+
this.isFabOpen = !isFabOpen;
294+
}
294295
}
295-
}
296296

297297
/**
298298
* Shows welcome message if user has no contributions yet i.e. new user.

app/src/main/java/fr/free/nrw/commons/customselector/helper/ImageHelper.kt

+29-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlin.collections.ArrayList
1111
import kotlin.collections.LinkedHashMap
1212

1313
/**
14-
* Image Helper object, includes all the static functions required by custom selector
14+
* Image Helper object, includes all the static functions required by custom selector.
1515
*/
1616

1717
object ImageHelper {
@@ -49,6 +49,34 @@ object ImageHelper {
4949
return filteredImages
5050
}
5151

52+
/**
53+
* getIndex: Returns the index of image in given list.
54+
*/
55+
fun getIndex(list: ArrayList<Image>, image: Image): Int {
56+
return list.indexOf(image)
57+
}
58+
59+
/**
60+
* Gets the list of indices from the master list.
61+
*/
62+
fun getIndexList(list: ArrayList<Image>, masterList: ArrayList<Image>): ArrayList<Int> {
63+
64+
/**
65+
* TODO
66+
* Can be optimised as masterList is sorted by time.
67+
*/
68+
69+
val indexes = arrayListOf<Int>()
70+
for(image in list) {
71+
val index = getIndex(masterList,image)
72+
if (index == -1) {
73+
continue
74+
}
75+
indexes.add(index)
76+
}
77+
return indexes
78+
}
79+
5280
/**
5381
* Generates the file sha1 from file input stream.
5482
*/

app/src/main/java/fr/free/nrw/commons/customselector/ui/adapter/ImageAdapter.kt

+71-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import androidx.constraintlayout.widget.Group
1010
import androidx.recyclerview.widget.DiffUtil
1111
import androidx.recyclerview.widget.RecyclerView
1212
import com.bumptech.glide.Glide
13+
import fr.free.nrw.commons.customselector.helper.ImageHelper
1314
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
1415
import fr.free.nrw.commons.customselector.model.Image
1516

@@ -26,6 +27,16 @@ class ImageAdapter(
2627

2728
RecyclerViewAdapter<ImageAdapter.ImageViewHolder>(context) {
2829

30+
/**
31+
* ImageSelectedOrUpdated payload class.
32+
*/
33+
class ImageSelectedOrUpdated
34+
35+
/**
36+
* ImageUnselected payload class.
37+
*/
38+
class ImageUnselected
39+
2940
/**
3041
* Currently selected images.
3142
*/
@@ -49,18 +60,41 @@ class ImageAdapter(
4960
*/
5061
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
5162
val image=images[position]
52-
// todo load image thumbnail, set selected view.
63+
val selectedIndex = ImageHelper.getIndex(selectedImages,image)
64+
val isSelected = selectedIndex != -1
65+
if(isSelected){
66+
holder.itemSelected(selectedIndex+1)
67+
}
68+
else {
69+
holder.itemUnselected();
70+
}
5371
Glide.with(context).load(image.uri).into(holder.image)
5472
holder.itemView.setOnClickListener {
55-
selectOrRemoveImage(image, position)
73+
selectOrRemoveImage(holder, position)
5674
}
5775
}
5876

5977
/**
6078
* Handle click event on an image, update counter on images.
6179
*/
62-
private fun selectOrRemoveImage(image:Image, position:Int){
63-
// todo select the image if not selected and remove it if already selected
80+
private fun selectOrRemoveImage(holder:ImageViewHolder, position:Int){
81+
val clickedIndex = ImageHelper.getIndex(selectedImages,images[position])
82+
if (clickedIndex != -1) {
83+
selectedImages.removeAt(clickedIndex)
84+
notifyItemChanged(position,ImageUnselected())
85+
val indexes = ImageHelper.getIndexList(selectedImages, images)
86+
for (index in indexes) {
87+
notifyItemChanged(index, ImageSelectedOrUpdated())
88+
}
89+
} else {
90+
/**
91+
* TODO
92+
* Show toast on tapping an uploaded item.
93+
*/
94+
selectedImages.add(images[position])
95+
notifyItemChanged(position, ImageSelectedOrUpdated())
96+
}
97+
imageSelectListener.onSelectedImagesChanged(selectedImages)
6498
}
6599

66100
/**
@@ -90,9 +124,39 @@ class ImageAdapter(
90124
*/
91125
class ImageViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
92126
val image: ImageView = itemView.findViewById(R.id.image_thumbnail)
93-
val selectedNumber: TextView = itemView.findViewById(R.id.selected_count)
94-
val uploadedGroup: Group = itemView.findViewById(R.id.uploaded_group)
95-
val selectedGroup: Group = itemView.findViewById(R.id.selected_group)
127+
private val selectedNumber: TextView = itemView.findViewById(R.id.selected_count)
128+
private val uploadedGroup: Group = itemView.findViewById(R.id.uploaded_group)
129+
private val selectedGroup: Group = itemView.findViewById(R.id.selected_group)
130+
131+
/**
132+
* Item selected view.
133+
*/
134+
fun itemSelected(index: Int) {
135+
selectedGroup.visibility = View.VISIBLE
136+
selectedNumber.text = index.toString()
137+
}
138+
139+
/**
140+
* Item Unselected view.
141+
*/
142+
fun itemUnselected() {
143+
selectedGroup.visibility = View.GONE
144+
}
145+
146+
/**
147+
* Item Uploaded view.
148+
*/
149+
fun itemUploaded() {
150+
uploadedGroup.visibility = View.VISIBLE
151+
}
152+
153+
/**
154+
* Item Not Uploaded view.
155+
*/
156+
fun itemNotUploaded() {
157+
uploadedGroup.visibility = View.GONE
158+
}
159+
96160
}
97161

98162
/**

app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorActivity.kt

+40-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fr.free.nrw.commons.customselector.ui.selector
22

3+
import android.app.Activity
4+
import android.content.Intent
35
import android.os.Bundle
46
import android.widget.ImageButton
57
import android.widget.TextView
@@ -10,6 +12,7 @@ import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
1012
import fr.free.nrw.commons.customselector.model.Folder
1113
import fr.free.nrw.commons.customselector.model.Image
1214
import fr.free.nrw.commons.theme.BaseActivity
15+
import java.io.File
1316
import javax.inject.Inject
1417

1518
class CustomSelectorActivity : BaseActivity(), FolderClickListener, ImageSelectListener {
@@ -73,7 +76,8 @@ class CustomSelectorActivity : BaseActivity(), FolderClickListener, ImageSelectL
7376
val back : ImageButton = findViewById(R.id.back)
7477
back.setOnClickListener { onBackPressed() }
7578

76-
// todo done listener.
79+
val done : ImageButton = findViewById(R.id.done)
80+
done.setOnClickListener { onDone() }
7781
}
7882

7983
/**
@@ -91,9 +95,44 @@ class CustomSelectorActivity : BaseActivity(), FolderClickListener, ImageSelectL
9195
* override Selected Images Change, update view model selected images.
9296
*/
9397
override fun onSelectedImagesChanged(selectedImages: ArrayList<Image>) {
98+
viewModel.selectedImages.value = selectedImages
9499
// todo update selected images in view model.
95100
}
96101

102+
/**
103+
* OnDone clicked.
104+
* Get the selected images. Remove any non existent file, forward the data to finish selector.
105+
*/
106+
fun onDone() {
107+
val selectedImages = viewModel.selectedImages.value
108+
if(selectedImages.isNullOrEmpty()) {
109+
finishPickImages(arrayListOf())
110+
return
111+
}
112+
var i = 0
113+
while (i < selectedImages.size) {
114+
val path = selectedImages[i].path
115+
val file = File(path)
116+
if (!file.exists()) {
117+
selectedImages.removeAt(i)
118+
i--
119+
}
120+
i++
121+
}
122+
finishPickImages(selectedImages)
123+
}
124+
125+
/**
126+
* finishPickImages, Load the data to the intent and set result.
127+
* Finish the activity.
128+
*/
129+
private fun finishPickImages(images: ArrayList<Image>) {
130+
val data = Intent()
131+
data.putParcelableArrayListExtra("Images", images)
132+
setResult(Activity.RESULT_OK, data)
133+
finish()
134+
}
135+
97136
/**
98137
* Back pressed.
99138
* Change toolbar title.
@@ -106,16 +145,4 @@ class CustomSelectorActivity : BaseActivity(), FolderClickListener, ImageSelectL
106145
}
107146
}
108147

109-
110-
/**
111-
*
112-
* TODO
113-
* Permission check.
114-
* OnDone
115-
* Activity Result.
116-
*
117-
*
118-
*/
119-
120-
121148
}

app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/CustomSelectorViewModel.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package fr.free.nrw.commons.customselector.ui.selector
22

33
import android.content.Context
4-
import android.util.Log
54
import androidx.lifecycle.MutableLiveData
65
import androidx.lifecycle.ViewModel
76
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
@@ -14,10 +13,18 @@ import kotlinx.coroutines.cancel
1413

1514
class CustomSelectorViewModel(var context: Context,var imageFileLoader: ImageFileLoader) : ViewModel() {
1615

16+
/**
17+
* Scope for coroutine task (image fetch).
18+
*/
1719
private val scope = CoroutineScope(Dispatchers.Main)
1820

1921
/**
20-
* Result Live Data
22+
* Stores selected images.
23+
*/
24+
var selectedImages: MutableLiveData<ArrayList<Image>> = MutableLiveData()
25+
26+
/**
27+
* Result Live Data.
2128
*/
2229
val result = MutableLiveData(Result(CallbackStatus.IDLE, arrayListOf()))
2330

app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
public class DBOpenHelper extends SQLiteOpenHelper {
1414

1515
private static final String DATABASE_NAME = "commons.db";
16-
private static final int DATABASE_VERSION = 15;
16+
private static final int DATABASE_VERSION = 14;
1717
public static final String CONTRIBUTIONS_TABLE = "contributions";
1818
private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s";
1919

app/src/main/java/fr/free/nrw/commons/filepicker/Constants.java

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface RequestCodes {
1010
int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876
1111
int SOURCE_CHOOSER = 1 << 15;
1212

13+
int PICK_PICTURE_FROM_CUSTOM_SELECTOR = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 10);
1314
int PICK_PICTURE_FROM_DOCUMENTS = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 11);
1415
int PICK_PICTURE_FROM_GALLERY = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 12);
1516
int TAKE_PICTURE = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 13);

0 commit comments

Comments
 (0)