Issue-5662-kotlinstyle (#5833)

* *.kt: bulk correction of formatting using ktlint --format

* *.kt: replace wildcard imports and second stage auto format ktlint --format

* QuizQuestionTest.kt: modified property names to camel case to meet ktlint standard

* LevelControllerTest.kt: modified property names to camel case to meet ktlint standard

* QuizActivityUnitTest.kt: modified property names to camel case to meet ktlint standard

* MediaDetailFragmentUnitTests.kt: modified property names to camel case to meet ktlint standard

* UploadWorker.kt: modified property names to camel case to meet ktlint standard

* UploadClient.kt: modified property names to camel case to meet ktlint standard

* BasePagingPresenter.kt: modified property names to camel case to meet ktlint standard

* DescriptionEditActivity.kt: modified property names to camel case to meet ktlint standard

* OnSwipeTouchListener.kt: modified property names to camel case to meet ktlint standard

* MediaDetailFragmentUnitTests.kt: corrected excessive line length to meet ktlint standard

* DepictedItem.kt: corrected property name format and catch format to for  ktlint standard

* UploadCategoryAdapter.kt: corrected class definition format to meet ktlint standard

* CustomSelectorActivity.kt: reformatted function names to first letter lowercase to meet ktlint standard

* MediaDetailFragmentUnitTests.kt: fix string literal indentation to meet ktlint standard

* NotForUploadDao.kt: file renamed to match class name, new file NotForUploadStatusDao.kt

* UploadedDao.kt: file renamed to match class name, new file UploadedStatusDao.kt

* Urls.kt: fixed excessive line length for ktLint standard

* Snak_partial.kt & Statement_partial.kt: refactored to remove underscores in class names to meet ktLint standard

* *.kt: fixed consecutive KDOC error for ktLint

* PageableBaseDataSourceTest.kt & UploadPresenterTest.kt: fixed excessive line lengths to meet ktLint standard

* CheckboxTriStatesTest.kt: renamed file to match class name to meet ktLint standard

* .kt: resolved backing-property-naming error in ktLint, made matching properties public, matched names and refactored

* TestConnectionFactory.kt: fixed property naming to adhere to ktLint standard
This commit is contained in:
tristan 2024-09-19 14:56:45 +10:00 committed by GitHub
parent 950539c55c
commit 2d82a430c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
405 changed files with 11032 additions and 9137 deletions

View file

@ -1,4 +1,6 @@
package fr.free.nrw.commons.media
data class IdAndCaptions(val id: String, val captions: Map<String, String>)
data class IdAndCaptions(
val id: String,
val captions: Map<String, String>,
)

View file

@ -6,10 +6,10 @@ import fr.free.nrw.commons.category.ContinuationClient
import fr.free.nrw.commons.explore.media.MediaConverter
import fr.free.nrw.commons.utils.CommonsDateUtil
import fr.free.nrw.commons.wikidata.model.Entities
import io.reactivex.Single
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
import java.util.*
import io.reactivex.Single
import java.util.Date
import javax.inject.Inject
import javax.inject.Singleton
@ -22,199 +22,200 @@ const val RADIUS = 10000
* Media Client to handle custom calls to Commons MediaWiki APIs
*/
@Singleton
class MediaClient @Inject constructor(
private val mediaInterface: MediaInterface,
private val pageMediaInterface: PageMediaInterface,
private val mediaDetailInterface: MediaDetailInterface,
private val mediaConverter: MediaConverter
) : ContinuationClient<MwQueryResponse, Media>() {
class MediaClient
@Inject
constructor(
private val mediaInterface: MediaInterface,
private val pageMediaInterface: PageMediaInterface,
private val mediaDetailInterface: MediaDetailInterface,
private val mediaConverter: MediaConverter,
) : ContinuationClient<MwQueryResponse, Media>() {
fun getMediaById(id: String) = responseMapper(mediaInterface.getMediaById(id)).map { it.first() }
fun getMediaById(id: String) =
responseMapper(mediaInterface.getMediaById(id)).map { it.first() }
/**
* Checks if a page exists on Commons
* The same method can be used to check for file or talk page
*
* @param title File:Test.jpg or Commons:Deletion_requests/File:Test1.jpeg
*/
fun checkPageExistsUsingTitle(title: String?): Single<Boolean> =
mediaInterface
.checkPageExistsUsingTitle(title)
.map { it.query()!!.firstPage()!!.pageId() > 0 }
/**
* Checks if a page exists on Commons
* The same method can be used to check for file or talk page
*
* @param title File:Test.jpg or Commons:Deletion_requests/File:Test1.jpeg
*/
fun checkPageExistsUsingTitle(title: String?): Single<Boolean> {
return mediaInterface.checkPageExistsUsingTitle(title)
.map { it.query()!!.firstPage()!!.pageId() > 0 }
}
/**
* Take the fileSha and returns whether a file with a matching SHA exists or not
*
* @param fileSha SHA of the file to be checked
*/
fun checkFileExistsUsingSha(fileSha: String?): Single<Boolean> =
mediaInterface
.checkFileExistsUsingSha(fileSha)
.map { it.query()!!.allImages().size > 0 }
/**
* Take the fileSha and returns whether a file with a matching SHA exists or not
*
* @param fileSha SHA of the file to be checked
*/
fun checkFileExistsUsingSha(fileSha: String?): Single<Boolean> {
return mediaInterface.checkFileExistsUsingSha(fileSha)
.map { it.query()!!.allImages().size > 0 }
}
/**
* This method takes the category as input and returns a list of Media objects filtered using image generator query
* It uses the generator query API to get the images searched using a query, 10 at a time.
*
* @param category the search category. Must start with "Category:"
* @return
*/
fun getMediaListFromCategory(category: String): Single<List<Media>> =
continuationRequest(CATEGORY_CONTINUATION_PREFIX, category) {
mediaInterface.getMediaListFromCategory(category, 10, it)
}
/**
* This method takes the category as input and returns a list of Media objects filtered using image generator query
* It uses the generator query API to get the images searched using a query, 10 at a time.
*
* @param category the search category. Must start with "Category:"
* @return
*/
fun getMediaListFromCategory(category: String): Single<List<Media>> {
return continuationRequest(CATEGORY_CONTINUATION_PREFIX, category) {
mediaInterface.getMediaListFromCategory(category, 10, it)
}
}
/**
* This method takes the userName as input and returns a list of Media objects filtered using
* allimages query It uses the allimages query API to get the images contributed by the userName,
* 10 at a time.
*
* @param userName the username
* @return
*/
fun getMediaListForUser(userName: String): Single<List<Media>> =
continuationRequest("user_", userName) {
mediaInterface.getMediaListForUser(userName, 10, it)
}
/**
* This method takes the userName as input and returns a list of Media objects filtered using
* allimages query It uses the allimages query API to get the images contributed by the userName,
* 10 at a time.
*
* @param userName the username
* @return
*/
fun getMediaListForUser(userName: String): Single<List<Media>> {
return continuationRequest("user_", userName) {
mediaInterface.getMediaListForUser(userName, 10, it)
}
}
/**
* This method takes a keyword as input and returns a list of Media objects filtered using image generator query
* It uses the generator query API to get the images searched using a query, 10 at a time.
*
* @param keyword the search keyword
* @param limit
* @param offset
* @return
*/
fun getMediaListFromSearch(
keyword: String?,
limit: Int,
offset: Int,
) = responseMapper(mediaInterface.getMediaListFromSearch(keyword, limit, offset))
/**
* This method takes a keyword as input and returns a list of Media objects filtered using image generator query
* It uses the generator query API to get the images searched using a query, 10 at a time.
*
* @param keyword the search keyword
* @param limit
* @param offset
* @return
*/
fun getMediaListFromSearch(keyword: String?, limit: Int, offset: Int) =
responseMapper(mediaInterface.getMediaListFromSearch(keyword, limit, offset))
/**
* This method takes coordinate as input and returns a list of Media objects.
* It uses the generator query API to get the images searched using a query.
*
* @param coordinate coordinate
* @return
*/
fun getMediaListFromGeoSearch(coordinate: String?) =
responseMapper(mediaInterface.getMediaListFromGeoSearch(coordinate, LIMIT, RADIUS))
/**
* This method takes coordinate as input and returns a list of Media objects.
* It uses the generator query API to get the images searched using a query.
*
* @param coordinate coordinate
* @return
*/
fun getMediaListFromGeoSearch(coordinate: String?) =
responseMapper(mediaInterface.getMediaListFromGeoSearch(coordinate, LIMIT, RADIUS))
/**
* @return list of images for a particular depict entity
*/
fun fetchImagesForDepictedItem(
query: String,
srlimit: Int,
sroffset: Int
): Single<List<Media>> {
return responseMapper(
mediaInterface.fetchImagesForDepictedItem(
"haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query,
srlimit.toString(),
sroffset.toString()
/**
* @return list of images for a particular depict entity
*/
fun fetchImagesForDepictedItem(
query: String,
srlimit: Int,
sroffset: Int,
): Single<List<Media>> =
responseMapper(
mediaInterface.fetchImagesForDepictedItem(
"haswbstatement:" + BuildConfig.DEPICTS_PROPERTY + "=" + query,
srlimit.toString(),
sroffset.toString(),
),
)
)
}
/**
* Fetches Media object from the imageInfo API
*
* @param titles the tiles to be searched for. Can be filename or template name
* @return
*/
fun getMedia(titles: String?): Single<Media> {
return responseMapper(mediaInterface.getMedia(titles))
.map { it.first() }
}
/**
* Fetches Media object from the imageInfo API
*
* @param titles the tiles to be searched for. Can be filename or template name
* @return
*/
fun getMedia(titles: String?): Single<Media> =
responseMapper(mediaInterface.getMedia(titles))
.map { it.first() }
/**
* Fetches Media object from the imageInfo API but suppress (known) errors
*
* @param titles the tiles to be searched for. Can be filename or template name
* @return
*/
fun getMediaSuppressingErrors(titles: String?): Single<Media> {
return responseMapper(mediaInterface.getMediaSuppressingErrors(titles))
.map { it.first() }
}
/**
* Fetches Media object from the imageInfo API but suppress (known) errors
*
* @param titles the tiles to be searched for. Can be filename or template name
* @return
*/
fun getMediaSuppressingErrors(titles: String?): Single<Media> =
responseMapper(mediaInterface.getMediaSuppressingErrors(titles))
.map { it.first() }
/**
* The method returns the picture of the day
*
* @return Media object corresponding to the picture of the day
*/
fun getPictureOfTheDay(): Single<Media> {
val date = CommonsDateUtil.getIso8601DateFormatShort().format(Date())
return responseMapper(mediaInterface.getMediaWithGenerator("Template:Potd/$date")).map { it.first() }
}
fun getPageHtml(title: String?): Single<String> {
return mediaInterface.getPageHtml(title)
.map { obj: MwParseResponse -> obj.parse()?.text() ?: "" }
}
fun getEntities(entityIds: List<String>): Single<Entities> {
return if (entityIds.isEmpty())
Single.error(Exception("empty list passed for ids"))
else
mediaDetailInterface.getEntity(entityIds.joinToString("|"))
}
fun doesPageContainMedia(title: String?): Single<Boolean> {
return pageMediaInterface.getMediaList(title)
.map { it.items.isNotEmpty() }
}
fun resetCategoryContinuation(category: String) {
resetContinuation(CATEGORY_CONTINUATION_PREFIX, category)
}
/**
* Call the resetUserContinuation method
*
* @param userName the username
*/
fun resetUserNameContinuation(userName: String) =
resetUserContinuation("user_", userName)
/**
* Get whole WikiText of required file
* @param title : Name of the file
* @return Observable<MwQueryResult>
*/
fun getCurrentWikiText(title: String): Single<String?> {
return mediaDetailInterface.getWikiText(title).map {
it.query()?.pages()?.get(0)?.revisions()?.get(0)?.content()
/**
* The method returns the picture of the day
*
* @return Media object corresponding to the picture of the day
*/
fun getPictureOfTheDay(): Single<Media> {
val date = CommonsDateUtil.getIso8601DateFormatShort().format(Date())
return responseMapper(mediaInterface.getMediaWithGenerator("Template:Potd/$date")).map { it.first() }
}
}
override fun responseMapper(
networkResult: Single<MwQueryResponse>,
key: String?
): Single<List<Media>> {
return networkResult.map {
handleContinuationResponse(it.continuation(), key)
it.query()?.pages() ?: emptyList()
}.flatMap(::mediaFromPageAndEntity)
}
fun getPageHtml(title: String?): Single<String> =
mediaInterface
.getPageHtml(title)
.map { obj: MwParseResponse -> obj.parse()?.text() ?: "" }
private fun mediaFromPageAndEntity(pages: List<MwQueryPage>): Single<List<Media>> {
return if (pages.isEmpty()) {
Single.just(emptyList())
} else {
getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" })
fun getEntities(entityIds: List<String>): Single<Entities> =
if (entityIds.isEmpty()) {
Single.error(Exception("empty list passed for ids"))
} else {
mediaDetailInterface.getEntity(entityIds.joinToString("|"))
}
fun doesPageContainMedia(title: String?): Single<Boolean> =
pageMediaInterface
.getMediaList(title)
.map { it.items.isNotEmpty() }
fun resetCategoryContinuation(category: String) {
resetContinuation(CATEGORY_CONTINUATION_PREFIX, category)
}
/**
* Call the resetUserContinuation method
*
* @param userName the username
*/
fun resetUserNameContinuation(userName: String) = resetUserContinuation("user_", userName)
/**
* Get whole WikiText of required file
* @param title : Name of the file
* @return Observable<MwQueryResult>
*/
fun getCurrentWikiText(title: String): Single<String?> =
mediaDetailInterface.getWikiText(title).map {
it
.query()
?.pages()
?.get(0)
?.revisions()
?.get(0)
?.content()
}
override fun responseMapper(
networkResult: Single<MwQueryResponse>,
key: String?,
): Single<List<Media>> =
networkResult
.map {
pages.zip(it.entities().values)
.mapNotNull { (page, entity) ->
page.imageInfo()?.let {
mediaConverter.convert(page, entity, it)
}
}
}
}
handleContinuationResponse(it.continuation(), key)
it.query()?.pages() ?: emptyList()
}.flatMap(::mediaFromPageAndEntity)
private fun mediaFromPageAndEntity(pages: List<MwQueryPage>): Single<List<Media>> =
if (pages.isEmpty()) {
Single.just(emptyList())
} else {
getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" })
.map {
pages
.zip(it.entities().values)
.mapNotNull { (page, entity) ->
page.imageInfo()?.let {
mediaConverter.convert(page, entity, it)
}
}
}
}
}
}

View file

@ -20,7 +20,7 @@ interface MediaDetailInterface {
@GET("w/api.php?action=wbgetentities&props=labels&format=json&languagefallback=1&sites=commonswiki")
fun fetchEntitiesByFileName(
@Query("languages") language: String?,
@Query("titles") filename: String?
@Query("titles") filename: String?,
): Observable<Entities>
/**
@ -28,7 +28,9 @@ interface MediaDetailInterface {
* @param entityId EntityId (Ex: Q81566) of the depict entity
*/
@GET("/w/api.php?format=json&action=wbgetentities&props=labels&languagefallback=1")
fun getEntity(@Query("ids") entityId: String?): Single<Entities>
fun getEntity(
@Query("ids") entityId: String?,
): Single<Entities>
/**
* Fetches caption using wikibaseIdentifier
@ -38,16 +40,16 @@ interface MediaDetailInterface {
@GET("/w/api.php?action=wbgetentities&props=labels&format=json&languagefallback=1&sites=commonswiki")
fun getEntityForImage(
@Query("languages") language: String?,
@Query("ids") wikibaseIdentifier: String?
@Query("ids") wikibaseIdentifier: String?,
): Observable<Entities>
/**
* Fetches current wikitext
* @param title file name
* @return Single<MwQueryResponse>
</MwQueryResponse> */
</MwQueryResponse> */
@GET(WikidataConstants.MW_API_PREFIX + "action=query&prop=revisions&rvprop=content|timestamp&rvlimit=1&converttitles=")
fun getWikiText(
@Query("titles") title: String?
@Query("titles") title: String?,
): Single<MwQueryResponse>
}

View file

@ -19,7 +19,9 @@ interface MediaInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2")
fun checkPageExistsUsingTitle(@Query("titles") title: String?): Single<MwQueryResponse>
fun checkPageExistsUsingTitle(
@Query("titles") title: String?,
): Single<MwQueryResponse>
/**
* Check if file exists
@ -28,7 +30,9 @@ interface MediaInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2&list=allimages")
fun checkFileExistsUsingSha(@Query("aisha1") aisha1: String?): Single<MwQueryResponse>
fun checkFileExistsUsingSha(
@Query("aisha1") aisha1: String?,
): Single<MwQueryResponse>
/**
* This method retrieves a list of Media objects filtered using image generator query
@ -39,13 +43,13 @@ interface MediaInterface {
* @return
*/
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=categorymembers&gcmtype=file&gcmsort=timestamp&gcmdir=desc$MEDIA_PARAMS" //Category parameters
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=categorymembers&gcmtype=file&gcmsort=timestamp&gcmdir=desc$MEDIA_PARAMS", // Category parameters
)
fun getMediaListFromCategory(
@Query("gcmtitle") category: String?,
@Query("gcmlimit") itemLimit: Int,
@QueryMap continuation: Map<String, String>
@QueryMap continuation: Map<String, String>,
): Single<MwQueryResponse>
/**
@ -57,13 +61,13 @@ interface MediaInterface {
* @return
*/
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=allimages&gaisort=timestamp&gaidir=older$MEDIA_PARAMS"
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=allimages&gaisort=timestamp&gaidir=older$MEDIA_PARAMS",
)
fun getMediaListForUser(
@Query("gaiuser") username: String?,
@Query("gailimit") itemLimit: Int,
@QueryMap(encoded = true) continuation: Map<String, String>
@QueryMap(encoded = true) continuation: Map<String, String>,
): Single<MwQueryResponse>
/**
@ -75,12 +79,13 @@ interface MediaInterface {
* @return
*/
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=search&gsrwhat=text&gsrnamespace=6$MEDIA_PARAMS" //Search parameters
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=search&gsrwhat=text&gsrnamespace=6$MEDIA_PARAMS", // Search parameters
)
fun getMediaListFromSearch(
@Query("gsrsearch") keyword: String?,
@Query("gsrlimit") itemLimit: Int, @Query("gsroffset") offset: Int
@Query("gsrlimit") itemLimit: Int,
@Query("gsroffset") offset: Int,
): Single<MwQueryResponse>
/**
@ -91,13 +96,13 @@ interface MediaInterface {
* @return
*/
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=geosearch&ggsnamespace=6$MEDIA_PARAMS" //Search parameters
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=geosearch&ggsnamespace=6$MEDIA_PARAMS", // Search parameters
)
fun getMediaListFromGeoSearch(
@Query("ggscoord") location: String?,
@Query("ggslimit") itemLimit: Int,
@Query("ggsradius") radius: Int
@Query("ggsradius") radius: Int,
): Single<MwQueryResponse>
/**
@ -107,7 +112,9 @@ interface MediaInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2$MEDIA_PARAMS_WITH_CATEGORY_DETAILS")
fun getMedia(@Query("titles") title: String?): Single<MwQueryResponse>
fun getMedia(
@Query("titles") title: String?,
): Single<MwQueryResponse>
/**
* Fetches Media object from the imageInfo API but suppress (known) errors
@ -117,7 +124,9 @@ interface MediaInterface {
*/
@GET("w/api.php?action=query&format=json&formatversion=2$MEDIA_PARAMS_WITH_CATEGORY_DETAILS")
@Headers(SUPPRESS_ERROR_LOG_HEADER)
fun getMediaSuppressingErrors(@Query("titles") title: String?): Single<MwQueryResponse>
fun getMediaSuppressingErrors(
@Query("titles") title: String?,
): Single<MwQueryResponse>
/**
* Fetches Media object from the imageInfo API
@ -127,7 +136,9 @@ interface MediaInterface {
*/
@GET("w/api.php?action=query&format=json&formatversion=2$MEDIA_PARAMS")
@Headers(SUPPRESS_ERROR_LOG_HEADER)
fun getMediaById(@Query("pageids") pageIds: String?): Single<MwQueryResponse>
fun getMediaById(
@Query("pageids") pageIds: String?,
): Single<MwQueryResponse>
/**
* Fetches Media object from the imageInfo API
@ -137,11 +148,15 @@ interface MediaInterface {
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2&generator=images$MEDIA_PARAMS")
fun getMediaWithGenerator(@Query("titles") title: String?): Single<MwQueryResponse>
fun getMediaWithGenerator(
@Query("titles") title: String?,
): Single<MwQueryResponse>
@GET("w/api.php?format=json&action=parse&prop=text")
@Headers(SUPPRESS_ERROR_LOG_HEADER)
fun getPageHtml(@Query("page") title: String?): Single<MwParseResponse>
fun getPageHtml(
@Query("page") title: String?,
): Single<MwParseResponse>
/**
* Fetches caption using file name
@ -151,7 +166,7 @@ interface MediaInterface {
@GET("w/api.php?action=wbgetentities&props=labels&format=json&languagefallback=1")
fun fetchCaptionByFilename(
@Query("language") language: String?,
@Query("titles") filename: String?
@Query("titles") filename: String?,
): Single<MwQueryResponse>
/**
@ -161,12 +176,13 @@ interface MediaInterface {
* @param sroffset number od depictions already fetched, this is useful in implementing pagination
*/
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=search&gsrnamespace=6$MEDIA_PARAMS" //Search parameters
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=search&gsrnamespace=6$MEDIA_PARAMS", // Search parameters
)
fun fetchImagesForDepictedItem(
@Query("gsrsearch") query: String?,
@Query("gsrlimit") srlimit: String?, @Query("gsroffset") sroffset: String?
@Query("gsrlimit") srlimit: String?,
@Query("gsroffset") sroffset: String?,
): Single<MwQueryResponse>
companion object {

View file

@ -15,5 +15,7 @@ interface PageMediaInterface {
* @param title the title of the page
*/
@GET("api/rest_v1/page/media-list/{title}")
fun getMediaList(@Path("title") title: String?): Single<PageMediaListResponse>
fun getMediaList(
@Path("title") title: String?,
): Single<PageMediaListResponse>
}

View file

@ -5,9 +5,9 @@ import fr.free.nrw.commons.Media
import fr.free.nrw.commons.category.ContinuationClient
import fr.free.nrw.commons.explore.media.MediaConverter
import fr.free.nrw.commons.wikidata.model.Entities
import io.reactivex.Single
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@ -15,79 +15,79 @@ import javax.inject.Singleton
* Media Client to handle custom calls to Commons MediaWiki APIs of production server
*/
@Singleton
class WikidataMediaClient @Inject constructor(
private val wikidataMediaInterface: WikidataMediaInterface,
private val mediaDetailInterface: MediaDetailInterface,
private val mediaConverter: MediaConverter
) : ContinuationClient<MwQueryResponse, Media>() {
/**
* Fetch images for depict ID
*
* @param query depictionEntityId ex. "Q9394"
* @param srlimit the number of items to fetch
* @param sroffset number of depictions already fetched,
* this is useful in implementing pagination
* @return list of images for a particular depict ID
*/
fun fetchImagesForDepictedItem(
query: String,
srlimit: Int,
sroffset: Int
): Single<List<Media>> {
return responseMapper(
wikidataMediaInterface.fetchImagesForDepictedItem(
"haswbstatement:" + BetaConstants.DEPICTS_PROPERTY + "=" + query,
srlimit.toString(),
sroffset.toString()
class WikidataMediaClient
@Inject
constructor(
private val wikidataMediaInterface: WikidataMediaInterface,
private val mediaDetailInterface: MediaDetailInterface,
private val mediaConverter: MediaConverter,
) : ContinuationClient<MwQueryResponse, Media>() {
/**
* Fetch images for depict ID
*
* @param query depictionEntityId ex. "Q9394"
* @param srlimit the number of items to fetch
* @param sroffset number of depictions already fetched,
* this is useful in implementing pagination
* @return list of images for a particular depict ID
*/
fun fetchImagesForDepictedItem(
query: String,
srlimit: Int,
sroffset: Int,
): Single<List<Media>> =
responseMapper(
wikidataMediaInterface.fetchImagesForDepictedItem(
"haswbstatement:" + BetaConstants.DEPICTS_PROPERTY + "=" + query,
srlimit.toString(),
sroffset.toString(),
),
)
)
}
/**
* Helps to map to the required data from the API response
*
* @param networkResult MwQueryResponse
* @param key for handling continuation request, this is null in this case
*/
override fun responseMapper(
networkResult: Single<MwQueryResponse>,
key: String?
): Single<List<Media>> {
return networkResult.map {
handleContinuationResponse(it.continuation(), key)
it.query()?.pages() ?: emptyList()
}.flatMap(::mediaFromPageAndEntity)
}
/**
* Gets list of Media from MwQueryPage
*/
private fun mediaFromPageAndEntity(pages: List<MwQueryPage>): Single<List<Media>> {
return if (pages.isEmpty())
Single.just(emptyList())
else
getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" })
/**
* Helps to map to the required data from the API response
*
* @param networkResult MwQueryResponse
* @param key for handling continuation request, this is null in this case
*/
override fun responseMapper(
networkResult: Single<MwQueryResponse>,
key: String?,
): Single<List<Media>> =
networkResult
.map {
pages.zip(it.entities().values)
.mapNotNull { (page, entity) ->
page.imageInfo()?.let {
mediaConverter.convert(page, entity, it)
handleContinuationResponse(it.continuation(), key)
it.query()?.pages() ?: emptyList()
}.flatMap(::mediaFromPageAndEntity)
/**
* Gets list of Media from MwQueryPage
*/
private fun mediaFromPageAndEntity(pages: List<MwQueryPage>): Single<List<Media>> =
if (pages.isEmpty()) {
Single.just(emptyList())
} else {
getEntities(pages.map { "$PAGE_ID_PREFIX${it.pageId()}" })
.map {
pages
.zip(it.entities().values)
.mapNotNull { (page, entity) ->
page.imageInfo()?.let {
mediaConverter.convert(page, entity, it)
}
}
}
}
}
}
}
/**
* Gets Entities from IDs
*
* @param entityIds list of IDs of pages/entities ex. {"M4254154", "M11413343"}
*/
fun getEntities(entityIds: List<String>): Single<Entities> {
return if (entityIds.isEmpty())
Single.error(Exception("empty list passed for ids"))
else
mediaDetailInterface.getEntity(entityIds.joinToString("|"))
/**
* Gets Entities from IDs
*
* @param entityIds list of IDs of pages/entities ex. {"M4254154", "M11413343"}
*/
fun getEntities(entityIds: List<String>): Single<Entities> =
if (entityIds.isEmpty()) {
Single.error(Exception("empty list passed for ids"))
} else {
mediaDetailInterface.getEntity(entityIds.joinToString("|"))
}
}
}

View file

@ -17,13 +17,14 @@ interface WikidataMediaInterface {
* @param sroffset number of depictions already fetched,
* this is useful in implementing pagination
* @return Single<MwQueryResponse>
</MwQueryResponse> */
</MwQueryResponse> */
@GET(
"w/api.php?action=query&format=json&formatversion=2" + //Basic parameters
"&generator=search&gsrnamespace=6$MEDIA_PARAMS" //Search parameters
"w/api.php?action=query&format=json&formatversion=2" + // Basic parameters
"&generator=search&gsrnamespace=6$MEDIA_PARAMS", // Search parameters
)
fun fetchImagesForDepictedItem(
@Query("gsrsearch") query: String?,
@Query("gsrlimit") srlimit: String?, @Query("gsroffset") sroffset: String?
@Query("gsrlimit") srlimit: String?,
@Query("gsroffset") sroffset: String?,
): Single<MwQueryResponse>
}

View file

@ -10,10 +10,7 @@ import android.os.Bundle
import android.view.View
import android.view.Window
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.controller.BaseControllerListener
@ -38,12 +35,16 @@ import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorViewModel
import fr.free.nrw.commons.customselector.ui.selector.CustomSelectorViewModelFactory
import fr.free.nrw.commons.databinding.ActivityZoomableBinding
import fr.free.nrw.commons.media.zoomControllers.zoomable.DoubleTapGestureListener
import fr.free.nrw.commons.media.zoomControllers.zoomable.ZoomableDraweeView
import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.upload.FileProcessor
import fr.free.nrw.commons.upload.FileUtilsWrapper
import fr.free.nrw.commons.utils.CustomSelectorUtils
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import kotlin.collections.ArrayList
@ -53,7 +54,6 @@ import kotlin.collections.ArrayList
* like zoom, and swap gestures
*/
class ZoomableActivity : BaseActivity() {
private lateinit var imageUri: Uri
/**
@ -67,7 +67,7 @@ class ZoomableActivity : BaseActivity() {
private lateinit var prefs: SharedPreferences
private lateinit var binding: ActivityZoomableBinding
var photoBackgroundColor: Int? = null
/**
@ -126,36 +126,39 @@ class ZoomableActivity : BaseActivity() {
lateinit var customSelectorViewModelFactory: CustomSelectorViewModelFactory
/**
* Coroutine Dispatchers and Scope.
*/
private var defaultDispatcher : CoroutineDispatcher = Dispatchers.Default
private var ioDispatcher : CoroutineDispatcher = Dispatchers.IO
private val scope : CoroutineScope = MainScope()
* Coroutine Dispatchers and Scope.
*/
private var defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
private var ioDispatcher: CoroutineDispatcher = Dispatchers.IO
private val scope: CoroutineScope = MainScope()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityZoomableBinding.inflate(layoutInflater)
setContentView(binding.root)
prefs = applicationContext.getSharedPreferences(
ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY,
MODE_PRIVATE
)
prefs =
applicationContext.getSharedPreferences(
ImageHelper.CUSTOM_SELECTOR_PREFERENCE_KEY,
MODE_PRIVATE,
)
selectedImages = intent.getParcelableArrayListExtra(
CustomSelectorConstants.TOTAL_SELECTED_IMAGES
)
selectedImages =
intent.getParcelableArrayListExtra(
CustomSelectorConstants.TOTAL_SELECTED_IMAGES,
)
position = intent.getIntExtra(CustomSelectorConstants.PRESENT_POSITION, 0)
bucketId = intent.getLongExtra(CustomSelectorConstants.BUCKET_ID, 0L)
viewModel = ViewModelProvider(this, customSelectorViewModelFactory).get(
CustomSelectorViewModel::class.java
)
viewModel =
ViewModelProvider(this, customSelectorViewModelFactory).get(
CustomSelectorViewModel::class.java,
)
viewModel.fetchImages()
viewModel.result.observe(this) {
handleResult(it)
}
val origin = intent.getStringExtra(ZoomableActivityConstants.ORIGIN);
val origin = intent.getStringExtra(ZoomableActivityConstants.ORIGIN)
/**
* If origin is "null" it means that ZoomableActivity was created by the custom picker
@ -166,15 +169,20 @@ class ZoomableActivity : BaseActivity() {
if (prefs.getBoolean(CustomSelectorConstants.FULL_SCREEN_MODE_FIRST_LUNCH, true)) {
// show welcome dialog on first launch
showWelcomeDialog()
prefs.edit().putBoolean(
CustomSelectorConstants.FULL_SCREEN_MODE_FIRST_LUNCH,
false
).apply()
prefs
.edit()
.putBoolean(
CustomSelectorConstants.FULL_SCREEN_MODE_FIRST_LUNCH,
false,
).apply()
}
}
val backgroundColor = intent.getIntExtra(ZoomableActivityConstants.PHOTO_BACKGROUND_COLOR,
MediaDetailFragment.DEFAULT_IMAGE_BACKGROUND_COLOR);
val backgroundColor =
intent.getIntExtra(
ZoomableActivityConstants.PHOTO_BACKGROUND_COLOR,
MediaDetailFragment.DEFAULT_IMAGE_BACKGROUND_COLOR,
)
if (backgroundColor != MediaDetailFragment.DEFAULT_IMAGE_BACKGROUND_COLOR) {
photoBackgroundColor = backgroundColor
@ -196,15 +204,16 @@ class ZoomableActivity : BaseActivity() {
* Handle view model result.
*/
private fun handleResult(result: Result) {
if(result.status is CallbackStatus.SUCCESS){
if (result.status is CallbackStatus.SUCCESS) {
val images = result.images
if(images.isNotEmpty()) {
if (images.isNotEmpty()) {
this@ZoomableActivity.images = ImageHelper.filterImages(images, bucketId)
imageUri = if (this@ZoomableActivity.images.isNullOrEmpty()) {
intent.data as Uri
} else {
this@ZoomableActivity.images!![position].uri
}
imageUri =
if (this@ZoomableActivity.images.isNullOrEmpty()) {
intent.data as Uri
} else {
this@ZoomableActivity.images!![position].uri
}
Timber.d("URL = $imageUri")
init(imageUri)
onSwipe()
@ -225,34 +234,36 @@ class ZoomableActivity : BaseActivity() {
sharedPreferences.getBoolean(ImageHelper.SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY, true)
if (!images.isNullOrEmpty()) {
binding.zoomable!!.setOnTouchListener(object : OnSwipeTouchListener(this) {
// Swipe left to view next image in the folder. (if available)
override fun onSwipeLeft() {
super.onSwipeLeft()
onLeftSwiped(showAlreadyActionedImages)
}
binding.zoomable!!.setOnTouchListener(
object : OnSwipeTouchListener(this) {
// Swipe left to view next image in the folder. (if available)
override fun onSwipeLeft() {
super.onSwipeLeft()
onLeftSwiped(showAlreadyActionedImages)
}
// Swipe right to view previous image in the folder. (if available)
override fun onSwipeRight() {
super.onSwipeRight()
onRightSwiped(showAlreadyActionedImages)
}
// Swipe right to view previous image in the folder. (if available)
override fun onSwipeRight() {
super.onSwipeRight()
onRightSwiped(showAlreadyActionedImages)
}
// Swipe up to select the picture (the equivalent of tapping it in non-fullscreen mode)
// and show the next picture skipping pictures that have either already been uploaded or
// marked as not for upload
override fun onSwipeUp() {
super.onSwipeUp()
onUpSwiped()
}
// Swipe up to select the picture (the equivalent of tapping it in non-fullscreen mode)
// and show the next picture skipping pictures that have either already been uploaded or
// marked as not for upload
override fun onSwipeUp() {
super.onSwipeUp()
onUpSwiped()
}
// Swipe down to mark that picture as "Not for upload" (the equivalent of selecting it then
// tapping "Mark as not for upload" in non-fullscreen mode), and show the next picture.
override fun onSwipeDown() {
super.onSwipeDown()
onDownSwiped()
}
})
// Swipe down to mark that picture as "Not for upload" (the equivalent of selecting it then
// tapping "Mark as not for upload" in non-fullscreen mode), and show the next picture.
override fun onSwipeDown() {
super.onSwipeDown()
onDownSwiped()
}
},
)
}
}
@ -260,58 +271,66 @@ class ZoomableActivity : BaseActivity() {
* Handles down swipe action
*/
private fun onDownSwiped() {
if (binding.zoomable?.zoomableController?.isIdentity == false)
if (binding.zoomable?.zoomableController?.isIdentity == false) {
return
}
scope.launch {
val imageSHA1 = CustomSelectorUtils.getImageSHA1(
images!![position].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver
)
val imageSHA1 =
CustomSelectorUtils.getImageSHA1(
images!![position].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver,
)
var isUploaded = uploadedStatusDao.findByImageSHA1(imageSHA1, true)
if (isUploaded > 0) {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT
).show()
} else {
val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
images!![position],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper
)
isUploaded = uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true
)
if (isUploaded > 0) {
Toast.makeText(
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT
Toast.LENGTH_SHORT,
).show()
} else {
val imageModifiedSHA1 =
CustomSelectorUtils.generateModifiedSHA1(
images!![position],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper,
)
isUploaded =
uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true,
)
if (isUploaded > 0) {
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT,
).show()
} else {
insertInNotForUpload(images!![position])
Toast.makeText(
this@ZoomableActivity,
getString(R.string.image_marked_as_not_for_upload),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.image_marked_as_not_for_upload),
Toast.LENGTH_SHORT,
).show()
shouldRefresh = true
if (position < images!!.size - 1) {
position++
init(images!![position].uri)
} else {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT,
).show()
}
}
}
@ -322,58 +341,66 @@ class ZoomableActivity : BaseActivity() {
* Handles up swipe action
*/
private fun onUpSwiped() {
if (binding.zoomable?.zoomableController?.isIdentity == false)
if (binding.zoomable?.zoomableController?.isIdentity == false) {
return
}
scope.launch {
val imageSHA1 = CustomSelectorUtils.getImageSHA1(
images!![position].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver
)
val imageSHA1 =
CustomSelectorUtils.getImageSHA1(
images!![position].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver,
)
var isNonActionable = notForUploadStatusDao.find(imageSHA1)
if (isNonActionable > 0) {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.can_not_select_this_image_for_upload),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.can_not_select_this_image_for_upload),
Toast.LENGTH_SHORT,
).show()
} else {
isNonActionable =
uploadedStatusDao.findByImageSHA1(imageSHA1, true)
if (isNonActionable > 0) {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT
).show()
} else {
val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
images!![position],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper
)
isNonActionable = uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true
)
if (isNonActionable > 0) {
Toast.makeText(
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT
Toast.LENGTH_SHORT,
).show()
} else {
val imageModifiedSHA1 =
CustomSelectorUtils.generateModifiedSHA1(
images!![position],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper,
)
isNonActionable =
uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true,
)
if (isNonActionable > 0) {
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.this_image_is_already_uploaded),
Toast.LENGTH_SHORT,
).show()
} else {
if (!selectedImages!!.contains(images!![position])) {
selectedImages!!.add(images!![position])
Toast.makeText(
this@ZoomableActivity,
getString(R.string.image_selected),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.image_selected),
Toast.LENGTH_SHORT,
).show()
}
position = getNextActionableImage(position + 1)
init(images!![position].uri)
@ -387,19 +414,21 @@ class ZoomableActivity : BaseActivity() {
* Handles right swipe action
*/
private fun onRightSwiped(showAlreadyActionedImages: Boolean) {
if (binding.zoomable?.zoomableController?.isIdentity == false)
if (binding.zoomable?.zoomableController?.isIdentity == false) {
return
}
if (showAlreadyActionedImages) {
if (position > 0) {
position--
init(images!![position].uri)
} else {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT,
).show()
}
} else {
if (position > 0) {
@ -408,11 +437,12 @@ class ZoomableActivity : BaseActivity() {
init(images!![position].uri)
}
} else {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT,
).show()
}
}
}
@ -421,19 +451,21 @@ class ZoomableActivity : BaseActivity() {
* Handles left swipe action
*/
private fun onLeftSwiped(showAlreadyActionedImages: Boolean) {
if (binding.zoomable?.zoomableController?.isIdentity == false)
if (binding.zoomable?.zoomableController?.isIdentity == false) {
return
}
if (showAlreadyActionedImages) {
if (position < images!!.size - 1) {
position++
init(images!![position].uri)
} else {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT,
).show()
}
} else {
if (position < images!!.size - 1) {
@ -442,11 +474,12 @@ class ZoomableActivity : BaseActivity() {
init(images!![position].uri)
}
} else {
Toast.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT
).show()
Toast
.makeText(
this@ZoomableActivity,
getString(R.string.no_more_images_found),
Toast.LENGTH_SHORT,
).show()
}
}
}
@ -459,29 +492,32 @@ class ZoomableActivity : BaseActivity() {
*/
private suspend fun getNextActionableImage(index: Int): Int {
var nextPosition = position
for(i in index until images!!.size){
for (i in index until images!!.size) {
nextPosition = i
val imageSHA1 = CustomSelectorUtils.getImageSHA1(
images!![i].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver
)
val imageSHA1 =
CustomSelectorUtils.getImageSHA1(
images!![i].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver,
)
var isNonActionable = notForUploadStatusDao.find(imageSHA1)
if (isNonActionable <= 0) {
isNonActionable = uploadedStatusDao.findByImageSHA1(imageSHA1, true)
if (isNonActionable <= 0) {
val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
images!![i],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper
)
isNonActionable = uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true
)
val imageModifiedSHA1 =
CustomSelectorUtils.generateModifiedSHA1(
images!![i],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper,
)
isNonActionable =
uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true,
)
if (isNonActionable <= 0) {
return i
} else {
@ -505,29 +541,32 @@ class ZoomableActivity : BaseActivity() {
*/
private suspend fun getPreviousActionableImage(index: Int): Int {
var previousPosition = position
for(i in index downTo 0){
for (i in index downTo 0) {
previousPosition = i
val imageSHA1 = CustomSelectorUtils.getImageSHA1(
images!![i].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver
)
val imageSHA1 =
CustomSelectorUtils.getImageSHA1(
images!![i].uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver,
)
var isNonActionable = notForUploadStatusDao.find(imageSHA1)
if (isNonActionable <= 0) {
isNonActionable = uploadedStatusDao.findByImageSHA1(imageSHA1, true)
if (isNonActionable <= 0) {
val imageModifiedSHA1 = CustomSelectorUtils.generateModifiedSHA1(
images!![i],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper
)
isNonActionable = uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true
)
val imageModifiedSHA1 =
CustomSelectorUtils.generateModifiedSHA1(
images!![i],
defaultDispatcher,
this@ZoomableActivity,
fileProcessor,
fileUtilsWrapper,
)
isNonActionable =
uploadedStatusDao.findByModifiedImageSHA1(
imageModifiedSHA1,
true,
)
if (isNonActionable <= 0) {
return i
} else {
@ -561,9 +600,10 @@ class ZoomableActivity : BaseActivity() {
/**
* Get position of an image from list
*/
private fun getImagePosition(list: ArrayList<Image>?, image: Image): Int {
return list!!.indexOf(image)
}
private fun getImagePosition(
list: ArrayList<Image>?,
image: Image,
): Int = list!!.indexOf(image)
/**
* Two types of loading indicators have been added to the zoom activity:
@ -573,19 +613,25 @@ class ZoomableActivity : BaseActivity() {
*/
private val loadingListener: ControllerListener<ImageInfo?> =
object : BaseControllerListener<ImageInfo?>() {
override fun onSubmit(id: String, callerContext: Any) {
override fun onSubmit(
id: String,
callerContext: Any,
) {
// Sometimes the spinner doesn't appear when rapidly switching between images, this fixes that
binding.zoomProgressBar.visibility = View.VISIBLE
}
override fun onIntermediateImageSet(id: String, imageInfo: ImageInfo?) {
override fun onIntermediateImageSet(
id: String,
imageInfo: ImageInfo?,
) {
binding.zoomProgressBar.visibility = View.GONE
}
override fun onFinalImageSet(
id: String,
imageInfo: ImageInfo?,
animatable: Animatable?
animatable: Animatable?,
) {
binding.zoomProgressBar.visibility = View.GONE
}
@ -593,23 +639,27 @@ class ZoomableActivity : BaseActivity() {
private fun init(imageUri: Uri?) {
if (imageUri != null) {
val hierarchy = GenericDraweeHierarchyBuilder.newInstance(resources)
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
.setProgressBarImage(ProgressBarDrawable())
.setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
.build()
val hierarchy =
GenericDraweeHierarchyBuilder
.newInstance(resources)
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
.setProgressBarImage(ProgressBarDrawable())
.setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
.build()
with(binding.zoomable!!) {
setHierarchy(hierarchy)
setAllowTouchInterceptionWhileZoomed(true)
setIsLongpressEnabled(false)
setTapListener(DoubleTapGestureListener(this))
}
val controller: DraweeController = Fresco.newDraweeControllerBuilder()
.setUri(imageUri)
.setControllerListener(loadingListener)
.build()
val controller: DraweeController =
Fresco
.newDraweeControllerBuilder()
.setUri(imageUri)
.setControllerListener(loadingListener)
.build()
binding.zoomable!!.controller = controller
if (photoBackgroundColor != null) {
binding.zoomable!!.setBackgroundColor(photoBackgroundColor!!)
}
@ -630,16 +680,17 @@ class ZoomableActivity : BaseActivity() {
* Inserts an image in Not For Upload table
*/
private suspend fun insertInNotForUpload(it: Image) {
val imageSHA1 = CustomSelectorUtils.getImageSHA1(
it.uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver
)
val imageSHA1 =
CustomSelectorUtils.getImageSHA1(
it.uri,
ioDispatcher,
fileUtilsWrapper,
contentResolver,
)
notForUploadStatusDao.insert(
NotForUploadStatus(
imageSHA1
)
imageSHA1,
),
)
}
@ -651,7 +702,7 @@ class ZoomableActivity : BaseActivity() {
val returnIntent = Intent()
returnIntent.putParcelableArrayListExtra(
CustomSelectorConstants.NEW_SELECTED_IMAGES,
selectedImages
selectedImages,
)
returnIntent.putExtra(SHOULD_REFRESH, shouldRefresh)
setResult(Activity.RESULT_OK, returnIntent)
@ -665,14 +716,14 @@ class ZoomableActivity : BaseActivity() {
super.onDestroy()
}
object ZoomableActivityConstants {
object ZoomableActivityConstants {
/**
* Key for Accessing Intent Data Named "Origin", The value indicates what fragment
* ZoomableActivity was created by. It is null if ZoomableActivity was created by
* the custom picker.
*/
const val ORIGIN = "Origin";
const val ORIGIN = "Origin"
const val PHOTO_BACKGROUND_COLOR = "photo_background_color"
}
}

View file

@ -3,7 +3,9 @@ package fr.free.nrw.commons.media.model
data class PageMediaListResponse(
val revision: String,
val tid: String,
val items: List<PageMediaListItem>
val items: List<PageMediaListItem>,
)
data class PageMediaListItem(val title: String)
data class PageMediaListItem(
val title: String,
)