mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 14:53:59 +01:00 
			
		
		
		
	Merge branch 'main' into fix-issues
This commit is contained in:
		
						commit
						7a932ef61f
					
				
					 8 changed files with 348 additions and 427 deletions
				
			
		|  | @ -105,7 +105,7 @@ class AboutActivityTest { | ||||||
|     fun testLaunchTranslate() { |     fun testLaunchTranslate() { | ||||||
|         Espresso.onView(ViewMatchers.withId(R.id.about_translate)).perform(ViewActions.click()) |         Espresso.onView(ViewMatchers.withId(R.id.about_translate)).perform(ViewActions.click()) | ||||||
|         Espresso.onView(ViewMatchers.withId(android.R.id.button1)).perform(ViewActions.click()) |         Espresso.onView(ViewMatchers.withId(android.R.id.button1)).perform(ViewActions.click()) | ||||||
|         val langCode = CommonsApplication.instance.languageLookUpTable!!.codes[0] |         val langCode = CommonsApplication.instance.languageLookUpTable!!.getCodes()[0] | ||||||
|         Intents.intended( |         Intents.intended( | ||||||
|             CoreMatchers.allOf( |             CoreMatchers.allOf( | ||||||
|                 IntentMatchers.hasAction(Intent.ACTION_VIEW), |                 IntentMatchers.hasAction(Intent.ACTION_VIEW), | ||||||
|  |  | ||||||
|  | @ -44,7 +44,6 @@ import okhttp3.logging.HttpLoggingInterceptor | ||||||
| import okhttp3.logging.HttpLoggingInterceptor.Level | import okhttp3.logging.HttpLoggingInterceptor.Level | ||||||
| import timber.log.Timber | import timber.log.Timber | ||||||
| import java.io.File | import java.io.File | ||||||
| import java.util.Locale |  | ||||||
| import java.util.concurrent.TimeUnit | import java.util.concurrent.TimeUnit | ||||||
| import javax.inject.Named | import javax.inject.Named | ||||||
| import javax.inject.Singleton | import javax.inject.Singleton | ||||||
|  | @ -293,9 +292,8 @@ class NetworkingModule { | ||||||
|     @Provides |     @Provides | ||||||
|     @Singleton |     @Singleton | ||||||
|     @Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE) |     @Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE) | ||||||
|     fun provideLanguageWikipediaSite(): WikiSite { |     fun provideLanguageWikipediaSite(): WikiSite = | ||||||
|         return WikiSite.forLanguageCode(Locale.getDefault().language) |         WikiSite.forDefaultLocaleLanguageCode() | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     companion object { |     companion object { | ||||||
|         private const val WIKIDATA_SPARQL_QUERY_URL = "https://query.wikidata.org/sparql" |         private const val WIKIDATA_SPARQL_QUERY_URL = "https://query.wikidata.org/sparql" | ||||||
|  |  | ||||||
|  | @ -1,24 +0,0 @@ | ||||||
| package fr.free.nrw.commons.wikidata.model; |  | ||||||
| 
 |  | ||||||
| import java.util.List; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Model class for API response obtained from search for depictions |  | ||||||
|  */ |  | ||||||
| public class DepictSearchResponse { |  | ||||||
|     private final List<DepictSearchItem> search; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Constructor to initialise value of the search object |  | ||||||
|      */ |  | ||||||
|     public DepictSearchResponse(List<DepictSearchItem> search) { |  | ||||||
|         this.search = search; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return List<DepictSearchItem> for the DepictSearchResponse |  | ||||||
|      */ |  | ||||||
|     public List<DepictSearchItem> getSearch() { |  | ||||||
|         return search; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | package fr.free.nrw.commons.wikidata.model | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Model class for API response obtained from search for depictions | ||||||
|  |  */ | ||||||
|  | class DepictSearchResponse( | ||||||
|  |     /** | ||||||
|  |      * @return List<DepictSearchItem> for the DepictSearchResponse | ||||||
|  |     </DepictSearchItem> | ||||||
|  |      */ | ||||||
|  |     val search: List<DepictSearchItem> | ||||||
|  | ) | ||||||
|  | @ -1,106 +0,0 @@ | ||||||
| package fr.free.nrw.commons.wikidata.model; |  | ||||||
| 
 |  | ||||||
| import androidx.annotation.NonNull; |  | ||||||
| import androidx.annotation.Nullable; |  | ||||||
| import com.google.gson.annotations.SerializedName; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import org.apache.commons.lang3.StringUtils; |  | ||||||
| import org.jetbrains.annotations.NotNull; |  | ||||||
| import fr.free.nrw.commons.wikidata.mwapi.MwResponse; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| public class Entities extends MwResponse { |  | ||||||
|     @Nullable private Map<String, Entity> entities; |  | ||||||
|     private int success; |  | ||||||
| 
 |  | ||||||
|     @NotNull |  | ||||||
|     public Map<String, Entity> entities() { |  | ||||||
|         return entities != null ? entities : Collections.emptyMap(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public int getSuccess() { |  | ||||||
|         return success; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Nullable public Entity getFirst() { |  | ||||||
|         if (entities == null) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|         return entities.values().iterator().next(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public void postProcess() { |  | ||||||
|         if (getFirst() != null && getFirst().isMissing()) { |  | ||||||
|             throw new RuntimeException("The requested entity was not found."); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Entity { |  | ||||||
|         @Nullable private String type; |  | ||||||
|         @Nullable private String id; |  | ||||||
|         @Nullable private Map<String, Label> labels; |  | ||||||
|         @Nullable private Map<String, Label> descriptions; |  | ||||||
|         @Nullable private Map<String, SiteLink> sitelinks; |  | ||||||
|         @Nullable @SerializedName(value = "statements", alternate = "claims") private Map<String, List<StatementPartial>> statements; |  | ||||||
|         @Nullable private String missing; |  | ||||||
| 
 |  | ||||||
|         @NonNull public String id() { |  | ||||||
|             return StringUtils.defaultString(id); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public Map<String, Label> labels() { |  | ||||||
|             return labels != null ? labels : Collections.emptyMap(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public Map<String, Label> descriptions() { |  | ||||||
|             return descriptions != null ? descriptions : Collections.emptyMap(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public Map<String, SiteLink> sitelinks() { |  | ||||||
|             return sitelinks != null ? sitelinks : Collections.emptyMap(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Nullable |  | ||||||
|         public Map<String, List<StatementPartial>> getStatements() { |  | ||||||
|             return statements; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         boolean isMissing() { |  | ||||||
|             return "-1".equals(id) && missing != null; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class Label { |  | ||||||
|         @Nullable private String language; |  | ||||||
|         @Nullable private String value; |  | ||||||
| 
 |  | ||||||
|         public Label(@Nullable final String language, @Nullable final String value) { |  | ||||||
|             this.language = language; |  | ||||||
|             this.value = value; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public String language() { |  | ||||||
|             return StringUtils.defaultString(language); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public String value() { |  | ||||||
|             return StringUtils.defaultString(value); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static class SiteLink { |  | ||||||
|         @Nullable private String site; |  | ||||||
|         @Nullable private String title; |  | ||||||
| 
 |  | ||||||
|         @NonNull public String getSite() { |  | ||||||
|             return StringUtils.defaultString(site); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @NonNull public String getTitle() { |  | ||||||
|             return StringUtils.defaultString(title); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,64 @@ | ||||||
|  | package fr.free.nrw.commons.wikidata.model | ||||||
|  | 
 | ||||||
|  | import com.google.gson.annotations.SerializedName | ||||||
|  | import fr.free.nrw.commons.wikidata.mwapi.MwResponse | ||||||
|  | import org.apache.commons.lang3.StringUtils | ||||||
|  | 
 | ||||||
|  | class Entities : MwResponse() { | ||||||
|  |     private val entities: Map<String, Entity>? = null | ||||||
|  |     val success: Int = 0 | ||||||
|  | 
 | ||||||
|  |     fun entities(): Map<String, Entity> = entities ?: emptyMap() | ||||||
|  | 
 | ||||||
|  |     private val first : Entity? | ||||||
|  |         get() = entities?.values?.iterator()?.next() | ||||||
|  | 
 | ||||||
|  |     override fun postProcess() { | ||||||
|  |         first?.let { | ||||||
|  |             if (it.isMissing()) throw RuntimeException("The requested entity was not found.") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class Entity { | ||||||
|  |         private val type: String? = null | ||||||
|  |         private val id: String? = null | ||||||
|  |         private val labels: Map<String, Label>? = null | ||||||
|  |         private val descriptions: Map<String, Label>? = null | ||||||
|  |         private val sitelinks: Map<String, SiteLink>? = null | ||||||
|  | 
 | ||||||
|  |         @SerializedName(value = "statements", alternate = ["claims"]) | ||||||
|  |         val statements: Map<String, List<StatementPartial>>? = null | ||||||
|  |         private val missing: String? = null | ||||||
|  | 
 | ||||||
|  |         fun id(): String = | ||||||
|  |             StringUtils.defaultString(id) | ||||||
|  | 
 | ||||||
|  |         fun labels(): Map<String, Label> = | ||||||
|  |             labels ?: emptyMap() | ||||||
|  | 
 | ||||||
|  |         fun descriptions(): Map<String, Label> = | ||||||
|  |             descriptions ?: emptyMap() | ||||||
|  | 
 | ||||||
|  |         fun sitelinks(): Map<String, SiteLink> = | ||||||
|  |             sitelinks ?: emptyMap() | ||||||
|  | 
 | ||||||
|  |         fun isMissing(): Boolean = | ||||||
|  |             "-1" == id && missing != null | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class Label(private val language: String?, private val value: String?) { | ||||||
|  |         fun language(): String = | ||||||
|  |             StringUtils.defaultString(language) | ||||||
|  | 
 | ||||||
|  |         fun value(): String = | ||||||
|  |             StringUtils.defaultString(value) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class SiteLink { | ||||||
|  |         val site: String? = null | ||||||
|  |             get() = StringUtils.defaultString(field) | ||||||
|  | 
 | ||||||
|  |         private val title: String? = null | ||||||
|  |             get() = StringUtils.defaultString(field) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,292 +0,0 @@ | ||||||
| package fr.free.nrw.commons.wikidata.model; |  | ||||||
| 
 |  | ||||||
| import android.net.Uri; |  | ||||||
| import android.os.Parcel; |  | ||||||
| import android.os.Parcelable; |  | ||||||
| import android.text.TextUtils; |  | ||||||
| 
 |  | ||||||
| import androidx.annotation.NonNull; |  | ||||||
| 
 |  | ||||||
| import com.google.gson.annotations.SerializedName; |  | ||||||
| 
 |  | ||||||
| import org.apache.commons.lang3.StringUtils; |  | ||||||
| import fr.free.nrw.commons.language.AppLanguageLookUpTable; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * The base URL and Wikipedia language code for a MediaWiki site. Examples: |  | ||||||
|  * |  | ||||||
|  * <ul> |  | ||||||
|  *     <lh>Name: scheme / authority / language code</lh> |  | ||||||
|  *     <li>English Wikipedia: HTTPS / en.wikipedia.org / en</li> |  | ||||||
|  *     <li>Chinese Wikipedia: HTTPS / zh.wikipedia.org / zh-hans or zh-hant</li> |  | ||||||
|  *     <li>Meta-Wiki: HTTPS / meta.wikimedia.org / (none)</li> |  | ||||||
|  *     <li>Test Wikipedia: HTTPS / test.wikipedia.org / test</li> |  | ||||||
|  *     <li>Võro Wikipedia: HTTPS / fiu-vro.wikipedia.org / fiu-vro</li> |  | ||||||
|  *     <li>Simple English Wikipedia: HTTPS / simple.wikipedia.org / simple</li> |  | ||||||
|  *     <li>Simple English Wikipedia (beta cluster mirror): HTTP / simple.wikipedia.beta.wmflabs.org / simple</li> |  | ||||||
|  *     <li>Development: HTTP / 192.168.1.11:8080 / (none)</li> |  | ||||||
|  * </ul> |  | ||||||
|  * |  | ||||||
|  * <strong>As shown above, the language code or mapping is part of the authority:</strong> |  | ||||||
|  * <ul> |  | ||||||
|  *     <lh>Validity: authority / language code</lh> |  | ||||||
|  *     <li>Correct: "test.wikipedia.org" / "test"</li> |  | ||||||
|  *     <li>Correct: "wikipedia.org", ""</li> |  | ||||||
|  *     <li>Correct: "no.wikipedia.org", "nb"</li> |  | ||||||
|  *     <li>Incorrect: "wikipedia.org", "test"</li> |  | ||||||
|  * </ul> |  | ||||||
|  */ |  | ||||||
| public class WikiSite implements Parcelable { |  | ||||||
|     private static String WIKIPEDIA_URL = "https://wikipedia.org/"; |  | ||||||
| 
 |  | ||||||
|     public static final String DEFAULT_SCHEME = "https"; |  | ||||||
|     private static String DEFAULT_BASE_URL = WIKIPEDIA_URL; |  | ||||||
| 
 |  | ||||||
|     public static final Parcelable.Creator<WikiSite> CREATOR = new Parcelable.Creator<WikiSite>() { |  | ||||||
|         @Override |  | ||||||
|         public WikiSite createFromParcel(Parcel in) { |  | ||||||
|             return new WikiSite(in); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Override |  | ||||||
|         public WikiSite[] newArray(int size) { |  | ||||||
|             return new WikiSite[size]; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     // todo: remove @SerializedName. this is now in the TypeAdapter and a "uri" case may be added |  | ||||||
|     @SerializedName("domain") @NonNull private final Uri uri; |  | ||||||
|     @NonNull private String languageCode; |  | ||||||
| 
 |  | ||||||
|     public static WikiSite forLanguageCode(@NonNull String languageCode) { |  | ||||||
|         Uri uri = ensureScheme(Uri.parse(DEFAULT_BASE_URL)); |  | ||||||
|         return new WikiSite((languageCode.isEmpty() |  | ||||||
|                 ? "" : (languageCodeToSubdomain(languageCode) + ".")) + uri.getAuthority(), |  | ||||||
|                 languageCode); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public WikiSite(@NonNull Uri uri) { |  | ||||||
|         Uri tempUri = ensureScheme(uri); |  | ||||||
|         String authority = tempUri.getAuthority(); |  | ||||||
|         if (("wikipedia.org".equals(authority) || "www.wikipedia.org".equals(authority)) |  | ||||||
|                 && tempUri.getPath() != null && tempUri.getPath().startsWith("/wiki")) { |  | ||||||
|             // Special case for Wikipedia only: assume English subdomain when none given. |  | ||||||
|             authority = "en.wikipedia.org"; |  | ||||||
|         } |  | ||||||
|         String langVariant = getLanguageVariantFromUri(tempUri); |  | ||||||
|         if (!TextUtils.isEmpty(langVariant)) { |  | ||||||
|             languageCode = langVariant; |  | ||||||
|         } else { |  | ||||||
|             languageCode = authorityToLanguageCode(authority); |  | ||||||
|         } |  | ||||||
|         this.uri = new Uri.Builder() |  | ||||||
|                 .scheme(tempUri.getScheme()) |  | ||||||
|                 .encodedAuthority(authority) |  | ||||||
|                 .build(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** Get language variant code from a Uri, e.g. "zh-*", otherwise returns empty string. */ |  | ||||||
|     @NonNull |  | ||||||
|     private String getLanguageVariantFromUri(@NonNull Uri uri) { |  | ||||||
|         if (TextUtils.isEmpty(uri.getPath())) { |  | ||||||
|             return ""; |  | ||||||
|         } |  | ||||||
|         String[] parts = StringUtils.split(StringUtils.defaultString(uri.getPath()), '/'); |  | ||||||
|         return parts.length > 1 && !parts[0].equals("wiki") ? parts[0] : ""; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public WikiSite(@NonNull String url) { |  | ||||||
|         this(url.startsWith("http") ? Uri.parse(url) : url.startsWith("//") |  | ||||||
|                 ? Uri.parse(DEFAULT_SCHEME + ":" + url) : Uri.parse(DEFAULT_SCHEME + "://" + url)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public WikiSite(@NonNull String authority, @NonNull String languageCode) { |  | ||||||
|         this(authority); |  | ||||||
|         this.languageCode = languageCode; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @NonNull |  | ||||||
|     public String scheme() { |  | ||||||
|         return TextUtils.isEmpty(uri.getScheme()) ? DEFAULT_SCHEME : uri.getScheme(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return The complete wiki authority including language subdomain but not including scheme, |  | ||||||
|      *         authentication, port, nor trailing slash. |  | ||||||
|      * |  | ||||||
|      * @see <a href='https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax'>URL syntax</a> |  | ||||||
|      */ |  | ||||||
|     @NonNull |  | ||||||
|     public String authority() { |  | ||||||
|         return uri.getAuthority(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Like {@link #authority()} but with a "m." between the language subdomain and the rest of the host. |  | ||||||
|      * Examples: |  | ||||||
|      * |  | ||||||
|      * <ul> |  | ||||||
|      *     <li>English Wikipedia: en.m.wikipedia.org</li> |  | ||||||
|      *     <li>Chinese Wikipedia: zh.m.wikipedia.org</li> |  | ||||||
|      *     <li>Meta-Wiki: meta.m.wikimedia.org</li> |  | ||||||
|      *     <li>Test Wikipedia: test.m.wikipedia.org</li> |  | ||||||
|      *     <li>Võro Wikipedia: fiu-vro.m.wikipedia.org</li> |  | ||||||
|      *     <li>Simple English Wikipedia: simple.m.wikipedia.org</li> |  | ||||||
|      *     <li>Simple English Wikipedia (beta cluster mirror): simple.m.wikipedia.beta.wmflabs.org</li> |  | ||||||
|      *     <li>Development: m.192.168.1.11</li> |  | ||||||
|      * </ul> |  | ||||||
|      */ |  | ||||||
|     @NonNull |  | ||||||
|     public String mobileAuthority() { |  | ||||||
|         return authorityToMobile(authority()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Get wiki's mobile URL |  | ||||||
|      * Eg. https://en.m.wikipedia.org |  | ||||||
|      * @return |  | ||||||
|      */ |  | ||||||
|     public String mobileUrl() { |  | ||||||
|         return String.format("%1$s://%2$s", scheme(), mobileAuthority()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @NonNull |  | ||||||
|     public String subdomain() { |  | ||||||
|         return languageCodeToSubdomain(languageCode); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return A path without an authority for the segment including a leading "/". |  | ||||||
|      */ |  | ||||||
|     @NonNull |  | ||||||
|     public String path(@NonNull String segment) { |  | ||||||
|         return "/w/" + segment; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     @NonNull public Uri uri() { |  | ||||||
|         return uri; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return The canonical URL. e.g., https://en.wikipedia.org. |  | ||||||
|      */ |  | ||||||
|     @NonNull public String url() { |  | ||||||
|         return uri.toString(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return The canonical URL for segment. e.g., https://en.wikipedia.org/w/foo. |  | ||||||
|      */ |  | ||||||
|     @NonNull public String url(@NonNull String segment) { |  | ||||||
|         return url() + path(segment); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * @return The wiki language code which may differ from the language subdomain. Empty if |  | ||||||
|      *         language code is unknown. Ex: "en", "zh-hans", "" |  | ||||||
|      * |  | ||||||
|      * @see AppLanguageLookUpTable |  | ||||||
|      */ |  | ||||||
|     @NonNull |  | ||||||
|     public String languageCode() { |  | ||||||
|         return languageCode; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Auto-generated |  | ||||||
|     @Override |  | ||||||
|     public boolean equals(Object o) { |  | ||||||
|         if (this == o) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         if (o == null || getClass() != o.getClass()) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         WikiSite wiki = (WikiSite) o; |  | ||||||
| 
 |  | ||||||
|         if (!uri.equals(wiki.uri)) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         return languageCode.equals(wiki.languageCode); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Auto-generated |  | ||||||
|     @Override |  | ||||||
|     public int hashCode() { |  | ||||||
|         int result = uri.hashCode(); |  | ||||||
|         result = 31 * result + languageCode.hashCode(); |  | ||||||
|         return result; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Auto-generated |  | ||||||
|     @Override |  | ||||||
|     public String toString() { |  | ||||||
|         return "WikiSite{" |  | ||||||
|                 + "uri=" + uri |  | ||||||
|                 + ", languageCode='" + languageCode + '\'' |  | ||||||
|                 + '}'; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public int describeContents() { |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public void writeToParcel(@NonNull Parcel dest, int flags) { |  | ||||||
|         dest.writeParcelable(uri, 0); |  | ||||||
|         dest.writeString(languageCode); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     protected WikiSite(@NonNull Parcel in) { |  | ||||||
|         this.uri = in.readParcelable(Uri.class.getClassLoader()); |  | ||||||
|         this.languageCode = in.readString(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @NonNull |  | ||||||
|     private static String languageCodeToSubdomain(@NonNull String languageCode) { |  | ||||||
|         switch (languageCode) { |  | ||||||
|             case AppLanguageLookUpTable.SIMPLIFIED_CHINESE_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.TRADITIONAL_CHINESE_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.CHINESE_CN_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.CHINESE_HK_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.CHINESE_MO_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.CHINESE_SG_LANGUAGE_CODE: |  | ||||||
|             case AppLanguageLookUpTable.CHINESE_TW_LANGUAGE_CODE: |  | ||||||
|                 return AppLanguageLookUpTable.CHINESE_LANGUAGE_CODE; |  | ||||||
|             case AppLanguageLookUpTable.NORWEGIAN_BOKMAL_LANGUAGE_CODE: |  | ||||||
|                 return AppLanguageLookUpTable.NORWEGIAN_LEGACY_LANGUAGE_CODE; // T114042 |  | ||||||
|             default: |  | ||||||
|                 return languageCode; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @NonNull private static String authorityToLanguageCode(@NonNull String authority) { |  | ||||||
|         String[] parts = authority.split("\\."); |  | ||||||
|         final int minLengthForSubdomain = 3; |  | ||||||
|         if (parts.length < minLengthForSubdomain |  | ||||||
|                 || parts.length == minLengthForSubdomain && parts[0].equals("m")) { |  | ||||||
|             // "" |  | ||||||
|             // wikipedia.org |  | ||||||
|             // m.wikipedia.org |  | ||||||
|             return ""; |  | ||||||
|         } |  | ||||||
|         return parts[0]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @NonNull private static Uri ensureScheme(@NonNull Uri uri) { |  | ||||||
|         if (TextUtils.isEmpty(uri.getScheme())) { |  | ||||||
|             return uri.buildUpon().scheme(DEFAULT_SCHEME).build(); |  | ||||||
|         } |  | ||||||
|         return uri; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** @param authority Host and optional port. */ |  | ||||||
|     @NonNull private String authorityToMobile(@NonNull String authority) { |  | ||||||
|         if (authority.startsWith("m.") || authority.contains(".m.")) { |  | ||||||
|             return authority; |  | ||||||
|         } |  | ||||||
|         return authority.replaceFirst("^" + subdomain() + "\\.?", "$0m."); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										269
									
								
								app/src/main/java/fr/free/nrw/commons/wikidata/model/WikiSite.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								app/src/main/java/fr/free/nrw/commons/wikidata/model/WikiSite.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,269 @@ | ||||||
|  | package fr.free.nrw.commons.wikidata.model | ||||||
|  | 
 | ||||||
|  | import android.net.Uri | ||||||
|  | import android.os.Parcel | ||||||
|  | import android.os.Parcelable | ||||||
|  | import android.text.TextUtils | ||||||
|  | import com.google.gson.annotations.SerializedName | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_CN_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_HK_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_MO_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_SG_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.CHINESE_TW_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.NORWEGIAN_BOKMAL_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.NORWEGIAN_LEGACY_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.SIMPLIFIED_CHINESE_LANGUAGE_CODE | ||||||
|  | import fr.free.nrw.commons.language.AppLanguageLookUpTable.Companion.TRADITIONAL_CHINESE_LANGUAGE_CODE | ||||||
|  | import org.apache.commons.lang3.StringUtils | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * The base URL and Wikipedia language code for a MediaWiki site. Examples: | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * <lh>Name: scheme / authority / language code</lh> | ||||||
|  |  *  * English Wikipedia: HTTPS / en.wikipedia.org / en | ||||||
|  |  *  * Chinese Wikipedia: HTTPS / zh.wikipedia.org / zh-hans or zh-hant | ||||||
|  |  *  * Meta-Wiki: HTTPS / meta.wikimedia.org / (none) | ||||||
|  |  *  * Test Wikipedia: HTTPS / test.wikipedia.org / test | ||||||
|  |  *  * Võro Wikipedia: HTTPS / fiu-vro.wikipedia.org / fiu-vro | ||||||
|  |  *  * Simple English Wikipedia: HTTPS / simple.wikipedia.org / simple | ||||||
|  |  *  * Simple English Wikipedia (beta cluster mirror): HTTP / simple.wikipedia.beta.wmflabs.org / simple | ||||||
|  |  *  * Development: HTTP / 192.168.1.11:8080 / (none) | ||||||
|  |  * | ||||||
|  |  * | ||||||
|  |  * **As shown above, the language code or mapping is part of the authority:** | ||||||
|  |  * | ||||||
|  |  * <lh>Validity: authority / language code</lh> | ||||||
|  |  *  * Correct: "test.wikipedia.org" / "test" | ||||||
|  |  *  * Correct: "wikipedia.org", "" | ||||||
|  |  *  * Correct: "no.wikipedia.org", "nb" | ||||||
|  |  *  * Incorrect: "wikipedia.org", "test" | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | class WikiSite : Parcelable { | ||||||
|  |     //TODO: remove @SerializedName. this is now in the TypeAdapter and a "uri" case may be added | ||||||
|  |     @SerializedName("domain") | ||||||
|  |     private val uri: Uri | ||||||
|  | 
 | ||||||
|  |     private var languageCode: String? = null | ||||||
|  | 
 | ||||||
|  |     constructor(uri: Uri) { | ||||||
|  |         val tempUri = ensureScheme(uri) | ||||||
|  |         var authority = tempUri.authority | ||||||
|  | 
 | ||||||
|  |         if (authority.isWikipedia && tempUri.path?.startsWith("/wiki") == true) { | ||||||
|  |             // Special case for Wikipedia only: assume English subdomain when none given. | ||||||
|  |             authority = "en.wikipedia.org" | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val langVariant = getLanguageVariantFromUri(tempUri) | ||||||
|  |         languageCode = if (!TextUtils.isEmpty(langVariant)) { | ||||||
|  |             langVariant | ||||||
|  |         } else { | ||||||
|  |             authorityToLanguageCode(authority!!) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.uri = Uri.Builder() | ||||||
|  |             .scheme(tempUri.scheme) | ||||||
|  |             .encodedAuthority(authority) | ||||||
|  |             .build() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private val String?.isWikipedia: Boolean get() = | ||||||
|  |         (this == "wikipedia.org" || this == "www.wikipedia.org") | ||||||
|  | 
 | ||||||
|  |     /** Get language variant code from a Uri, e.g. "zh-*", otherwise returns empty string.  */ | ||||||
|  |     private fun getLanguageVariantFromUri(uri: Uri): String { | ||||||
|  |         if (TextUtils.isEmpty(uri.path)) { | ||||||
|  |             return "" | ||||||
|  |         } | ||||||
|  |         val parts = StringUtils.split(StringUtils.defaultString(uri.path), '/') | ||||||
|  |         return if (parts.size > 1 && parts[0] != "wiki") parts[0] else "" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     constructor(url: String) : this( | ||||||
|  |         if (url.startsWith("http")) Uri.parse(url) else if (url.startsWith("//")) | ||||||
|  |             Uri.parse("$DEFAULT_SCHEME:$url") | ||||||
|  |         else | ||||||
|  |             Uri.parse("$DEFAULT_SCHEME://$url") | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     constructor(authority: String, languageCode: String) : this(authority) { | ||||||
|  |         this.languageCode = languageCode | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun scheme(): String = | ||||||
|  |         if (TextUtils.isEmpty(uri.scheme)) DEFAULT_SCHEME else uri.scheme!! | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return The complete wiki authority including language subdomain but not including scheme, | ||||||
|  |      * authentication, port, nor trailing slash. | ||||||
|  |      * | ||||||
|  |      * @see [URL syntax](https://en.wikipedia.org/wiki/Uniform_Resource_Locator.Syntax) | ||||||
|  |      */ | ||||||
|  |     fun authority(): String = uri.authority!! | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Like [.authority] but with a "m." between the language subdomain and the rest of the host. | ||||||
|  |      * Examples: | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      *  * English Wikipedia: en.m.wikipedia.org | ||||||
|  |      *  * Chinese Wikipedia: zh.m.wikipedia.org | ||||||
|  |      *  * Meta-Wiki: meta.m.wikimedia.org | ||||||
|  |      *  * Test Wikipedia: test.m.wikipedia.org | ||||||
|  |      *  * Võro Wikipedia: fiu-vro.m.wikipedia.org | ||||||
|  |      *  * Simple English Wikipedia: simple.m.wikipedia.org | ||||||
|  |      *  * Simple English Wikipedia (beta cluster mirror): simple.m.wikipedia.beta.wmflabs.org | ||||||
|  |      *  * Development: m.192.168.1.11 | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     fun mobileAuthority(): String = authorityToMobile(authority()) | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get wiki's mobile URL | ||||||
|  |      * Eg. https://en.m.wikipedia.org | ||||||
|  |      * @return | ||||||
|  |      */ | ||||||
|  |     fun mobileUrl(): String = String.format("%1\$s://%2\$s", scheme(), mobileAuthority()) | ||||||
|  | 
 | ||||||
|  |     fun subdomain(): String = languageCodeToSubdomain(languageCode!!) | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return A path without an authority for the segment including a leading "/". | ||||||
|  |      */ | ||||||
|  |     fun path(segment: String): String = "/w/$segment" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     fun uri(): Uri = uri | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return The canonical URL. e.g., https://en.wikipedia.org. | ||||||
|  |      */ | ||||||
|  |     fun url(): String = uri.toString() | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return The canonical URL for segment. e.g., https://en.wikipedia.org/w/foo. | ||||||
|  |      */ | ||||||
|  |     fun url(segment: String): String = url() + path(segment) | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return The wiki language code which may differ from the language subdomain. Empty if | ||||||
|  |      * language code is unknown. Ex: "en", "zh-hans", "" | ||||||
|  |      * | ||||||
|  |      * @see AppLanguageLookUpTable | ||||||
|  |      */ | ||||||
|  |     fun languageCode(): String = languageCode!! | ||||||
|  | 
 | ||||||
|  |     // Auto-generated | ||||||
|  |     override fun equals(o: Any?): Boolean { | ||||||
|  |         if (this === o) { | ||||||
|  |             return true | ||||||
|  |         } | ||||||
|  |         if (o == null || javaClass != o.javaClass) { | ||||||
|  |             return false | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         val wiki = o as WikiSite | ||||||
|  | 
 | ||||||
|  |         if (uri != wiki.uri) { | ||||||
|  |             return false | ||||||
|  |         } | ||||||
|  |         return languageCode == wiki.languageCode | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Auto-generated | ||||||
|  |     override fun hashCode(): Int { | ||||||
|  |         var result = uri.hashCode() | ||||||
|  |         result = 31 * result + languageCode.hashCode() | ||||||
|  |         return result | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Auto-generated | ||||||
|  |     override fun toString(): String { | ||||||
|  |         return ("WikiSite{" | ||||||
|  |                 + "uri=" + uri | ||||||
|  |                 + ", languageCode='" + languageCode + '\'' | ||||||
|  |                 + '}') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun describeContents(): Int = 0 | ||||||
|  | 
 | ||||||
|  |     override fun writeToParcel(dest: Parcel, flags: Int) { | ||||||
|  |         dest.writeParcelable(uri, 0) | ||||||
|  |         dest.writeString(languageCode) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected constructor(`in`: Parcel) { | ||||||
|  |         uri = `in`.readParcelable(Uri::class.java.classLoader)!! | ||||||
|  |         languageCode = `in`.readString() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** @param authority Host and optional port. | ||||||
|  |      */ | ||||||
|  |     private fun authorityToMobile(authority: String): String { | ||||||
|  |         if (authority.startsWith("m.") || authority.contains(".m.")) { | ||||||
|  |             return authority | ||||||
|  |         } | ||||||
|  |         return authority.replaceFirst(("^" + subdomain() + "\\.?").toRegex(), "$0m.") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         const val WIKIPEDIA_URL = "https://wikipedia.org/" | ||||||
|  |         const val DEFAULT_SCHEME: String = "https" | ||||||
|  | 
 | ||||||
|  |         @JvmField | ||||||
|  |         val CREATOR: Parcelable.Creator<WikiSite> = object : Parcelable.Creator<WikiSite> { | ||||||
|  |             override fun createFromParcel(parcel: Parcel): WikiSite { | ||||||
|  |                 return WikiSite(parcel) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             override fun newArray(size: Int): Array<WikiSite?> { | ||||||
|  |                 return arrayOfNulls(size) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         fun forDefaultLocaleLanguageCode(): WikiSite { | ||||||
|  |             val languageCode: String = Locale.getDefault().language | ||||||
|  |             val subdomain = if (languageCode.isEmpty()) "" else languageCodeToSubdomain(languageCode) + "." | ||||||
|  |             val uri = ensureScheme(Uri.parse(WIKIPEDIA_URL)) | ||||||
|  |             return WikiSite(subdomain + uri.authority, languageCode) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private fun languageCodeToSubdomain(languageCode: String): String = when (languageCode) { | ||||||
|  |             SIMPLIFIED_CHINESE_LANGUAGE_CODE, | ||||||
|  |             TRADITIONAL_CHINESE_LANGUAGE_CODE, | ||||||
|  |             CHINESE_CN_LANGUAGE_CODE, | ||||||
|  |             CHINESE_HK_LANGUAGE_CODE, | ||||||
|  |             CHINESE_MO_LANGUAGE_CODE, | ||||||
|  |             CHINESE_SG_LANGUAGE_CODE, | ||||||
|  |             CHINESE_TW_LANGUAGE_CODE -> CHINESE_LANGUAGE_CODE | ||||||
|  | 
 | ||||||
|  |             NORWEGIAN_BOKMAL_LANGUAGE_CODE -> NORWEGIAN_LEGACY_LANGUAGE_CODE // T114042 | ||||||
|  | 
 | ||||||
|  |             else -> languageCode | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private fun authorityToLanguageCode(authority: String): String { | ||||||
|  |             val parts = authority.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | ||||||
|  |             val minLengthForSubdomain = 3 | ||||||
|  |             if (parts.size < minLengthForSubdomain || parts.size == minLengthForSubdomain && parts[0] == "m") { | ||||||
|  |                 // "" | ||||||
|  |                 // wikipedia.org | ||||||
|  |                 // m.wikipedia.org | ||||||
|  |                 return "" | ||||||
|  |             } | ||||||
|  |             return parts[0] | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private fun ensureScheme(uri: Uri): Uri { | ||||||
|  |             if (TextUtils.isEmpty(uri.scheme)) { | ||||||
|  |                 return uri.buildUpon().scheme(DEFAULT_SCHEME).build() | ||||||
|  |             } | ||||||
|  |             return uri | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Nicolas Raoul
						Nicolas Raoul