mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 04:13:53 +01:00
convert top level classes to kotlin (#6368)
* Converted welcome activity / pager to kotlin * Removed unused interface * Convert ViewPagerAdapter to kotlin and enforce that all tabs must have a title that comes from strings.xml * Convert OkHttpConnectionFactory and remove an exception class nobody was using * Convert MapController to kotlin along with fixing nullability in a few places
This commit is contained in:
parent
65f41beed8
commit
66395b9871
29 changed files with 555 additions and 655 deletions
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
|
|
@ -16,6 +16,7 @@
|
||||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||||
<option name="IMPORT_LAYOUT_TABLE">
|
<option name="IMPORT_LAYOUT_TABLE">
|
||||||
<value>
|
<value>
|
||||||
|
<package name="" withSubpackages="true" static="false" module="true" />
|
||||||
<package name="" withSubpackages="true" static="true" />
|
<package name="" withSubpackages="true" static="true" />
|
||||||
<emptyLine />
|
<emptyLine />
|
||||||
<package name="" withSubpackages="true" static="false" />
|
<package name="" withSubpackages="true" static="false" />
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class MapController {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We pass this variable as a group of placeList and boundaryCoordinates
|
|
||||||
*/
|
|
||||||
public class NearbyPlacesInfo {
|
|
||||||
public List<Place> placeList; // List of nearby places
|
|
||||||
public LatLng[] boundaryCoordinates; // Corners of nearby area
|
|
||||||
public LatLng currentLatLng; // Current location when this places are populated
|
|
||||||
public LatLng searchLatLng; // Search location for finding this places
|
|
||||||
public List<Media> mediaList; // Search location for finding this places
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We pass this variable as a group of placeList and boundaryCoordinates
|
|
||||||
*/
|
|
||||||
public class ExplorePlacesInfo {
|
|
||||||
public List<Place> explorePlaceList; // List of nearby places
|
|
||||||
public LatLng[] boundaryCoordinates; // Corners of nearby area
|
|
||||||
public LatLng currentLatLng; // Current location when this places are populated
|
|
||||||
public LatLng searchLatLng; // Search location for finding this places
|
|
||||||
public List<Media> mediaList; // Search location for finding this places
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
app/src/main/java/fr/free/nrw/commons/MapController.kt
Normal file
46
app/src/main/java/fr/free/nrw/commons/MapController.kt
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
|
||||||
|
abstract class MapController {
|
||||||
|
/**
|
||||||
|
* We pass this variable as a group of placeList and boundaryCoordinates
|
||||||
|
*/
|
||||||
|
inner class NearbyPlacesInfo {
|
||||||
|
@JvmField
|
||||||
|
var placeList: List<Place> = emptyList() // List of nearby places
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var boundaryCoordinates: Array<LatLng> = emptyArray() // Corners of nearby area
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var currentLatLng: LatLng? = null // Current location when this places are populated
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var searchLatLng: LatLng? = null // Search location for finding this places
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var mediaList: List<Media>? = null // Search location for finding this places
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We pass this variable as a group of placeList and boundaryCoordinates
|
||||||
|
*/
|
||||||
|
inner class ExplorePlacesInfo {
|
||||||
|
@JvmField
|
||||||
|
var explorePlaceList: List<Place> = emptyList() // List of nearby places
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var boundaryCoordinates: Array<LatLng> = emptyArray() // Corners of nearby area
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var currentLatLng: LatLng? = null // Current location when this places are populated
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var searchLatLng: LatLng? = null // Search location for finding this places
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var mediaList: List<Media> = emptyList() // Search location for finding this places
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import okhttp3.Cache;
|
|
||||||
import okhttp3.Interceptor;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
public final class OkHttpConnectionFactory {
|
|
||||||
private static final String CACHE_DIR_NAME = "okhttp-cache";
|
|
||||||
private static final long NET_CACHE_SIZE = 64 * 1024 * 1024;
|
|
||||||
|
|
||||||
public static OkHttpClient CLIENT;
|
|
||||||
|
|
||||||
@NonNull public static OkHttpClient getClient(final CommonsCookieJar cookieJar) {
|
|
||||||
if (CLIENT == null) {
|
|
||||||
CLIENT = createClient(cookieJar);
|
|
||||||
}
|
|
||||||
return CLIENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static OkHttpClient createClient(final CommonsCookieJar cookieJar) {
|
|
||||||
return new OkHttpClient.Builder()
|
|
||||||
.cookieJar(cookieJar)
|
|
||||||
.cache((CommonsApplication.getInstance()!=null) ? new Cache(new File(CommonsApplication.getInstance().getCacheDir(), CACHE_DIR_NAME), NET_CACHE_SIZE) : null)
|
|
||||||
.connectTimeout(120, TimeUnit.SECONDS)
|
|
||||||
.writeTimeout(120, TimeUnit.SECONDS)
|
|
||||||
.readTimeout(120, TimeUnit.SECONDS)
|
|
||||||
.addInterceptor(getLoggingInterceptor())
|
|
||||||
.addInterceptor(new UnsuccessfulResponseInterceptor())
|
|
||||||
.addInterceptor(new CommonHeaderRequestInterceptor())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HttpLoggingInterceptor getLoggingInterceptor() {
|
|
||||||
final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor()
|
|
||||||
.setLevel(Level.BASIC);
|
|
||||||
|
|
||||||
httpLoggingInterceptor.redactHeader("Authorization");
|
|
||||||
httpLoggingInterceptor.redactHeader("Cookie");
|
|
||||||
|
|
||||||
return httpLoggingInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CommonHeaderRequestInterceptor implements Interceptor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public Response intercept(@NonNull final Chain chain) throws IOException {
|
|
||||||
final Request request = chain.request().newBuilder()
|
|
||||||
.header("User-Agent", CommonsApplication.getInstance().getUserAgent())
|
|
||||||
.build();
|
|
||||||
return chain.proceed(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UnsuccessfulResponseInterceptor implements Interceptor {
|
|
||||||
private static final String SUPPRESS_ERROR_LOG = "x-commons-suppress-error-log";
|
|
||||||
public static final String SUPPRESS_ERROR_LOG_HEADER = SUPPRESS_ERROR_LOG+": true";
|
|
||||||
private static final List<String> DO_NOT_INTERCEPT = Collections.singletonList(
|
|
||||||
"api.php?format=json&formatversion=2&errorformat=plaintext&action=upload&ignorewarnings=1");
|
|
||||||
|
|
||||||
private static final String ERRORS_PREFIX = "{\"error";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public Response intercept(@NonNull final Chain chain) throws IOException {
|
|
||||||
final Request rq = chain.request();
|
|
||||||
|
|
||||||
// If the request contains our special "suppress errors" header, make note of it
|
|
||||||
// but don't pass that on to the server.
|
|
||||||
final boolean suppressErrors = rq.headers().names().contains(SUPPRESS_ERROR_LOG);
|
|
||||||
final Request request = rq.newBuilder()
|
|
||||||
.removeHeader(SUPPRESS_ERROR_LOG)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
final Response rsp = chain.proceed(request);
|
|
||||||
|
|
||||||
// Do not intercept certain requests and let the caller handle the errors
|
|
||||||
if(isExcludedUrl(chain.request())) {
|
|
||||||
return rsp;
|
|
||||||
}
|
|
||||||
if (rsp.isSuccessful()) {
|
|
||||||
try (final ResponseBody responseBody = rsp.peekBody(ERRORS_PREFIX.length())) {
|
|
||||||
if (ERRORS_PREFIX.equals(responseBody.string())) {
|
|
||||||
try (final ResponseBody body = rsp.body()) {
|
|
||||||
throw new IOException(body.string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final IOException e) {
|
|
||||||
// Log the error as debug (and therefore, "expected") or at error level
|
|
||||||
if (suppressErrors) {
|
|
||||||
Timber.d(e, "Suppressed (known / expected) error");
|
|
||||||
} else {
|
|
||||||
Timber.e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rsp;
|
|
||||||
}
|
|
||||||
throw new HttpStatusException(rsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExcludedUrl(final Request request) {
|
|
||||||
final String requestUrl = request.url().toString();
|
|
||||||
for(final String url: DO_NOT_INTERCEPT) {
|
|
||||||
if(requestUrl.contains(url)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OkHttpConnectionFactory() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class HttpStatusException extends IOException {
|
|
||||||
private final int code;
|
|
||||||
private final String url;
|
|
||||||
public HttpStatusException(@NonNull Response rsp) {
|
|
||||||
this.code = rsp.code();
|
|
||||||
this.url = rsp.request().url().uri().toString();
|
|
||||||
try {
|
|
||||||
if (rsp.body() != null && rsp.body().contentType() != null
|
|
||||||
&& rsp.body().contentType().toString().contains("json")) {
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Log?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int code() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
String str = "Code: " + code + ", URL: " + url;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
122
app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.kt
Normal file
122
app/src/main/java/fr/free/nrw/commons/OkHttpConnectionFactory.kt
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar
|
||||||
|
import okhttp3.Cache
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
object OkHttpConnectionFactory {
|
||||||
|
private const val CACHE_DIR_NAME = "okhttp-cache"
|
||||||
|
private const val NET_CACHE_SIZE = (64 * 1024 * 1024).toLong()
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
var CLIENT: OkHttpClient? = null
|
||||||
|
|
||||||
|
fun getClient(cookieJar: CommonsCookieJar): OkHttpClient {
|
||||||
|
if (CLIENT == null) {
|
||||||
|
CLIENT = createClient(cookieJar)
|
||||||
|
}
|
||||||
|
return CLIENT!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createClient(cookieJar: CommonsCookieJar): OkHttpClient {
|
||||||
|
return OkHttpClient.Builder()
|
||||||
|
.cookieJar(cookieJar)
|
||||||
|
.cache(
|
||||||
|
if (CommonsApplication.instance != null) Cache(
|
||||||
|
File(CommonsApplication.instance.cacheDir, CACHE_DIR_NAME),
|
||||||
|
NET_CACHE_SIZE
|
||||||
|
) else null
|
||||||
|
)
|
||||||
|
.connectTimeout(120, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(120, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(120, TimeUnit.SECONDS)
|
||||||
|
.addInterceptor(HttpLoggingInterceptor().apply {
|
||||||
|
setLevel(HttpLoggingInterceptor.Level.BASIC)
|
||||||
|
redactHeader("Authorization")
|
||||||
|
redactHeader("Cookie")
|
||||||
|
})
|
||||||
|
.addInterceptor(UnsuccessfulResponseInterceptor())
|
||||||
|
.addInterceptor(CommonHeaderRequestInterceptor())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommonHeaderRequestInterceptor : Interceptor {
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request().newBuilder()
|
||||||
|
.header("User-Agent", CommonsApplication.instance.userAgent)
|
||||||
|
.build()
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val SUPPRESS_ERROR_LOG = "x-commons-suppress-error-log"
|
||||||
|
const val SUPPRESS_ERROR_LOG_HEADER: String = "$SUPPRESS_ERROR_LOG: true"
|
||||||
|
|
||||||
|
private class UnsuccessfulResponseInterceptor : Interceptor {
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val rq = chain.request()
|
||||||
|
|
||||||
|
// If the request contains our special "suppress errors" header, make note of it
|
||||||
|
// but don't pass that on to the server.
|
||||||
|
val suppressErrors = rq.headers.names().contains(SUPPRESS_ERROR_LOG)
|
||||||
|
val request = rq.newBuilder()
|
||||||
|
.removeHeader(SUPPRESS_ERROR_LOG)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val rsp = chain.proceed(request)
|
||||||
|
|
||||||
|
// Do not intercept certain requests and let the caller handle the errors
|
||||||
|
if (isExcludedUrl(chain.request())) {
|
||||||
|
return rsp
|
||||||
|
}
|
||||||
|
if (rsp.isSuccessful) {
|
||||||
|
try {
|
||||||
|
rsp.peekBody(ERRORS_PREFIX.length.toLong()).use { responseBody ->
|
||||||
|
if (ERRORS_PREFIX == responseBody.string()) {
|
||||||
|
rsp.body.use { body ->
|
||||||
|
throw IOException(body!!.string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
// Log the error as debug (and therefore, "expected") or at error level
|
||||||
|
if (suppressErrors) {
|
||||||
|
Timber.d(e, "Suppressed (known / expected) error")
|
||||||
|
} else {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rsp
|
||||||
|
}
|
||||||
|
throw IOException("Unsuccessful response")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isExcludedUrl(request: Request): Boolean {
|
||||||
|
val requestUrl = request.url.toString()
|
||||||
|
for (url in DO_NOT_INTERCEPT) {
|
||||||
|
if (requestUrl.contains(url)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DO_NOT_INTERCEPT = listOf(
|
||||||
|
"api.php?format=json&formatversion=2&errorformat=plaintext&action=upload&ignorewarnings=1"
|
||||||
|
)
|
||||||
|
const val ERRORS_PREFIX = "{\"error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
public interface ViewHolder<T> {
|
|
||||||
void bindModel(Context context, T model);
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import androidx.fragment.app.FragmentPagerAdapter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This adapter will be used to display fragments in a ViewPager
|
|
||||||
*/
|
|
||||||
public class ViewPagerAdapter extends FragmentPagerAdapter {
|
|
||||||
private List<Fragment> fragmentList = new ArrayList<>();
|
|
||||||
private List<String> fragmentTitleList = new ArrayList<>();
|
|
||||||
|
|
||||||
public ViewPagerAdapter(FragmentManager manager) {
|
|
||||||
super(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a ViewPagerAdapter with a specified Fragment Manager and Fragment resume behavior.
|
|
||||||
*
|
|
||||||
* @param manager The FragmentManager
|
|
||||||
* @param behavior An integer which represents the behavior of non visible fragments. See
|
|
||||||
* FragmentPagerAdapter.java for options.
|
|
||||||
*/
|
|
||||||
public ViewPagerAdapter(FragmentManager manager, int behavior) {
|
|
||||||
super(manager, behavior);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the fragment of the viewpager at a particular position
|
|
||||||
* @param position
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Fragment getItem(int position) {
|
|
||||||
return fragmentList.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the total number of fragments in the viewpager.
|
|
||||||
* @return size
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return fragmentList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method sets the fragment and title list in the viewpager
|
|
||||||
* @param fragmentList List of all fragments to be displayed in the viewpager
|
|
||||||
* @param fragmentTitleList List of all titles of the fragments
|
|
||||||
*/
|
|
||||||
public void setTabData(List<Fragment> fragmentList, List<String> fragmentTitleList) {
|
|
||||||
this.fragmentList = fragmentList;
|
|
||||||
this.fragmentTitleList = fragmentTitleList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the title of the page at a particular position
|
|
||||||
* @param position
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public CharSequence getPageTitle(int position) {
|
|
||||||
return fragmentTitleList.get(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
app/src/main/java/fr/free/nrw/commons/ViewPagerAdapter.kt
Normal file
44
app/src/main/java/fr/free/nrw/commons/ViewPagerAdapter.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This adapter will be used to display fragments in a ViewPager
|
||||||
|
*/
|
||||||
|
class ViewPagerAdapter : FragmentPagerAdapter {
|
||||||
|
private val context: Context
|
||||||
|
private var fragmentList: List<Fragment> = emptyList()
|
||||||
|
private var fragmentTitleList: List<String> = emptyList()
|
||||||
|
|
||||||
|
constructor(context: Context, manager: FragmentManager) : super(manager) {
|
||||||
|
this.context = context
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, manager: FragmentManager, behavior: Int) : super(manager, behavior) {
|
||||||
|
this.context = context
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(position: Int): Fragment = fragmentList[position]
|
||||||
|
|
||||||
|
override fun getPageTitle(position: Int): CharSequence = fragmentTitleList[position]
|
||||||
|
|
||||||
|
override fun getCount(): Int = fragmentList.size
|
||||||
|
|
||||||
|
fun setTabs(vararg titlesToFragments: Pair<Int, Fragment>) {
|
||||||
|
// Enforce that every title must come from strings.xml and all will consistently be uppercase
|
||||||
|
fragmentTitleList = titlesToFragments.map {
|
||||||
|
context.getString(it.first).uppercase(Locale.ROOT)
|
||||||
|
}
|
||||||
|
fragmentList = titlesToFragments.map { it.second }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Convenience method for Java callers, can be removed when everything is migrated
|
||||||
|
@JvmStatic
|
||||||
|
fun pairOf(first: Int, second: Fragment) = first to second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import fr.free.nrw.commons.databinding.ActivityWelcomeBinding;
|
|
||||||
import fr.free.nrw.commons.databinding.PopupForCopyrightBinding;
|
|
||||||
import fr.free.nrw.commons.quiz.QuizActivity;
|
|
||||||
import fr.free.nrw.commons.theme.BaseActivity;
|
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
|
||||||
|
|
||||||
public class WelcomeActivity extends BaseActivity {
|
|
||||||
|
|
||||||
private ActivityWelcomeBinding binding;
|
|
||||||
private PopupForCopyrightBinding copyrightBinding;
|
|
||||||
|
|
||||||
private final WelcomePagerAdapter adapter = new WelcomePagerAdapter();
|
|
||||||
private boolean isQuiz;
|
|
||||||
private AlertDialog.Builder dialogBuilder;
|
|
||||||
private AlertDialog dialog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialises exiting fields and dependencies
|
|
||||||
*
|
|
||||||
* @param savedInstanceState WelcomeActivity bundled data
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
binding = ActivityWelcomeBinding.inflate(getLayoutInflater());
|
|
||||||
final View view = binding.getRoot();
|
|
||||||
setContentView(view);
|
|
||||||
|
|
||||||
if (getIntent() != null) {
|
|
||||||
final Bundle bundle = getIntent().getExtras();
|
|
||||||
if (bundle != null) {
|
|
||||||
isQuiz = bundle.getBoolean("isQuiz");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isQuiz = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable skip button if beta flavor
|
|
||||||
if (ConfigUtils.isBetaFlavour()) {
|
|
||||||
binding.finishTutorialButton.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
dialogBuilder = new AlertDialog.Builder(this);
|
|
||||||
copyrightBinding = PopupForCopyrightBinding.inflate(getLayoutInflater());
|
|
||||||
final View contactPopupView = copyrightBinding.getRoot();
|
|
||||||
dialogBuilder.setView(contactPopupView);
|
|
||||||
dialogBuilder.setCancelable(false);
|
|
||||||
dialog = dialogBuilder.create();
|
|
||||||
dialog.show();
|
|
||||||
|
|
||||||
copyrightBinding.buttonOk.setOnClickListener(v -> dialog.dismiss());
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.welcomePager.setAdapter(adapter);
|
|
||||||
binding.welcomePagerIndicator.setViewPager(binding.welcomePager);
|
|
||||||
|
|
||||||
binding.finishTutorialButton.setOnClickListener(v -> finishTutorial());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* References WelcomePageAdapter to null before the activity is destroyed
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
if (isQuiz) {
|
|
||||||
final Intent i = new Intent(this, QuizActivity.class);
|
|
||||||
startActivity(i);
|
|
||||||
}
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a way to change current activity to WelcomeActivity
|
|
||||||
*
|
|
||||||
* @param context Activity context
|
|
||||||
*/
|
|
||||||
public static void startYourself(final Context context) {
|
|
||||||
final Intent welcomeIntent = new Intent(context, WelcomeActivity.class);
|
|
||||||
context.startActivity(welcomeIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override onBackPressed() to go to previous tutorial 'pages' if not on first page
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (binding.welcomePager.getCurrentItem() != 0) {
|
|
||||||
binding.welcomePager.setCurrentItem(binding.welcomePager.getCurrentItem() - 1, true);
|
|
||||||
} else {
|
|
||||||
if (defaultKvStore.getBoolean("firstrun", true)) {
|
|
||||||
finishAffinity();
|
|
||||||
} else {
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finishTutorial() {
|
|
||||||
defaultKvStore.putBoolean("firstrun", false);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
78
app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt
Normal file
78
app/src/main/java/fr/free/nrw/commons/WelcomeActivity.kt
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import fr.free.nrw.commons.databinding.ActivityWelcomeBinding
|
||||||
|
import fr.free.nrw.commons.databinding.PopupForCopyrightBinding
|
||||||
|
import fr.free.nrw.commons.quiz.QuizActivity
|
||||||
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
|
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
|
||||||
|
|
||||||
|
class WelcomeActivity : BaseActivity() {
|
||||||
|
private var binding: ActivityWelcomeBinding? = null
|
||||||
|
private var isQuiz = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises exiting fields and dependencies
|
||||||
|
*
|
||||||
|
* @param savedInstanceState WelcomeActivity bundled data
|
||||||
|
*/
|
||||||
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityWelcomeBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding!!.root)
|
||||||
|
|
||||||
|
isQuiz = intent?.extras?.getBoolean("isQuiz", false) ?: false
|
||||||
|
|
||||||
|
// Enable skip button if beta flavor
|
||||||
|
if (isBetaFlavour) {
|
||||||
|
binding!!.finishTutorialButton.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val copyrightBinding = PopupForCopyrightBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
val dialog = AlertDialog.Builder(this)
|
||||||
|
.setView(copyrightBinding.root)
|
||||||
|
.setCancelable(false)
|
||||||
|
.create()
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
copyrightBinding.buttonOk.setOnClickListener { v: View? -> dialog.dismiss() }
|
||||||
|
}
|
||||||
|
|
||||||
|
val adapter = WelcomePagerAdapter()
|
||||||
|
binding!!.welcomePager.adapter = adapter
|
||||||
|
binding!!.welcomePagerIndicator.setViewPager(binding!!.welcomePager)
|
||||||
|
binding!!.finishTutorialButton.setOnClickListener { v: View? -> finishTutorial() }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onDestroy() {
|
||||||
|
if (isQuiz) {
|
||||||
|
startActivity(Intent(this, QuizActivity::class.java))
|
||||||
|
}
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (binding!!.welcomePager.currentItem != 0) {
|
||||||
|
binding!!.welcomePager.setCurrentItem(binding!!.welcomePager.currentItem - 1, true)
|
||||||
|
} else {
|
||||||
|
if (defaultKvStore.getBoolean("firstrun", true)) {
|
||||||
|
finishAffinity()
|
||||||
|
} else {
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finishTutorial() {
|
||||||
|
defaultKvStore.putBoolean("firstrun", false)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.startWelcome() {
|
||||||
|
startActivity(Intent(this, WelcomeActivity::class.java))
|
||||||
|
}
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.viewpager.widget.PagerAdapter;
|
|
||||||
import fr.free.nrw.commons.utils.UnderlineUtils;
|
|
||||||
|
|
||||||
public class WelcomePagerAdapter extends PagerAdapter {
|
|
||||||
private static final int[] PAGE_LAYOUTS = new int[]{
|
|
||||||
R.layout.welcome_wikipedia,
|
|
||||||
R.layout.welcome_do_upload,
|
|
||||||
R.layout.welcome_dont_upload,
|
|
||||||
R.layout.welcome_image_example,
|
|
||||||
R.layout.welcome_final
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets total number of layouts
|
|
||||||
* @return Number of layouts
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return PAGE_LAYOUTS.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares given view with provided object
|
|
||||||
* @param view Adapter view
|
|
||||||
* @param object Adapter object
|
|
||||||
* @return Equality between view and object
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isViewFromObject(View view, Object object) {
|
|
||||||
return (view == object);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object instantiateItem(ViewGroup container, int position) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(container.getContext());
|
|
||||||
ViewGroup layout = (ViewGroup) inflater.inflate(PAGE_LAYOUTS[position], container, false);
|
|
||||||
|
|
||||||
// If final page
|
|
||||||
if (position == PAGE_LAYOUTS.length - 1) {
|
|
||||||
// Add link to more information
|
|
||||||
TextView moreInfo = layout.findViewById(R.id.welcomeInfo);
|
|
||||||
UnderlineUtils.setUnderlinedText(moreInfo, R.string.welcome_help_button_text);
|
|
||||||
moreInfo.setOnClickListener(view -> handleWebUrl(
|
|
||||||
container.getContext(),
|
|
||||||
Uri.parse("https://commons.wikimedia.org/wiki/Help:Contents")
|
|
||||||
));
|
|
||||||
|
|
||||||
// Handle click of finishTutorialButton ("YES!" button) inside layout
|
|
||||||
layout.findViewById(R.id.finishTutorialButton)
|
|
||||||
.setOnClickListener(view -> ((WelcomeActivity) container.getContext()).finishTutorial());
|
|
||||||
}
|
|
||||||
|
|
||||||
container.addView(layout);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a way to remove an item from container
|
|
||||||
* @param container Adapter view group container
|
|
||||||
* @param position Index of item
|
|
||||||
* @param obj Adapter object
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void destroyItem(ViewGroup container, int position, Object obj) {
|
|
||||||
container.removeView((View) obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
70
app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt
Normal file
70
app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.kt
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.viewpager.widget.PagerAdapter
|
||||||
|
import fr.free.nrw.commons.utils.UnderlineUtils.setUnderlinedText
|
||||||
|
import fr.free.nrw.commons.utils.handleWebUrl
|
||||||
|
|
||||||
|
class WelcomePagerAdapter : PagerAdapter() {
|
||||||
|
/**
|
||||||
|
* Gets total number of layouts
|
||||||
|
* @return Number of layouts
|
||||||
|
*/
|
||||||
|
override fun getCount(): Int = PAGE_LAYOUTS.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares given view with provided object
|
||||||
|
* @param view Adapter view
|
||||||
|
* @param obj Adapter object
|
||||||
|
* @return Equality between view and object
|
||||||
|
*/
|
||||||
|
override fun isViewFromObject(view: View, obj: Any): Boolean = (view === obj)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a way to remove an item from container
|
||||||
|
* @param container Adapter view group container
|
||||||
|
* @param position Index of item
|
||||||
|
* @param obj Adapter object
|
||||||
|
*/
|
||||||
|
override fun destroyItem(container: ViewGroup, position: Int, obj: Any) =
|
||||||
|
container.removeView(obj as View)
|
||||||
|
|
||||||
|
override fun instantiateItem(container: ViewGroup, position: Int): Any {
|
||||||
|
val inflater = LayoutInflater.from(container.context)
|
||||||
|
val layout = inflater.inflate(PAGE_LAYOUTS[position], container, false) as ViewGroup
|
||||||
|
|
||||||
|
// If final page
|
||||||
|
if (position == PAGE_LAYOUTS.size - 1) {
|
||||||
|
// Add link to more information
|
||||||
|
val moreInfo = layout.findViewById<TextView>(R.id.welcomeInfo)
|
||||||
|
setUnderlinedText(moreInfo, R.string.welcome_help_button_text)
|
||||||
|
moreInfo.setOnClickListener {
|
||||||
|
handleWebUrl(
|
||||||
|
container.context,
|
||||||
|
"https://commons.wikimedia.org/wiki/Help:Contents".toUri()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle click of finishTutorialButton ("YES!" button) inside layout
|
||||||
|
layout.findViewById<View>(R.id.finishTutorialButton)
|
||||||
|
.setOnClickListener { view: View? -> (container.context as WelcomeActivity).finishTutorial() }
|
||||||
|
}
|
||||||
|
|
||||||
|
container.addView(layout)
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val PAGE_LAYOUTS = intArrayOf(
|
||||||
|
R.layout.welcome_wikipedia,
|
||||||
|
R.layout.welcome_do_upload,
|
||||||
|
R.layout.welcome_dont_upload,
|
||||||
|
R.layout.welcome_image_example,
|
||||||
|
R.layout.welcome_final
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
supportFragmentManager = getSupportFragmentManager()
|
supportFragmentManager = getSupportFragmentManager()
|
||||||
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
|
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
|
||||||
binding.viewPager.adapter = viewPagerAdapter
|
binding.viewPager.adapter = viewPagerAdapter
|
||||||
binding.viewPager.offscreenPageLimit = 2
|
binding.viewPager.offscreenPageLimit = 2
|
||||||
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
||||||
|
|
@ -83,8 +83,6 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
* Set the fragments according to the tab selected in the viewPager.
|
* Set the fragments according to the tab selected in the viewPager.
|
||||||
*/
|
*/
|
||||||
private fun setTabs() {
|
private fun setTabs() {
|
||||||
val fragmentList = mutableListOf<Fragment>()
|
|
||||||
val titleList = mutableListOf<String>()
|
|
||||||
categoriesMediaFragment = CategoriesMediaFragment()
|
categoriesMediaFragment = CategoriesMediaFragment()
|
||||||
val subCategoryListFragment = SubCategoriesFragment()
|
val subCategoryListFragment = SubCategoriesFragment()
|
||||||
val parentCategoriesFragment = ParentCategoriesFragment()
|
val parentCategoriesFragment = ParentCategoriesFragment()
|
||||||
|
|
@ -99,13 +97,12 @@ class CategoryDetailsActivity : BaseActivity(),
|
||||||
|
|
||||||
viewModel.onCheckIfBookmarked(categoryName!!)
|
viewModel.onCheckIfBookmarked(categoryName!!)
|
||||||
}
|
}
|
||||||
fragmentList.add(categoriesMediaFragment)
|
|
||||||
titleList.add("MEDIA")
|
viewPagerAdapter.setTabs(
|
||||||
fragmentList.add(subCategoryListFragment)
|
R.string.title_for_media to categoriesMediaFragment,
|
||||||
titleList.add("SUBCATEGORIES")
|
R.string.title_for_subcategories to subCategoryListFragment,
|
||||||
fragmentList.add(parentCategoriesFragment)
|
R.string.title_for_parent_categories to parentCategoriesFragment
|
||||||
titleList.add("PARENT CATEGORIES")
|
)
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList)
|
|
||||||
viewPagerAdapter.notifyDataSetChanged()
|
viewPagerAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import androidx.fragment.app.FragmentManager
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.WelcomeActivity
|
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.bookmarks.BookmarkFragment
|
import fr.free.nrw.commons.bookmarks.BookmarkFragment
|
||||||
import fr.free.nrw.commons.contributions.ContributionsFragment.Companion.newInstance
|
import fr.free.nrw.commons.contributions.ContributionsFragment.Companion.newInstance
|
||||||
|
|
@ -33,6 +32,7 @@ import fr.free.nrw.commons.notification.NotificationActivity.Companion.startYour
|
||||||
import fr.free.nrw.commons.notification.NotificationController
|
import fr.free.nrw.commons.notification.NotificationController
|
||||||
import fr.free.nrw.commons.quiz.QuizChecker
|
import fr.free.nrw.commons.quiz.QuizChecker
|
||||||
import fr.free.nrw.commons.settings.SettingsFragment
|
import fr.free.nrw.commons.settings.SettingsFragment
|
||||||
|
import fr.free.nrw.commons.startWelcome
|
||||||
import fr.free.nrw.commons.theme.BaseActivity
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
import fr.free.nrw.commons.upload.UploadProgressActivity
|
import fr.free.nrw.commons.upload.UploadProgressActivity
|
||||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
|
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
|
||||||
|
|
@ -517,7 +517,7 @@ after opening the app.
|
||||||
(!applicationKvStore!!.getBoolean("login_skipped"))
|
(!applicationKvStore!!.getBoolean("login_skipped"))
|
||||||
) {
|
) {
|
||||||
defaultKvStore.putBoolean("inAppCameraFirstRun", true)
|
defaultKvStore.putBoolean("inAppCameraFirstRun", true)
|
||||||
WelcomeActivity.startYourself(this)
|
startWelcome()
|
||||||
}
|
}
|
||||||
|
|
||||||
retryAllFailedUploads()
|
retryAllFailedUploads()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package fr.free.nrw.commons.explore;
|
package fr.free.nrw.commons.explore;
|
||||||
|
|
||||||
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
|
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
|
||||||
|
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
@ -23,10 +24,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.theme.BaseActivity;
|
import fr.free.nrw.commons.theme.BaseActivity;
|
||||||
import fr.free.nrw.commons.utils.ActivityUtils;
|
import fr.free.nrw.commons.utils.ActivityUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import kotlin.Pair;
|
||||||
|
|
||||||
public class ExploreFragment extends CommonsDaggerSupportFragment {
|
public class ExploreFragment extends CommonsDaggerSupportFragment {
|
||||||
|
|
||||||
|
|
@ -70,7 +73,7 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
|
||||||
loadNearbyMapData();
|
loadNearbyMapData();
|
||||||
binding = FragmentExploreBinding.inflate(inflater, container, false);
|
binding = FragmentExploreBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager(),
|
viewPagerAdapter = new ViewPagerAdapter(requireContext(), getChildFragmentManager(),
|
||||||
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||||
|
|
||||||
binding.viewPager.setAdapter(viewPagerAdapter);
|
binding.viewPager.setAdapter(viewPagerAdapter);
|
||||||
|
|
@ -111,9 +114,6 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
|
||||||
* Sets the titles in the tabLayout and fragments in the viewPager
|
* Sets the titles in the tabLayout and fragments in the viewPager
|
||||||
*/
|
*/
|
||||||
public void setTabs() {
|
public void setTabs() {
|
||||||
List<Fragment> fragmentList = new ArrayList<>();
|
|
||||||
List<String> titleList = new ArrayList<>();
|
|
||||||
|
|
||||||
Bundle featuredArguments = new Bundle();
|
Bundle featuredArguments = new Bundle();
|
||||||
featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY);
|
featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY);
|
||||||
|
|
||||||
|
|
@ -133,19 +133,15 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
|
||||||
featuredRootFragment = new ExploreListRootFragment(featuredArguments);
|
featuredRootFragment = new ExploreListRootFragment(featuredArguments);
|
||||||
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
|
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
|
||||||
mapRootFragment = new ExploreMapRootFragment(mapArguments);
|
mapRootFragment = new ExploreMapRootFragment(mapArguments);
|
||||||
fragmentList.add(featuredRootFragment);
|
|
||||||
titleList.add(getString(R.string.explore_tab_title_featured).toUpperCase(Locale.ROOT));
|
|
||||||
|
|
||||||
fragmentList.add(mobileRootFragment);
|
|
||||||
titleList.add(getString(R.string.explore_tab_title_mobile).toUpperCase(Locale.ROOT));
|
|
||||||
|
|
||||||
fragmentList.add(mapRootFragment);
|
|
||||||
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase(Locale.ROOT));
|
|
||||||
|
|
||||||
((MainActivity) getActivity()).showTabs();
|
((MainActivity) getActivity()).showTabs();
|
||||||
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
|
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
viewPagerAdapter.setTabs(
|
||||||
|
pairOf(R.string.explore_tab_title_featured, featuredRootFragment),
|
||||||
|
pairOf(R.string.explore_tab_title_mobile, mobileRootFragment),
|
||||||
|
pairOf(R.string.explore_tab_title_map, mapRootFragment)
|
||||||
|
);
|
||||||
viewPagerAdapter.notifyDataSetChanged();
|
viewPagerAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package fr.free.nrw.commons.explore;
|
package fr.free.nrw.commons.explore;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
@ -26,11 +28,13 @@ import fr.free.nrw.commons.utils.FragmentUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import kotlin.Pair;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -65,7 +69,7 @@ public class SearchActivity extends BaseActivity
|
||||||
binding.toolbarSearch.setNavigationOnClickListener(v->onBackPressed());
|
binding.toolbarSearch.setNavigationOnClickListener(v->onBackPressed());
|
||||||
supportFragmentManager = getSupportFragmentManager();
|
supportFragmentManager = getSupportFragmentManager();
|
||||||
setSearchHistoryFragment();
|
setSearchHistoryFragment();
|
||||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
|
viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
|
||||||
binding.viewPager.setAdapter(viewPagerAdapter);
|
binding.viewPager.setAdapter(viewPagerAdapter);
|
||||||
binding.viewPager.setOffscreenPageLimit(2); // Because we want all the fragments to be alive
|
binding.viewPager.setOffscreenPageLimit(2); // Because we want all the fragments to be alive
|
||||||
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
||||||
|
|
@ -90,19 +94,15 @@ public class SearchActivity extends BaseActivity
|
||||||
* Sets the titles in the tabLayout and fragments in the viewPager
|
* Sets the titles in the tabLayout and fragments in the viewPager
|
||||||
*/
|
*/
|
||||||
public void setTabs() {
|
public void setTabs() {
|
||||||
List<Fragment> fragmentList = new ArrayList<>();
|
|
||||||
List<String> titleList = new ArrayList<>();
|
|
||||||
searchMediaFragment = new SearchMediaFragment();
|
searchMediaFragment = new SearchMediaFragment();
|
||||||
searchDepictionsFragment = new SearchDepictionsFragment();
|
searchDepictionsFragment = new SearchDepictionsFragment();
|
||||||
searchCategoryFragment= new SearchCategoryFragment();
|
searchCategoryFragment= new SearchCategoryFragment();
|
||||||
fragmentList.add(searchMediaFragment);
|
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_media).toUpperCase(Locale.ROOT));
|
|
||||||
fragmentList.add(searchCategoryFragment);
|
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_categories).toUpperCase(Locale.ROOT));
|
|
||||||
fragmentList.add(searchDepictionsFragment);
|
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_depictions).toUpperCase(Locale.ROOT));
|
|
||||||
|
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
viewPagerAdapter.setTabs(
|
||||||
|
pairOf(R.string.search_tab_title_media, searchMediaFragment),
|
||||||
|
pairOf(R.string.search_tab_title_categories, searchCategoryFragment),
|
||||||
|
pairOf(R.string.search_tab_title_depictions, searchDepictionsFragment)
|
||||||
|
);
|
||||||
viewPagerAdapter.notifyDataSetChanged();
|
viewPagerAdapter.notifyDataSetChanged();
|
||||||
getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox)
|
getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox)
|
||||||
.takeUntil(RxView.detaches(binding.searchBox))
|
.takeUntil(RxView.detaches(binding.searchBox))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.explore.depictions;
|
package fr.free.nrw.commons.explore.depictions;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
|
||||||
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
|
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -31,8 +32,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import kotlin.Pair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
|
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
|
||||||
|
|
@ -66,7 +69,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
compositeDisposable = new CompositeDisposable();
|
compositeDisposable = new CompositeDisposable();
|
||||||
supportFragmentManager = getSupportFragmentManager();
|
supportFragmentManager = getSupportFragmentManager();
|
||||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
|
viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
|
||||||
binding.viewPager.setAdapter(viewPagerAdapter);
|
binding.viewPager.setAdapter(viewPagerAdapter);
|
||||||
binding.viewPager.setOffscreenPageLimit(2);
|
binding.viewPager.setOffscreenPageLimit(2);
|
||||||
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
||||||
|
|
@ -105,8 +108,6 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
||||||
* Set the fragments according to the tab selected in the viewPager.
|
* Set the fragments according to the tab selected in the viewPager.
|
||||||
*/
|
*/
|
||||||
private void setTabs() {
|
private void setTabs() {
|
||||||
List<Fragment> fragmentList = new ArrayList<>();
|
|
||||||
List<String> titleList = new ArrayList<>();
|
|
||||||
depictionImagesListFragment = new DepictedImagesFragment();
|
depictionImagesListFragment = new DepictedImagesFragment();
|
||||||
ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment();
|
ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment();
|
||||||
ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment();
|
ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment();
|
||||||
|
|
@ -120,13 +121,12 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
|
||||||
parentDepictionsFragment.setArguments(arguments);
|
parentDepictionsFragment.setArguments(arguments);
|
||||||
childDepictionsFragment.setArguments(arguments);
|
childDepictionsFragment.setArguments(arguments);
|
||||||
}
|
}
|
||||||
fragmentList.add(depictionImagesListFragment);
|
|
||||||
titleList.add(getResources().getString(R.string.title_for_media));
|
viewPagerAdapter.setTabs(
|
||||||
fragmentList.add(childDepictionsFragment);
|
pairOf(R.string.title_for_media, depictionImagesListFragment),
|
||||||
titleList.add(getResources().getString(R.string.title_for_child_classes));
|
pairOf(R.string.title_for_subcategories, childDepictionsFragment),
|
||||||
fragmentList.add(parentDepictionsFragment);
|
pairOf(R.string.title_for_parent_categories, parentDepictionsFragment)
|
||||||
titleList.add(getResources().getString(R.string.title_for_parent_classes));
|
);
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
|
||||||
binding.viewPager.setOffscreenPageLimit(2);
|
binding.viewPager.setOffscreenPageLimit(2);
|
||||||
viewPagerAdapter.notifyDataSetChanged();
|
viewPagerAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package fr.free.nrw.commons.explore.map;
|
package fr.free.nrw.commons.explore.map;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
import fr.free.nrw.commons.media.MediaClient;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
@ -23,6 +25,7 @@ public class ExploreMapCalls {
|
||||||
* @param currentLatLng coordinates of search location
|
* @param currentLatLng coordinates of search location
|
||||||
* @return list of places obtained
|
* @return list of places obtained
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
List<Media> callCommonsQuery(final LatLng currentLatLng) {
|
List<Media> callCommonsQuery(final LatLng currentLatLng) {
|
||||||
String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude();
|
String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude();
|
||||||
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet();
|
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet();
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import fr.free.nrw.commons.explore.map.ExploreMapController.NearbyBaseMarkerThum
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
||||||
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -182,7 +183,7 @@ public class ExploreMapPresenter
|
||||||
exploreMapController
|
exploreMapController
|
||||||
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
|
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
|
||||||
// Curlatlang will be used to calculate distances
|
// Curlatlang will be used to calculate distances
|
||||||
explorePlacesInfo.explorePlaceList,
|
(List<Place>) explorePlacesInfo.explorePlaceList,
|
||||||
exploreMapFragmentView.getContext(),
|
exploreMapFragmentView.getContext(),
|
||||||
this,
|
this,
|
||||||
explorePlacesInfo);
|
explorePlacesInfo);
|
||||||
|
|
@ -230,11 +231,7 @@ public class ExploreMapPresenter
|
||||||
mylocation.setLongitude(exploreMapFragmentView.getLastMapFocus().getLongitude());
|
mylocation.setLongitude(exploreMapFragmentView.getLastMapFocus().getLongitude());
|
||||||
Float distance = mylocation.distanceTo(dest_location);
|
Float distance = mylocation.distanceTo(dest_location);
|
||||||
|
|
||||||
if (distance > 2000.0 * 3 / 4) {
|
return !(distance > 2000.0 * 3 / 4);
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package fr.free.nrw.commons.media
|
package fr.free.nrw.commons.media
|
||||||
|
|
||||||
import fr.free.nrw.commons.OkHttpConnectionFactory.UnsuccessfulResponseInterceptor.SUPPRESS_ERROR_LOG_HEADER
|
import fr.free.nrw.commons.SUPPRESS_ERROR_LOG_HEADER
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import fr.free.nrw.commons.BuildConfig
|
||||||
import fr.free.nrw.commons.CommonsApplication
|
import fr.free.nrw.commons.CommonsApplication
|
||||||
import fr.free.nrw.commons.CommonsApplication.ActivityLogoutListener
|
import fr.free.nrw.commons.CommonsApplication.ActivityLogoutListener
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.WelcomeActivity
|
|
||||||
import fr.free.nrw.commons.actions.PageEditClient
|
import fr.free.nrw.commons.actions.PageEditClient
|
||||||
import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding
|
import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection
|
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||||
|
|
@ -32,6 +31,7 @@ import fr.free.nrw.commons.logging.CommonsLogSender
|
||||||
import fr.free.nrw.commons.profile.ProfileActivity
|
import fr.free.nrw.commons.profile.ProfileActivity
|
||||||
import fr.free.nrw.commons.review.ReviewActivity
|
import fr.free.nrw.commons.review.ReviewActivity
|
||||||
import fr.free.nrw.commons.settings.SettingsActivity
|
import fr.free.nrw.commons.settings.SettingsActivity
|
||||||
|
import fr.free.nrw.commons.startWelcome
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
@ -241,7 +241,7 @@ class MoreBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onTutorialClicked() {
|
fun onTutorialClicked() {
|
||||||
WelcomeActivity.startYourself(requireActivity())
|
requireContext().startWelcome()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSettingsClicked() {
|
fun onSettingsClicked() {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.nearby.model.NearbyQueryParams;
|
import fr.free.nrw.commons.nearby.model.NearbyQueryParams;
|
||||||
|
import fr.free.nrw.commons.nearby.model.NearbyQueryParams.Radial;
|
||||||
|
import fr.free.nrw.commons.nearby.model.NearbyQueryParams.Rectangular;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -46,13 +50,14 @@ public class NearbyPlaces {
|
||||||
* @param customQuery
|
* @param customQuery
|
||||||
* @return list of places obtained
|
* @return list of places obtained
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
List<Place> radiusExpander(final LatLng currentLatLng, final String lang,
|
List<Place> radiusExpander(final LatLng currentLatLng, final String lang,
|
||||||
final boolean returnClosestResult, @Nullable final String customQuery) throws Exception {
|
final boolean returnClosestResult, @Nullable final String customQuery) throws Exception {
|
||||||
|
|
||||||
final int minResults;
|
final int minResults;
|
||||||
final double maxRadius;
|
final double maxRadius;
|
||||||
|
|
||||||
List<Place> places = Collections.emptyList();
|
List<Place> places = emptyList();
|
||||||
|
|
||||||
// If returnClosestResult is true, then this means that we are trying to get closest point
|
// If returnClosestResult is true, then this means that we are trying to get closest point
|
||||||
// to use in cardView in Contributions fragment
|
// to use in cardView in Contributions fragment
|
||||||
|
|
@ -113,6 +118,7 @@ public class NearbyPlaces {
|
||||||
* @return A list of places obtained from the Wikidata query.
|
* @return A list of places obtained from the Wikidata query.
|
||||||
* @throws Exception If an error occurs during the retrieval process.
|
* @throws Exception If an error occurs during the retrieval process.
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
public List<Place> getFromWikidataQuery(
|
public List<Place> getFromWikidataQuery(
|
||||||
final fr.free.nrw.commons.location.LatLng centerPoint,
|
final fr.free.nrw.commons.location.LatLng centerPoint,
|
||||||
final fr.free.nrw.commons.location.LatLng screenTopRight,
|
final fr.free.nrw.commons.location.LatLng screenTopRight,
|
||||||
|
|
@ -120,11 +126,11 @@ public class NearbyPlaces {
|
||||||
final boolean shouldQueryForMonuments,
|
final boolean shouldQueryForMonuments,
|
||||||
@Nullable final String customQuery) throws Exception {
|
@Nullable final String customQuery) throws Exception {
|
||||||
if (customQuery != null) {
|
if (customQuery != null) {
|
||||||
return okHttpJsonApiClient
|
final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
|
||||||
.getNearbyPlaces(
|
new Rectangular(screenTopRight, screenBottomLeft), lang,
|
||||||
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang,
|
|
||||||
shouldQueryForMonuments,
|
shouldQueryForMonuments,
|
||||||
customQuery);
|
customQuery);
|
||||||
|
return nearbyPlaces != null ? nearbyPlaces : emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
final int lowerLimit = 1000, upperLimit = 1500;
|
final int lowerLimit = 1000, upperLimit = 1500;
|
||||||
|
|
@ -141,9 +147,10 @@ public class NearbyPlaces {
|
||||||
final int itemCount = okHttpJsonApiClient.getNearbyItemCount(
|
final int itemCount = okHttpJsonApiClient.getNearbyItemCount(
|
||||||
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft));
|
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft));
|
||||||
if (itemCount < upperLimit) {
|
if (itemCount < upperLimit) {
|
||||||
return okHttpJsonApiClient.getNearbyPlaces(
|
final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
|
||||||
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang,
|
new Rectangular(screenTopRight, screenBottomLeft), lang,
|
||||||
shouldQueryForMonuments, null);
|
shouldQueryForMonuments, null);
|
||||||
|
return nearbyPlaces != null ? nearbyPlaces : emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,9 +182,10 @@ public class NearbyPlaces {
|
||||||
maxRadius = targetRadius - 1;
|
maxRadius = targetRadius - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return okHttpJsonApiClient.getNearbyPlaces(
|
final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
|
||||||
new NearbyQueryParams.Radial(centerPoint, targetRadius / 100f), lang, shouldQueryForMonuments,
|
new Radial(centerPoint, targetRadius / 100f), lang, shouldQueryForMonuments,
|
||||||
null);
|
null);
|
||||||
|
return nearbyPlaces != null ? nearbyPlaces : emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.ViewPagerAdapter
|
import fr.free.nrw.commons.ViewPagerAdapter
|
||||||
|
|
@ -71,7 +72,7 @@ class ProfileActivity : BaseActivity() {
|
||||||
title = userName
|
title = userName
|
||||||
shouldShowContributions = intent.getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false)
|
shouldShowContributions = intent.getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false)
|
||||||
|
|
||||||
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
|
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
|
||||||
binding.viewPager.adapter = viewPagerAdapter
|
binding.viewPager.adapter = viewPagerAdapter
|
||||||
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
||||||
setTabs()
|
setTabs()
|
||||||
|
|
@ -83,39 +84,23 @@ class ProfileActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setTabs() {
|
private fun setTabs() {
|
||||||
val fragmentList = mutableListOf<Fragment>()
|
|
||||||
val titleList = mutableListOf<String>()
|
|
||||||
|
|
||||||
// Add Achievements tab
|
|
||||||
achievementsFragment = AchievementsFragment().apply {
|
achievementsFragment = AchievementsFragment().apply {
|
||||||
arguments = Bundle().apply {
|
arguments = bundleOf(KEY_USERNAME to userName)
|
||||||
putString(KEY_USERNAME, userName)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fragmentList.add(achievementsFragment)
|
|
||||||
titleList.add(resources.getString(R.string.achievements_tab_title).uppercase())
|
|
||||||
|
|
||||||
// Add Leaderboard tab
|
|
||||||
leaderboardFragment = LeaderboardFragment().apply {
|
leaderboardFragment = LeaderboardFragment().apply {
|
||||||
arguments = Bundle().apply {
|
arguments = bundleOf(KEY_USERNAME to userName)
|
||||||
putString(KEY_USERNAME, userName)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fragmentList.add(leaderboardFragment)
|
|
||||||
titleList.add(resources.getString(R.string.leaderboard_tab_title).uppercase(Locale.ROOT))
|
|
||||||
|
|
||||||
// Add Contributions tab
|
|
||||||
contributionsFragment = ContributionsFragment().apply {
|
contributionsFragment = ContributionsFragment().apply {
|
||||||
arguments = Bundle().apply {
|
arguments = bundleOf(KEY_USERNAME to userName)
|
||||||
putString(KEY_USERNAME, userName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contributionsFragment?.let {
|
|
||||||
fragmentList.add(it)
|
|
||||||
titleList.add(getString(R.string.contributions_fragment).uppercase(Locale.ROOT))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList)
|
viewPagerAdapter.setTabs(
|
||||||
|
R.string.achievements_tab_title to achievementsFragment,
|
||||||
|
R.string.leaderboard_tab_title to leaderboardFragment,
|
||||||
|
R.string.contributions_fragment to contributionsFragment!!
|
||||||
|
)
|
||||||
viewPagerAdapter.notifyDataSetChanged()
|
viewPagerAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ class UploadProgressActivity : BaseActivity() {
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var contributionDao: ContributionDao
|
lateinit var contributionDao: ContributionDao
|
||||||
|
|
||||||
val fragmentList: MutableList<Fragment> = ArrayList()
|
|
||||||
val titleList: MutableList<String> = ArrayList()
|
|
||||||
var isPaused = true
|
var isPaused = true
|
||||||
var isPendingIconsVisible = true
|
var isPendingIconsVisible = true
|
||||||
var isErrorIconsVisisble = false
|
var isErrorIconsVisisble = false
|
||||||
|
|
@ -38,7 +36,7 @@ class UploadProgressActivity : BaseActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityUploadProgressBinding.inflate(layoutInflater)
|
binding = ActivityUploadProgressBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
|
viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
|
||||||
binding.uploadProgressViewPager.setAdapter(viewPagerAdapter)
|
binding.uploadProgressViewPager.setAdapter(viewPagerAdapter)
|
||||||
binding.uploadProgressViewPager.setId(R.id.upload_progress_view_pager)
|
binding.uploadProgressViewPager.setId(R.id.upload_progress_view_pager)
|
||||||
binding.uploadProgressTabLayout.setupWithViewPager(binding.uploadProgressViewPager)
|
binding.uploadProgressTabLayout.setupWithViewPager(binding.uploadProgressViewPager)
|
||||||
|
|
@ -81,11 +79,10 @@ class UploadProgressActivity : BaseActivity() {
|
||||||
pendingUploadsFragment = PendingUploadsFragment()
|
pendingUploadsFragment = PendingUploadsFragment()
|
||||||
failedUploadsFragment = FailedUploadsFragment()
|
failedUploadsFragment = FailedUploadsFragment()
|
||||||
|
|
||||||
fragmentList.add(pendingUploadsFragment!!)
|
viewPagerAdapter!!.setTabs(
|
||||||
titleList.add(getString(R.string.pending))
|
R.string.pending to pendingUploadsFragment!!,
|
||||||
fragmentList.add(failedUploadsFragment!!)
|
R.string.failed to failedUploadsFragment!!
|
||||||
titleList.add(getString(R.string.failed))
|
)
|
||||||
viewPagerAdapter!!.setTabData(fragmentList, titleList)
|
|
||||||
viewPagerAdapter!!.notifyDataSetChanged()
|
viewPagerAdapter!!.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -617,6 +617,8 @@ Upload your first media by tapping on the add button.</string>
|
||||||
<string name="title_for_media">MEDIA</string>
|
<string name="title_for_media">MEDIA</string>
|
||||||
<string name="title_for_child_classes">CHILD CLASSES</string>
|
<string name="title_for_child_classes">CHILD CLASSES</string>
|
||||||
<string name="title_for_parent_classes">PARENT CLASSES</string>
|
<string name="title_for_parent_classes">PARENT CLASSES</string>
|
||||||
|
<string name="title_for_subcategories">SUBCATEGORIES</string>
|
||||||
|
<string name="title_for_parent_categories">PARENT CATEGORIES</string>
|
||||||
|
|
||||||
<string name="upload_nearby_place_found_title">Nearby Place Found</string>
|
<string name="upload_nearby_place_found_title">Nearby Place Found</string>
|
||||||
<string name="upload_nearby_place_found_description_plural">Are these pictures of %1$s?</string>
|
<string name="upload_nearby_place_found_description_plural">Are these pictures of %1$s?</string>
|
||||||
|
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.TestConnectionFactoryKt.createTestClient;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.AbstractExecutorService;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import okhttp3.Dispatcher;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import fr.free.nrw.commons.wikidata.GsonUtil;
|
|
||||||
import retrofit2.Retrofit;
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public abstract class MockWebServerTest {
|
|
||||||
private OkHttpClient okHttpClient;
|
|
||||||
private final TestWebServer server = new TestWebServer();
|
|
||||||
|
|
||||||
@Before public void setUp() throws Throwable {
|
|
||||||
OkHttpConnectionFactory.CLIENT = createTestClient();
|
|
||||||
okHttpClient = OkHttpConnectionFactory.CLIENT.newBuilder()
|
|
||||||
.dispatcher(new Dispatcher(new ImmediateExecutorService())).build();
|
|
||||||
server.setUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After public void tearDown() throws Throwable {
|
|
||||||
server.tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull protected TestWebServer server() {
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void enqueueFromFile(@NonNull String filename) throws Throwable {
|
|
||||||
String json = TestFileUtil.readRawFile(filename);
|
|
||||||
server.enqueue(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void enqueue404() {
|
|
||||||
final int code = 404;
|
|
||||||
server.enqueue(new MockResponse().setResponseCode(code).setBody("Not Found"));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void enqueueMalformed() {
|
|
||||||
server.enqueue("(╯°□°)╯︵ ┻━┻");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void enqueueEmptyJson() {
|
|
||||||
server.enqueue(new MockResponse().setBody("{}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull protected OkHttpClient okHttpClient() {
|
|
||||||
return okHttpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull protected <T> T service(Class<T> clazz) {
|
|
||||||
return service(clazz, server().getUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull protected <T> T service(Class<T> clazz, @NonNull String url) {
|
|
||||||
return new Retrofit.Builder()
|
|
||||||
.baseUrl(url)
|
|
||||||
.callbackExecutor(new ImmediateExecutor())
|
|
||||||
.client(okHttpClient)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create(GsonUtil.INSTANCE.getDefaultGson()))
|
|
||||||
.build()
|
|
||||||
.create(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class ImmediateExecutorService extends AbstractExecutorService {
|
|
||||||
@Override public void shutdown() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull @Override public List<Runnable> shutdownNow() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isShutdown() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isTerminated() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean awaitTermination(long l, @NonNull TimeUnit timeUnit)
|
|
||||||
throws InterruptedException {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void execute(@NonNull Runnable runnable) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ImmediateExecutor implements Executor {
|
|
||||||
@Override
|
|
||||||
public void execute(@NonNull Runnable runnable) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
110
app/src/test/kotlin/fr/free/nrw/commons/MockWebServerTest.kt
Normal file
110
app/src/test/kotlin/fr/free/nrw/commons/MockWebServerTest.kt
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.wikidata.GsonUtil.defaultGson
|
||||||
|
import okhttp3.Dispatcher
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.mockwebserver.MockResponse
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import java.util.concurrent.AbstractExecutorService
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
abstract class MockWebServerTest {
|
||||||
|
private var okHttpClient: OkHttpClient? = null
|
||||||
|
private val server = TestWebServer()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
open fun setUp() {
|
||||||
|
OkHttpConnectionFactory.CLIENT = createTestClient()
|
||||||
|
okHttpClient = OkHttpConnectionFactory.CLIENT!!.newBuilder()
|
||||||
|
.dispatcher(Dispatcher(ImmediateExecutorService())).build()
|
||||||
|
server.setUp()
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
fun tearDown() {
|
||||||
|
server.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun server(): TestWebServer {
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
protected fun enqueueFromFile(filename: String) {
|
||||||
|
val json = TestFileUtil.readRawFile(filename)
|
||||||
|
server.enqueue(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun enqueue404() {
|
||||||
|
val code = 404
|
||||||
|
server.enqueue(MockResponse().setResponseCode(code).setBody("Not Found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun enqueueMalformed() {
|
||||||
|
server.enqueue("(╯°□°)╯︵ ┻━┻")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun enqueueEmptyJson() {
|
||||||
|
server.enqueue(MockResponse().setBody("{}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun okHttpClient(): OkHttpClient {
|
||||||
|
return okHttpClient!!
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun <T> service(clazz: Class<T>): T {
|
||||||
|
return service(clazz, server().url)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun <T> service(clazz: Class<T>, url: String): T {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(url)
|
||||||
|
.callbackExecutor(ImmediateExecutor())
|
||||||
|
.client(okHttpClient)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create(defaultGson))
|
||||||
|
.build()
|
||||||
|
.create(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ImmediateExecutorService : AbstractExecutorService() {
|
||||||
|
override fun shutdown() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shutdownNow(): List<Runnable> {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isShutdown(): Boolean {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTerminated(): Boolean {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
override fun awaitTermination(l: Long, timeUnit: TimeUnit): Boolean {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun execute(runnable: Runnable) {
|
||||||
|
runnable.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ImmediateExecutor : Executor {
|
||||||
|
override fun execute(runnable: Runnable) {
|
||||||
|
runnable.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package fr.free.nrw.commons
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
import fr.free.nrw.commons.OkHttpConnectionFactory.HttpStatusException
|
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
@ -39,6 +38,6 @@ private class UnsuccessfulResponseInterceptor : Interceptor {
|
||||||
if (rsp.isSuccessful) {
|
if (rsp.isSuccessful) {
|
||||||
return rsp
|
return rsp
|
||||||
}
|
}
|
||||||
throw HttpStatusException(rsp)
|
throw IOException("Unsuccessful response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package fr.free.nrw.commons.auth.csrf
|
||||||
|
|
||||||
import com.google.gson.stream.MalformedJsonException
|
import com.google.gson.stream.MalformedJsonException
|
||||||
import fr.free.nrw.commons.MockWebServerTest
|
import fr.free.nrw.commons.MockWebServerTest
|
||||||
import fr.free.nrw.commons.OkHttpConnectionFactory.HttpStatusException
|
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.auth.login.LoginClient
|
import fr.free.nrw.commons.auth.login.LoginClient
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwException
|
import fr.free.nrw.commons.wikidata.mwapi.MwException
|
||||||
|
|
@ -13,6 +12,7 @@ import org.mockito.ArgumentMatchers.isA
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.Mockito.never
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
class CsrfTokenClientTest : MockWebServerTest() {
|
class CsrfTokenClientTest : MockWebServerTest() {
|
||||||
private val cb = mock(CsrfTokenClient.Callback::class.java)
|
private val cb = mock(CsrfTokenClient.Callback::class.java)
|
||||||
|
|
@ -53,7 +53,7 @@ class CsrfTokenClientTest : MockWebServerTest() {
|
||||||
performRequest()
|
performRequest()
|
||||||
|
|
||||||
verify(cb, never()).success(any(String::class.java))
|
verify(cb, never()).success(any(String::class.java))
|
||||||
verify(cb).failure(isA(HttpStatusException::class.java))
|
verify(cb).failure(isA(IOException::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue