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() { | ||||
|         Espresso.onView(ViewMatchers.withId(R.id.about_translate)).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( | ||||
|             CoreMatchers.allOf( | ||||
|                 IntentMatchers.hasAction(Intent.ACTION_VIEW), | ||||
|  |  | |||
|  | @ -44,7 +44,6 @@ import okhttp3.logging.HttpLoggingInterceptor | |||
| import okhttp3.logging.HttpLoggingInterceptor.Level | ||||
| import timber.log.Timber | ||||
| import java.io.File | ||||
| import java.util.Locale | ||||
| import java.util.concurrent.TimeUnit | ||||
| import javax.inject.Named | ||||
| import javax.inject.Singleton | ||||
|  | @ -293,9 +292,8 @@ class NetworkingModule { | |||
|     @Provides | ||||
|     @Singleton | ||||
|     @Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE) | ||||
|     fun provideLanguageWikipediaSite(): WikiSite { | ||||
|         return WikiSite.forLanguageCode(Locale.getDefault().language) | ||||
|     } | ||||
|     fun provideLanguageWikipediaSite(): WikiSite = | ||||
|         WikiSite.forDefaultLocaleLanguageCode() | ||||
| 
 | ||||
|     companion object { | ||||
|         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