[GSoC] Custom Selector Tests (#4494)

* Localisation updates from https://translatewiki.net.

* Fixes #4357  After switching to different account, contributions screen shows pictures of previous account (#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 b1b4257f20.

Co-authored-by: Obsidian_zero <1198474846@qq.com>

* Remove unnecessary whitespace from a message (#4439)

* Merge v3.0.1 into master (#4446)

* Versioning and changelog for v3.0.0 (#4152)

* Versioning for v3.0.0

* Update changelog.md

* Handled migration 8-9-10 in BookmarksLocationDao (#4154)

* #Fixes #4141
- Handled migrations for BookmarkLocationsDao from 8-9-10

* #Fixes #4141
- Handled migrations for BookmarkLocationsDao from 8-9-10

* Fixes #4179 (#4180)

* Handled null pointer exception in MainActivity->ContributionsFragment#backButtonClicked()
* Updated >ContributionsFragment#backButtonClicked() to handle back press properly

* Fixes #4179 (#4181)

* Handled possible null check on MediaDetails in BookmarkListRootFragment#backPressed()

* Cherrypick for hotfix3.1 (#4205)

* Fixes #4159 On Explore Tab, All Available Options on toolbar in media detail view are only targeting the first media in the list.

Fixes #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 #4132 (#4146)

* fixed bug:app crashes on viewing review in Review Fragment #4135

* Fixed the issue with back button in contribution tab. (#4177)

Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com>

* Fixed the issue with back navigation button on toolbar in explore tab. (#4175)

* Fix (#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 #4173 (#4396)

* Fix #4147  Pre-fill desc in Nearby uploads with Wikidata item's label + description (#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 (#4354)

* Remove nonexistent method

* Fix #4283 IllegalStateException (#4440)

* Fix #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 a feature for editing coordinates (#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. (#4451)

* Localisation updates from https://translatewiki.net.

* Fixes 4344 - Duplicate Uploads (#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

* Fixes #3694 Pre-select places as depictions (#4452)

* WikidataEditService: stop automatically adding WikidataPlace as a depiction

When the user initiates the upload process from Nearby and also manually adds the place as a depiction, the depiction is added twice. Since this behavior is invisible to the user, it is being removed in preparation for auto-selecting the place as a depiction on the DepictsFragment screen.

* DepictsFragment: auto-select place as a depiction

Pass the Place reference from UploadActivity to DepictsFragment and select the corresponding DepictedItem. Using the place id, retrieve the corresponding Entity to create and select a DepictedItem.

* UploadRepository: use Place from UploadItem to obtain a DepictedItem

Instead of passing a Place object from UploadActivity to DepictsFragment and then passing the Place object up the chain to obtain and select a DepictedItem, retrieve the Place object directly within UploadRepository

* DepictsFragment: select Place depiction when fragment becomes visible

* UploadDepictsAdapter: make adapter aware of selection state

Update selection state when recycled list items are automatically selected, preventing automatically selected items from appearing as unselected until they are forced to re-bind (i.e. after scrolling)

* DepictsFragment: pre-select place depictions for all UploadItems

If several images are selected and set to different places, pre-select all place depictions to reinforce the intended upload workflow philosophy (i.e. all images in a set are intended to be from/of the same place). See discussion in commons-app/apps-android-commons#3694

* DepictsFragment: scroll to the top every time list is updated

* Typo fixes (#4461)

* Fixed typo on class documentation of TextUtils

* corrected comma placement in documentation

* Fixed typos in comments

* fix-issue-4424 (#4445)

Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com>

* fix edit categories ui (#4414)

Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com>

* Fix doom version issue (#4463)

* Update db version

* DBOpenHelper version update

* fix :Back Pressed Event not work in Explore tab when user not login (#4404)

* fix :Back Pressed Event not work in Explore tab

* minor changes

* fix :Upload count or number of contribution does not get updated when media  is successful uploaded (#4399)

* * fix:Number of Contributions not updated
 * Add javadocs

* minor changes

* made minor changes

* String was nonsense and untranslatible, fixed (#4466)

* Ability to show captions and descriptions in all entered languages (#4355)

* implement Ability to show captions and descriptions in all entered languages
*Add Javadoc

* handle Back event of fragment(mediaDetailFragment)

* fix minor bugs

* add internationalization

* revert previous changes

* fix visibility bug

* resolve conflict

* Fixes #4437 - Changed indentation on files with 2 spaces to 4 spaces (#4462)

* Edited Project.xml to make indent size 4

* Changed files with 2 space indentation to use 4 space indentation

* Edited Project.xml to make indent size 4

* changed files with 2 space indent to 4 space indent

* fix :Back Pressed Event not work in Explore tab when user not login (#4404)

* fix :Back Pressed Event not work in Explore tab

* minor changes

* fix :Upload count or number of contribution does not get updated when media  is successful uploaded (#4399)

* * fix:Number of Contributions not updated
 * Add javadocs

* minor changes

* made minor changes

* String was nonsense and untranslatible, fixed (#4466)

* Ability to show captions and descriptions in all entered languages (#4355)

* implement Ability to show captions and descriptions in all entered languages
*Add Javadoc

* handle Back event of fragment(mediaDetailFragment)

* fix minor bugs

* add internationalization

* revert previous changes

* fix visibility bug

* resolve conflict

Co-authored-by: Prince kushwaha <65972015+Prince-kushwaha@users.noreply.github.com>
Co-authored-by: neslihanturan <tur.neslihan@gmail.com>

* Use more understandable strings (#4470)

* Fix #3792 Missing Column Issue (#4468)

* Fix Missing Column Issue

* Fix tests

* Add UploadCategoriesFragment Unit Tests (#4473)

* Panorama (#4467)

* panoramic images fixed

* made requested changes

* Minor refactoring

Co-authored-by: Aditya Srivastava <iamaditya2009@gmail.com>

* Localisation updates from https://translatewiki.net.

* Main activity title is sometimes "Contributions", sometimes "Commons" (#4472)

Fixes #4438  Replace == with equals() in onRestoreInstanceState

* Localisation updates from https://translatewiki.net.

* caption and description copyable (#4481)

* Removed next button in quiz (#4382)

* issues resolved

* modification done

* warning fixed

* issues resolved

* Button added

* don't know function added

* Button added

* modification done

* modification done

* Localisation updates from https://translatewiki.net.

* Added option to show and modify location while uploading (#4475)

* initial commit

* Everything done

* minor modification

* minor modification

* Issues fixed

* minor modifications

* issue fixed

* Issues fixed

* Tutorial removed from log out state (#4479)

* tutorial removed from log out state

* Issue removed

* Update changelog.md

* Versioning for v3.0.2

* Fix #4482 (#4484)

* Fix crash when image resolution is very high (#4483)

* Localisation updates from https://translatewiki.net.

* Add Contributions Fragment Unit Tests (#4490)

* Fix Tests Errors (#4491)

* Add UploadMediaDetailFragment Unit Tests (#4492)

* Localisation updates from https://translatewiki.net.

* Folder Fragment test

* Folder Fragment test done

* Initialised xmls, made folder and image item.

* xmls done

* xmls completed

* removed unwanted attribute

* Created models, adapters and view models (#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

* [GSOC] Added Image Fetch (#4449)

* Added basic Fetch

* added permission request

* Folder count rectified

* Loaded thumbnail

* disabled overlay

* Added sha1 function

* Documented the code

* [GSoC] Image Selection (#4457)

* Localisation updates from https://translatewiki.net.

* Fixes #4357  After switching to different account, contributions screen shows pictures of previous account (#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 b1b4257f20.

Co-authored-by: Obsidian_zero <1198474846@qq.com>

* Remove unnecessary whitespace from a message (#4439)

* Merge v3.0.1 into master (#4446)

* Versioning and changelog for v3.0.0 (#4152)

* Versioning for v3.0.0

* Update changelog.md

* Handled migration 8-9-10 in BookmarksLocationDao (#4154)

* #Fixes #4141
- Handled migrations for BookmarkLocationsDao from 8-9-10

* #Fixes #4141
- Handled migrations for BookmarkLocationsDao from 8-9-10

* Fixes #4179 (#4180)

* Handled null pointer exception in MainActivity->ContributionsFragment#backButtonClicked()
* Updated >ContributionsFragment#backButtonClicked() to handle back press properly

* Fixes #4179 (#4181)

* Handled possible null check on MediaDetails in BookmarkListRootFragment#backPressed()

* Cherrypick for hotfix3.1 (#4205)

* Fixes #4159 On Explore Tab, All Available Options on toolbar in media detail view are only targeting the first media in the list.

Fixes #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 #4132 (#4146)

* fixed bug:app crashes on viewing review in Review Fragment #4135

* Fixed the issue with back button in contribution tab. (#4177)

Co-authored-by: Pratham2305 <Pratham2305@users.noreply.github.com>

* Fixed the issue with back navigation button on toolbar in explore tab. (#4175)

* Fix (#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 #4173 (#4396)

* Fix #4147  Pre-fill desc in Nearby uploads with Wikidata item's label + description (#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 (#4354)

* Remove nonexistent method

* Fix #4283 IllegalStateException (#4440)

* Fix #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 (#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. (#4451)

* Localisation updates from https://translatewiki.net.

* Fixes 4344 - Duplicate Uploads (#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 (#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 (#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>

* [GSoC] Show uploaded images differently. (#4464)

* uploaded images shown differently

* Loaded images before query

* Handled exceptions, Made ImageLoader injectable, Document and clean code

* [GSoC] Added Uploaded status table in room database. (#4476)

* added Uploaded status table in room database

* Added unique property, minor refractoring

* Database intigrated

* Database integrated

* Handled result null exception

* Exceptions handled and refractored

* Introduced constants

* moved to sealed class

* No database insert on network error

* queried original image

* documented the code

* Updated uploaded status on upload success

* Image Helper test (#4485)

* [GSoC] Adapter Tests (#4488)

* Added FolderAdapterTest

* Image Adapter Test

* Folder Fragment test

* Folder Fragment test done

* Fragment test complete

* Added Custom Selector View Model Test

* ImageFileLoaderTest

* Update strings.xml

* Custom Selector Activiy test

* Image Loader Test

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>
Co-authored-by: Brigham Byerly <6891883+byerlyb20@users.noreply.github.com>
Co-authored-by: Jamie Brown <jamiejbrown521@gmail.com>
Co-authored-by: Prince kushwaha <65972015+Prince-kushwaha@users.noreply.github.com>
Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
Co-authored-by: Ashar <asharalikhan200@gmail.com>
This commit is contained in:
Aditya-Srivastav 2021-07-18 05:47:01 +05:30 committed by Aditya Srivastava
parent 86ee96ccdd
commit 732b343b89
11 changed files with 786 additions and 11 deletions

View file

@ -4,9 +4,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import fr.free.nrw.commons.R
import fr.free.nrw.commons.customselector.helper.ImageHelper
import fr.free.nrw.commons.customselector.model.Result
@ -16,7 +18,6 @@ import fr.free.nrw.commons.customselector.ui.adapter.FolderAdapter
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.upload.FileProcessor
import kotlinx.android.synthetic.main.fragment_custom_selector.*
import kotlinx.android.synthetic.main.fragment_custom_selector.view.*
import javax.inject.Inject
@ -27,6 +28,12 @@ class FolderFragment : CommonsDaggerSupportFragment() {
*/
private var viewModel: CustomSelectorViewModel? = null
/**
* View Elements
*/
private var selectorRV: RecyclerView? = null
private var loader: ProgressBar? = null
/**
* View Model Factory.
*/
@ -75,6 +82,8 @@ class FolderFragment : CommonsDaggerSupportFragment() {
val root = inflater.inflate(R.layout.fragment_custom_selector, container, false)
folderAdapter = FolderAdapter(activity!!, activity as FolderClickListener)
gridLayoutManager = GridLayoutManager(context, columnCount())
selectorRV = root.selector_rv
loader = root.loader
with(root.selector_rv){
this.layoutManager = gridLayoutManager
setHasFixedSize(true)
@ -96,9 +105,13 @@ class FolderFragment : CommonsDaggerSupportFragment() {
val folders = ImageHelper.folderListFromImages(result.images)
folderAdapter.init(folders)
folderAdapter.notifyDataSetChanged()
selector_rv.visibility = View.VISIBLE
selectorRV?.let {
it.visibility = View.VISIBLE
}
}
loader?.let {
it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
}
loader.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
}
/**

View file

@ -4,9 +4,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import fr.free.nrw.commons.R
import fr.free.nrw.commons.customselector.helper.ImageHelper
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
@ -28,7 +30,13 @@ class ImageFragment: CommonsDaggerSupportFragment() {
/**
* View model for images.
*/
private lateinit var viewModel: CustomSelectorViewModel
private var viewModel: CustomSelectorViewModel? = null
/**
* View Elements
*/
private var selectorRV: RecyclerView? = null
private var loader: ProgressBar? = null
/**
* View model Factory.
@ -98,10 +106,13 @@ class ImageFragment: CommonsDaggerSupportFragment() {
this.adapter = imageAdapter
}
viewModel.result.observe(viewLifecycleOwner, Observer{
viewModel?.result?.observe(viewLifecycleOwner, Observer{
handleResult(it)
})
selectorRV = root.selector_rv
loader = root.loader
return root
}
@ -113,13 +124,19 @@ class ImageFragment: CommonsDaggerSupportFragment() {
val images = result.images
if(images.isNotEmpty()) {
imageAdapter.init(ImageHelper.filterImages(images,bucketId))
selector_rv.visibility = View.VISIBLE
selectorRV?.let{
it.visibility = View.VISIBLE
}
}
else{
selector_rv.visibility = View.GONE
selectorRV?.let{
it.visibility = View.GONE
}
}
}
loader.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
loader?.let {
it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
}
}
/**

View file

@ -19,6 +19,7 @@ import timber.log.Timber
import java.io.IOException
import java.net.UnknownHostException
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.collections.HashMap
@ -179,7 +180,8 @@ class ImageLoader @Inject constructor(
return Result.TRUE
} else {
uploadedStatus.lastUpdated?.let {
if (it.date >= Calendar.getInstance().time.date - INVALIDATE_DAY_COUNT) {
val duration = Calendar.getInstance().time.time - it.time
if (TimeUnit.MILLISECONDS.toDays(duration) < INVALIDATE_DAY_COUNT) {
return Result.FALSE
}
}
@ -218,7 +220,7 @@ class ImageLoader @Inject constructor(
}
companion object {
const val INVALIDATE_DAY_COUNT: Int = 7
const val INVALIDATE_DAY_COUNT: Long = 7
}
}

View file

@ -40,7 +40,7 @@ public class ExploreListRootFragment extends CommonsDaggerSupportFragment implem
featuredArguments.putString("categoryName", title);
listFragment.setArguments(featuredArguments);
}
@Nullable
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,

View file

@ -0,0 +1,96 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.net.Uri
import android.os.Bundle
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.customselector.model.Folder
import fr.free.nrw.commons.customselector.model.Image
import org.junit.Before
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
/**
* Custom Selector Activity Test
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
class CustomSelectorActivityTest {
private lateinit var activity: CustomSelectorActivity
/**
* Set up the tests.
*/
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
activity = Robolectric.buildActivity(CustomSelectorActivity::class.java)
.get()
val onCreate = activity.javaClass.getDeclaredMethod("onCreate", Bundle::class.java)
onCreate.isAccessible = true
onCreate.invoke(activity, null)
}
/**
* Test activity not null.
*/
@Test
@Throws(Exception::class)
fun testActivityNotNull() {
assertNotNull(activity)
}
/**
* Test changeTitle function.
*/
@Test
@Throws(Exception::class)
fun testChangeTitle() {
val func = activity.javaClass.getDeclaredMethod("changeTitle", String::class.java)
func.isAccessible = true
func.invoke(activity, "test")
}
/**
* Test onFolderClick function.
*/
@Test
@Throws(Exception::class)
fun testOnFolderClick() {
activity.onFolderClick(Folder(1, "test", arrayListOf()));
}
/**
* Test selectedImagesChanged function.
*/
@Test
@Throws(Exception::class)
fun testOnSelectedImagesChanged() {
activity.onSelectedImagesChanged(ArrayList())
}
/**
* Test onDone function.
*/
@Test
@Throws(Exception::class)
fun testOnDone() {
activity.onDone()
activity.onSelectedImagesChanged(ArrayList(arrayListOf(Image(1, "test", Uri.parse("test"), "test", 1))));
activity.onDone()
}
/**
* Test onBackPressed Function.
*/
@Test
@Throws(Exception::class)
fun testOnBackPressed() {
activity.onBackPressed()
}
}

View file

@ -0,0 +1,41 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.content.Context
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
/**
* Custom Selector View Model test.
*/
class CustomSelectorViewModelTest {
private lateinit var viewModel: CustomSelectorViewModel
@Mock
private lateinit var imageFileLoader: ImageFileLoader
@Mock
private lateinit var context: Context
/**
* Set up the test.
*/
@Before
fun setUp(){
MockitoAnnotations.initMocks(this)
viewModel = CustomSelectorViewModel(context, imageFileLoader);
}
/**
* Test onCleared();
*/
@Test
fun testOnCleared(){
val func = viewModel.javaClass.getDeclaredMethod("onCleared")
func.isAccessible = true
func.invoke(viewModel);
}
}

View file

@ -0,0 +1,130 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.content.Context
import android.os.Bundle
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import fr.free.nrw.commons.customselector.model.Result
import android.widget.ProgressBar
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.soloader.SoLoader
import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.customselector.model.CallbackStatus
import fr.free.nrw.commons.customselector.ui.adapter.FolderAdapter
import org.junit.Before
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import org.wikipedia.AppAdapter
import java.lang.reflect.Field
/**
* Custom Selector Folder Fragment Test.
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED)
class FolderFragmentTest {
private lateinit var fragment: FolderFragment
private lateinit var view: View
private lateinit var selectorRV : RecyclerView
private lateinit var loader : ProgressBar
private lateinit var layoutInflater: LayoutInflater
private lateinit var context: Context
private lateinit var viewModelField:Field
@Mock
private lateinit var adapter: FolderAdapter
@Mock
private lateinit var savedInstanceState: Bundle
/**
* Setup the folder fragment.
*/
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
context = RuntimeEnvironment.application.applicationContext
AppAdapter.set(TestAppAdapter())
SoLoader.setInTestMode()
Fresco.initialize(context)
val activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get()
fragment = FolderFragment.newInstance()
val fragmentManager: FragmentManager = activity.supportFragmentManager
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(fragment, null)
fragmentTransaction.commit()
layoutInflater = LayoutInflater.from(activity)
view = layoutInflater.inflate(R.layout.fragment_custom_selector, null) as View
selectorRV = view.findViewById(R.id.selector_rv)
loader = view.findViewById(R.id.loader)
Whitebox.setInternalState(fragment, "folderAdapter", adapter)
Whitebox.setInternalState(fragment, "selectorRV", selectorRV )
Whitebox.setInternalState(fragment, "loader", loader)
viewModelField = fragment.javaClass.getDeclaredField("viewModel")
viewModelField.isAccessible = true
}
/**
* Test onCreateView
*/
@Test
@Throws(Exception::class)
fun testOnCreateView() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
viewModelField.set(fragment, null)
fragment.onCreateView(layoutInflater, null, savedInstanceState)
}
/**
* Test onCreate
*/
@Test
@Throws(Exception::class)
fun testOnCreate() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.onCreate(savedInstanceState)
}
/**
* Test columnCount.
*/
@Test
fun testColumnCount() {
val func = fragment.javaClass.getDeclaredMethod("columnCount")
func.isAccessible = true
assertEquals(2, func.invoke(fragment))
}
/**
* Test handleResult.
*/
@Test
fun testHandleResult() {
val func = fragment.javaClass.getDeclaredMethod("handleResult", Result::class.java)
func.isAccessible = true
func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf()))
}
}

View file

@ -0,0 +1,123 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.content.ContentResolver
import android.content.Context
import android.provider.MediaStore
import com.nhaarman.mockitokotlin2.anyOrNull
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.same
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.customselector.listeners.ImageLoaderListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import org.robolectric.fakes.RoboCursor
import java.io.File
import kotlin.coroutines.CoroutineContext
/**
* Custom Selector Image File loader test.
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED)
class ImageFileLoaderTest {
@Mock
private lateinit var mockContentResolver: ContentResolver
@Mock
private lateinit var context: Context;
@Mock
private lateinit var imageLoaderListener: ImageLoaderListener
@Mock
private lateinit var coroutineScope: CoroutineScope
private lateinit var imageCursor: RoboCursor
private lateinit var coroutineContext: CoroutineContext
private lateinit var projection: List<String>
private lateinit var imageFileLoader: ImageFileLoader
/**
* Setup before tests.
*/
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
coroutineContext = Dispatchers.Main
imageCursor = RoboCursor()
imageFileLoader = ImageFileLoader(context)
projection = listOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME
)
Whitebox.setInternalState(imageFileLoader, "coroutineContext", coroutineContext)
}
/**
* Test loading device images.
*/
@Test
fun testLoadDeviceImages() {
imageFileLoader.loadDeviceImages(imageLoaderListener, coroutineScope)
}
/**
* Test get images from the device function.
*/
@Test
fun testGetImages() {
val func = imageFileLoader.javaClass.getDeclaredMethod(
"getImages",
ImageLoaderListener::class.java
)
func.isAccessible = true
val image1 = arrayOf(1, "imageLoaderTestFile", "src/test/resources/imageLoaderTestFile", 1, "downloads")
val image2 = arrayOf(2, "imageLoaderTestFile", null, 1, "downloads")
File("src/test/resources/imageLoaderTestFile").createNewFile()
imageCursor.setColumnNames(projection)
imageCursor.setResults(arrayOf(image1, image2));
val contentResolver: ContentResolver = mock {
on {
query(
same(MediaStore.Images.Media.EXTERNAL_CONTENT_URI),
anyOrNull(),
anyOrNull(),
anyOrNull(),
anyOrNull()
)
} doReturn imageCursor;
}
// test null cursor.
`when`(
context.contentResolver
).thenReturn(mockContentResolver)
func.invoke(imageFileLoader, imageLoaderListener);
// test demo cursor.
`when`(
context.contentResolver
).thenReturn(contentResolver)
func.invoke(imageFileLoader, imageLoaderListener);
}
}

View file

@ -0,0 +1,135 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.content.Context
import android.os.Bundle
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.widget.ProgressBar
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.soloader.SoLoader
import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestAppAdapter
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.customselector.model.CallbackStatus
import fr.free.nrw.commons.customselector.model.Image
import fr.free.nrw.commons.customselector.model.Result
import fr.free.nrw.commons.customselector.ui.adapter.ImageAdapter
import org.junit.Before
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.powermock.reflect.Whitebox
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import org.wikipedia.AppAdapter
import java.lang.reflect.Field
/**
* Custom Selector Image Fragment Test.
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
@LooperMode(LooperMode.Mode.PAUSED)
class ImageFragmentTest {
private lateinit var fragment: ImageFragment
private lateinit var view: View
private lateinit var selectorRV : RecyclerView
private lateinit var loader : ProgressBar
private lateinit var layoutInflater: LayoutInflater
private lateinit var context: Context
private lateinit var viewModelField: Field
@Mock
private lateinit var image: Image
@Mock
private lateinit var adapter: ImageAdapter
@Mock
private lateinit var savedInstanceState: Bundle
/**
* Setup the image fragment.
*/
@Before
fun setUp(){
MockitoAnnotations.initMocks(this)
context = RuntimeEnvironment.application.applicationContext
AppAdapter.set(TestAppAdapter())
SoLoader.setInTestMode()
Fresco.initialize(context)
val activity = Robolectric.buildActivity(CustomSelectorActivity::class.java).create().get()
fragment = ImageFragment.newInstance(1)
val fragmentManager: FragmentManager = activity.supportFragmentManager
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(fragment, null)
fragmentTransaction.commit()
layoutInflater = LayoutInflater.from(activity)
view = layoutInflater.inflate(R.layout.fragment_custom_selector, null, false) as View
selectorRV = view.findViewById(R.id.selector_rv)
loader = view.findViewById(R.id.loader)
Whitebox.setInternalState(fragment, "imageAdapter", adapter)
Whitebox.setInternalState(fragment, "selectorRV", selectorRV )
Whitebox.setInternalState(fragment, "loader", loader)
viewModelField = fragment.javaClass.getDeclaredField("viewModel")
viewModelField.isAccessible = true
}
/**
* Test onCreate
*/
@Test
@Throws(Exception::class)
fun testOnCreate(){
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.onCreate(savedInstanceState);
}
/**
* Test onCreateView
*/
@Test
@Throws(Exception::class)
fun testOnCreateView() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
viewModelField.set(fragment, null)
fragment.onCreateView(layoutInflater, null, savedInstanceState)
}
/**
* Test handleResult.
*/
@Test
fun testHandleResult(){
val func = fragment.javaClass.getDeclaredMethod("handleResult", Result::class.java)
func.isAccessible = true
func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf()))
func.invoke(fragment, Result(CallbackStatus.SUCCESS, arrayListOf(image,image)))
}
/**
* Test getSpanCount.
*/
@Test
fun testGetSpanCount() {
val func = fragment.javaClass.getDeclaredMethod("getSpanCount")
func.isAccessible = true
assertEquals(3, func.invoke(fragment))
}
}

View file

@ -0,0 +1,218 @@
package fr.free.nrw.commons.customselector.ui.selector
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.TestCommonsApplication
import fr.free.nrw.commons.customselector.database.UploadedStatus
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
import fr.free.nrw.commons.customselector.model.Image
import fr.free.nrw.commons.customselector.ui.adapter.ImageAdapter
import fr.free.nrw.commons.filepicker.PickedFiles
import fr.free.nrw.commons.filepicker.UploadableFile
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.upload.FileProcessor
import fr.free.nrw.commons.upload.FileUtilsWrapper
import io.reactivex.Single
import junit.framework.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.*
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.reflect.Whitebox
import org.robolectric.annotation.Config
import java.io.File
import java.io.FileInputStream
import java.lang.Exception
import java.util.*
import kotlin.collections.HashMap
/**
* Image Loader Test.
*/
@RunWith(PowerMockRunner::class)
@PrepareForTest(PickedFiles::class)
@Config(sdk = [21], application = TestCommonsApplication::class)
class ImageLoaderTest {
@Mock
private lateinit var uri:Uri
@Mock
private lateinit var mediaClient: MediaClient
@Mock
private lateinit var single: Single<Boolean>
@Mock
private lateinit var fileProcessor: FileProcessor
@Mock
private lateinit var fileUtilsWrapper: FileUtilsWrapper
@Mock
private lateinit var uploadedStatusDao: UploadedStatusDao
@Mock
private lateinit var holder: ImageAdapter.ImageViewHolder
@Mock
private lateinit var context: Context
@Mock
private lateinit var uploadableFile: UploadableFile
@Mock
private lateinit var inputStream: FileInputStream
@Mock
private lateinit var contentResolver: ContentResolver
@Mock
private lateinit var image: Image;
private lateinit var imageLoader: ImageLoader;
private var mapImageSHA1: HashMap<Image, String> = HashMap()
private var mapHolderImage : HashMap<ImageAdapter.ImageViewHolder, Image> = HashMap()
private var mapResult: HashMap<String, ImageLoader.Result> = HashMap()
/**
* Setup before test.
*/
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
imageLoader =
ImageLoader(mediaClient, fileProcessor, fileUtilsWrapper, uploadedStatusDao, context)
Whitebox.setInternalState(imageLoader, "mapImageSHA1", mapImageSHA1);
Whitebox.setInternalState(imageLoader, "mapHolderImage", mapHolderImage);
Whitebox.setInternalState(imageLoader, "mapResult", mapResult);
Whitebox.setInternalState(imageLoader, "context", context)
}
/**
* Test queryAndSetView.
*/
@Test
fun testQueryAndSetView(){
// TODO
imageLoader.queryAndSetView(holder,image)
}
/**
* Test querySha1
*/
@Test
fun testQuerySha1() {
val func = imageLoader.javaClass.getDeclaredMethod(
"querySHA1",
String::class.java
)
func.isAccessible = true
Mockito.`when`(single.blockingGet()).thenReturn(true)
Mockito.`when`(mediaClient.checkFileExistsUsingSha("testSha1")).thenReturn(single)
Mockito.`when`(fileUtilsWrapper.getSHA1(any())).thenReturn("testSha1")
// test without saving in map.
func.invoke(imageLoader, "testSha1");
// test with map save.
mapResult["testSha1"] = ImageLoader.Result.FALSE
func.invoke(imageLoader, "testSha1");
}
/**
* Test getSha1
*/
@Test
@Throws (Exception::class)
fun testGetSha1() {
val func = imageLoader.javaClass.getDeclaredMethod(
"getSHA1",
Image::class.java
)
func.isAccessible = true
PowerMockito.mockStatic(PickedFiles::class.java);
BDDMockito.given(PickedFiles.pickedExistingPicture(context, image.uri))
.willReturn(UploadableFile(uri, File("ABC")));
whenever(fileUtilsWrapper.getFileInputStream("ABC")).thenReturn(inputStream)
whenever(fileUtilsWrapper.getSHA1(inputStream)).thenReturn("testSha1")
Assert.assertEquals("testSha1", func.invoke(imageLoader, image));
whenever(PickedFiles.pickedExistingPicture(context,Uri.parse("test"))).thenReturn(uploadableFile)
mapImageSHA1[image] = "testSha2"
Assert.assertEquals("testSha2", func.invoke(imageLoader, image));
}
/**
* Test insertIntoUploaded Function.
*/
@Test
@Throws (Exception::class)
fun testInsertIntoUploaded() {
val func = imageLoader.javaClass.getDeclaredMethod(
"insertIntoUploaded",
String::class.java,
String::class.java,
Boolean::class.java,
Boolean::class.java)
func.isAccessible = true
func.invoke(imageLoader, "", "", true, true)
}
/**
* Test getImageSha1.
*/
@Test
@Throws (Exception::class)
fun testGetImageSHA1() {
val func = imageLoader.javaClass.getDeclaredMethod(
"getImageSHA1",
Uri::class.java)
func.isAccessible = true
whenever(contentResolver.openInputStream(uri)).thenReturn(inputStream)
whenever(context.contentResolver).thenReturn(contentResolver)
whenever(fileUtilsWrapper.getSHA1(inputStream)).thenReturn("testSha1")
Assert.assertEquals("testSha1", func.invoke(imageLoader,uri))
}
/**
* Test getResultFromUploadedStatus.
*/
@Test
@Throws (Exception::class)
fun testGetResultFromUploadedStatus() {
val func = imageLoader.javaClass.getDeclaredMethod(
"getResultFromUploadedStatus",
UploadedStatus::class.java)
func.isAccessible = true
// test Result.TRUE
Assert.assertEquals(ImageLoader.Result.TRUE,
func.invoke(imageLoader,
UploadedStatus("", "", true, true)))
// test Result.FALSE
Assert.assertEquals(ImageLoader.Result.FALSE,
func.invoke(imageLoader,
UploadedStatus("", "", false, false, Calendar.getInstance().time)))
// test Result.INVALID
Assert.assertEquals(ImageLoader.Result.INVALID,
func.invoke(imageLoader, UploadedStatus("", "", false, false, Date(0))))
}
}