diff --git a/app/build.gradle b/app/build.gradle index fe14d8c8a..b5e2c2303 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,6 +84,29 @@ android { } } + productFlavors { + prod { + buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.org/w/api.php\"" + buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" + buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\"" + buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\"" + buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.org/wiki/\"" + buildConfigField "String", "EVENTLOG_URL", "\"https://www.wikimedia.org/beacon/event\"" + buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" + } + + beta { + // What values do we need to hit the BETA versions of the site / api ? + buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.beta.wmflabs.org/w/api.php\"" + buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" + buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\"" + buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\"" + buildConfigField "String", "MOBILE_HOME_URL", "\"https://commons.m.wikimedia.beta.wmflabs.org/wiki/\"" + buildConfigField "String", "EVENTLOG_URL", "\"https://commons.wikimedia.beta.wmflabs.org/beacon/event\"" + buildConfigField "String", "EVENTLOG_WIKI", "\"commonswiki\"" + } + } + lintOptions { disable 'MissingTranslation' disable 'ExtraTranslation' diff --git a/app/src/androidTest/java/fr/free/nrw/commons/MediaTest.java b/app/src/androidTest/java/fr/free/nrw/commons/MediaTest.java deleted file mode 100644 index ecb465293..000000000 --- a/app/src/androidTest/java/fr/free/nrw/commons/MediaTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.free.nrw.commons; - -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.CoreMatchers.is; - -// TODO: use Robolectric and make it runnable without a connected device -@RunWith(AndroidJUnit4.class) -public class MediaTest { - @Test public void displayTitleShouldStripExtension() { - Media m = new Media("File:Example.jpg"); - Assert.assertThat(m.getDisplayTitle(), is("Example")); - } - - @Test public void displayTitleShouldUseSpaceForUnderscore() { - Media m = new Media("File:Example 1_2.jpg"); - Assert.assertThat(m.getDisplayTitle(), is("Example 1 2")); - } -} diff --git a/app/src/androidTest/java/fr/free/nrw/commons/NearbyControllerTest.java b/app/src/androidTest/java/fr/free/nrw/commons/NearbyControllerTest.java deleted file mode 100644 index aa32d2637..000000000 --- a/app/src/androidTest/java/fr/free/nrw/commons/NearbyControllerTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.free.nrw.commons; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; - -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.nearby.NearbyBaseMarker; -import fr.free.nrw.commons.nearby.NearbyController; -import fr.free.nrw.commons.nearby.Place; - -import static org.hamcrest.CoreMatchers.is; - -@RunWith(AndroidJUnit4.class) -public class NearbyControllerTest { - private Context instrumentationContext; - - @Before - public void setup() { - instrumentationContext = InstrumentationRegistry.getTargetContext(); - } - - @Test public void testNullAttractions() { - LatLng location = new LatLng(0, 0, 0); - - List options = - NearbyController.loadAttractionsFromLocationToBaseMarkerOptions( - location, - null, - instrumentationContext - ); - - Assert.assertThat(options.size(), is(0)); - } - - @Test public void testEmptyList() { - LatLng location = new LatLng(0, 0, 0); - List emptyList = new ArrayList<>(); - - List options = - NearbyController.loadAttractionsFromLocationToBaseMarkerOptions( - location, - emptyList, - instrumentationContext - ); - - Assert.assertThat(options.size(), is(0)); - } -} diff --git a/app/src/androidTest/java/fr/free/nrw/commons/PageTitleTest.java b/app/src/androidTest/java/fr/free/nrw/commons/PageTitleTest.java deleted file mode 100644 index 5c83ef691..000000000 --- a/app/src/androidTest/java/fr/free/nrw/commons/PageTitleTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package fr.free.nrw.commons; - -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.URLEncoder; - -import static org.hamcrest.CoreMatchers.is; - -// TODO: use Robolectric and make it runnable without a connected device -@RunWith(AndroidJUnit4.class) -public class PageTitleTest { - @Test public void displayTextShouldNotBeUnderscored() { - Assert.assertThat(new PageTitle("Ex_1 ").getDisplayText(), - is("Ex 1")); - } - - @Test public void moreThanTwoColons() { - Assert.assertThat(new PageTitle("File:sample:a.jpg").getPrefixedText(), - is("File:Sample:a.jpg")); - } - - @Test public void getTextShouldReturnWithoutNamespace() { - Assert.assertThat(new PageTitle("File:sample.jpg").getText(), - is("Sample.jpg")); - } - - - @Test public void capitalizeNameAfterNamespace() { - Assert.assertThat(new PageTitle("File:sample.jpg").getPrefixedText(), - is("File:Sample.jpg")); - } - - @Test public void prefixedTextShouldBeUnderscored() { - Assert.assertThat(new PageTitle("Ex 1 ").getPrefixedText(), - is("Ex_1")); - } - - @Test public void getMobileUriForTest() { - Assert.assertThat(new PageTitle("Test").getMobileUri().toString(), - is("https://commons.m.wikimedia.org/wiki/Test")); - } - - @Test public void spaceBecomesUnderscoreInUri() { - Assert.assertThat(new PageTitle("File:Ex 1.jpg").getCanonicalUri().toString(), - is("https://commons.wikimedia.org/wiki/File:Ex_1.jpg")); - } - - @Test public void leaveSubpageNamesUncapitalizedInUri() { - Assert.assertThat(new PageTitle("User:Ex/subpage").getCanonicalUri().toString(), - is("https://commons.wikimedia.org/wiki/User:Ex/subpage")); - } - - @Test public void unicodeUri() throws Throwable { - Assert.assertThat(new PageTitle("User:例").getCanonicalUri().toString(), - is("https://commons.wikimedia.org/wiki/User:" + URLEncoder.encode("例", "utf-8"))); - } -} diff --git a/app/src/betaDebug/res/drawable-hdpi/ic_launcher.png b/app/src/betaDebug/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..46c0a4202 Binary files /dev/null and b/app/src/betaDebug/res/drawable-hdpi/ic_launcher.png differ diff --git a/app/src/betaDebug/res/drawable-mdpi/ic_launcher.png b/app/src/betaDebug/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..2e5499676 Binary files /dev/null and b/app/src/betaDebug/res/drawable-mdpi/ic_launcher.png differ diff --git a/app/src/betaDebug/res/drawable-xhdpi/ic_launcher.png b/app/src/betaDebug/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..0f0c702ed Binary files /dev/null and b/app/src/betaDebug/res/drawable-xhdpi/ic_launcher.png differ diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index 40ef35bc0..25d5c4b96 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -49,13 +49,6 @@ public class CommonsApplication extends DaggerApplication { @Inject SessionManager sessionManager; @Inject DBOpenHelper dbOpenHelper; - public static final String API_URL = "https://commons.wikimedia.org/w/api.php"; - public static final String IMAGE_URL_BASE = "https://upload.wikimedia.org/wikipedia/commons"; - public static final String HOME_URL = "https://commons.wikimedia.org/wiki/"; - public static final String MOBILE_HOME_URL = "https://commons.m.wikimedia.org/wiki/"; - public static final String EVENTLOG_URL = "https://www.wikimedia.org/beacon/event"; - public static final String EVENTLOG_WIKI = "commonswiki"; - public static final Object[] EVENT_UPLOAD_ATTEMPT = {"MobileAppUploadAttempts", 5334329L}; public static final Object[] EVENT_LOGIN_ATTEMPT = {"MobileAppLoginAttempts", 5257721L}; public static final Object[] EVENT_SHARE_ATTEMPT = {"MobileAppShareAttempts", 5346170L}; diff --git a/app/src/main/java/fr/free/nrw/commons/PageTitle.java b/app/src/main/java/fr/free/nrw/commons/PageTitle.java index eb8a61284..6229e7ef9 100644 --- a/app/src/main/java/fr/free/nrw/commons/PageTitle.java +++ b/app/src/main/java/fr/free/nrw/commons/PageTitle.java @@ -58,7 +58,7 @@ public class PageTitle { */ @NonNull public Uri getCanonicalUri() { - String uriStr = CommonsApplication.HOME_URL + Uri.encode(getPrefixedText(), ":/"); + String uriStr = BuildConfig.HOME_URL + Uri.encode(getPrefixedText(), ":/"); return Uri.parse(uriStr); } @@ -71,7 +71,7 @@ public class PageTitle { */ @NonNull public Uri getMobileUri() { - String uriStr = CommonsApplication.MOBILE_HOME_URL + Uri.encode(getPrefixedText(), ":/"); + String uriStr = BuildConfig.MOBILE_HOME_URL + Uri.encode(getPrefixedText(), ":/"); return Uri.parse(uriStr); } diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 4d16e8a6e..faf016e38 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -11,6 +11,7 @@ import java.util.regex.Pattern; import fr.free.nrw.commons.settings.Prefs; + public class Utils { /** @@ -32,7 +33,7 @@ public class Utils { public static String makeThumbBaseUrl(String filename) { String name = new PageTitle(filename).getPrefixedText(); String sha = new String(Hex.encodeHex(DigestUtils.md5(name))); - return String.format("%s/%s/%s/%s", CommonsApplication.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name)); + return String.format("%s/%s/%s/%s", BuildConfig.IMAGE_URL_BASE, sha.substring(0, 1), sha.substring(0, 2), urlEncode(name)); } public static String urlEncode(String url) { diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index b3370da80..3736332ed 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -6,6 +6,7 @@ import javax.inject.Singleton; import dagger.Module; import dagger.Provides; +import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.SessionManager; @@ -37,7 +38,7 @@ public class CommonsApplicationModule { @Provides @Singleton public MediaWikiApi provideMediaWikiApi() { - return new ApacheHttpClientMediaWikiApi(CommonsApplication.API_URL); + return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST); } @Provides diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java b/app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java index f15a576ed..29f44995e 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java @@ -47,12 +47,12 @@ public class LogBuilder { try { fullData.put("schema", schema); fullData.put("revision", rev); - fullData.put("wiki", CommonsApplication.EVENTLOG_WIKI); + fullData.put("wiki", BuildConfig.EVENTLOG_WIKI); data.put("device", EventLog.DEVICE); data.put("platform", "Android/" + Build.VERSION.RELEASE); data.put("appversion", "Android/" + BuildConfig.VERSION_NAME); fullData.put("event", data); - return new URL(CommonsApplication.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";"); + return new URL(BuildConfig.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";"); } catch (MalformedURLException | JSONException e) { throw new RuntimeException(e); } diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java index fb90557ab..3f4bfba33 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java @@ -7,7 +7,7 @@ import android.preference.PreferenceManager; import dagger.android.support.DaggerAppCompatActivity; import fr.free.nrw.commons.R; -public class BaseActivity extends DaggerAppCompatActivity { +public abstract class BaseActivity extends DaggerAppCompatActivity { boolean currentTheme; @Override diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 3c1ec8baf..0254a2721 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -20,11 +20,11 @@ اتمام بارگذاری %1$s %1$s بارگذاری نشد برای دیدن انگشت بزنید - - یک پرونده در حال بارگذاری + + %d پرونده در حال بارگذاری %d پرونده در حال بارگذاری - بارگذاری‌های من + بارگذاری‌های اخیر من در صف ناموفق بود %1$d٪ کامل شد @@ -42,6 +42,7 @@ ناتوانی در ورود - لطفاً گذرواژه‌یتان را بررسی کنید تلاش ناموفق بیش از حد. لطفاً چند دقیقهٔ دیگر دوباره تلاش کنید پوزش، کاربر در ویکی‌انبار بسته شده‌است + باید تأیید دومرحله‌ای را فعال کنید. ورود ناموفق بود بارگذاری نام این مجموعه @@ -49,17 +50,21 @@ بارگذاری جستجوی رده‌ها ذخیره - - هنوز بارگذاری نشده است - یک بارگذاری شد + تازه کردن + مکان‌یاب در دستگاه شما خاموش است. آیا دوست دارید فعال شود؟ + فعال کردن مکان‌یاب + هنوز هیچ بارگذاری + + \@string/contributions_subtitle_zero + بارگذاری شد %d بارگذاری شد - - شروع بارگذاری پرونده - شروع بارگذاری %d پرونده + + شروع %d بارگذاری پرونده + شروع بارگذاری %d پرونده - - ۱ بارگذاری + + %d بارگذاری %d بارگذاری رده‌ای منطبق با %1$s یافت نشد @@ -68,9 +73,10 @@ تنظیمات ثبت نام درباره - نرم‌افزار متن‌باز آزاد تحت <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">مجوز آپاچی نسخهٔ ۲</a>\n\nویکی‌انبار و نشانش یک نشان تجاری‌ست و با اجازهٔ بنیاد ویکی‌مدیا استفاده می‌شود. ما زیرمجموعه یا شعبهٔ بنیاد نیستیم. + نرم‌افزار متن‌باز آزاد تحت <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">مجوز آپاچی نسخهٔ ۲</a>\n\n%1$s و نشانش یک نشان تجاری‌ست و با اجازهٔ بنیاد ویکی‌مدیا استفاده می‌شود. ما زیرمجموعه یا شعبهٔ بنیاد نیستیم. <a href=\"https://github.com/commons-app/apps-android-commons\">Source</a> and <a href=\"https://commons-app.github.io/\">وب‌سایت</a> در گیت‌هاب. ایجاد یک <a href=\"https://github.com/commons-app/apps-android-commons/issues\">درخواست در گیت‌هاب</a> برای گزارش باگ و یا پیشنهاد یک خصوصیت جدید. <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">سیاست حفظ حریم خصوصی</a> + <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">مجوز</a> درباره ارسال بازخورد (از طریق ایمیل) نرم‌افزار ایمیل نصب نیست @@ -80,11 +86,16 @@ تلاش مجدد لغو این نگاره تحت مجوز %1$s است + با بارگذاری این تصویر، تأیید می‌کنم که این اثر کار خودم است و از محتوای دارای حق تکثیر یا سلفی برای ایجاد آن استفاده نکرده‌ام و شرایط ذکر شده در By submitting this picture, I declare that this is my own work, that it does not contain copyrighted material or selfies, and otherwise adheres to <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">سیاست‌های ویکی‌انبار</a> را رعایت می‌کند. دریافت مجوز از عنوان/توضیحات پیشین استفاده کنید دریافت خودکار موقعیت کنونی درحال دریافت موقعیت برای پیشنهاد رده در صورتی که برچسب جغرافیایی وجود نداشته باشد. + حالت شبانه + استفاده از حالت تیره + CC Attribution-ShareAlike 4.0 + Attribution 4.0 CC Attribution-ShareAlike 3.0 CC Attribution 3.0 CC0 @@ -127,8 +138,60 @@ اجازه‌های اختیاری: دریافت موقعیت برای پیشنهاد رده تأیید مکان‌‌های اطراف + مکانی در نزدیکی یافت نشد هشدار پرونده در ویکی‌انبار موجود است. آیا مطمئنید که می‌خواهید ادامه دهید؟ بله خیر + عنوان + عنوان رسانه + توضیح + توضیحات رسانه اینجا می‌روند. امکان دارد طولانی باشد و نیاز به چند خط شدن داشته باشد. امیدواریم خوب دیده شود. + تاریخ بارگذاری + مجوز + مختصات‌ها + ارائه نشده است + آزمایشگر نسخهٔ آزمایشی شوید + به گروه آزمایشی ما در گوگل‌پلی بپیوندید و از خصوصیات جدید و خطاهای رفع‌شده زودتر از دیگران برخوردار شوید. + استفاده از ویکی‌داده + (هشدار: غیرفعال کردن این ممکن است حجم زیادی از اینترنت تلفن همراه را مصرف کند) + کد 2FA + محدودیت بارگذاری اخیر من + حداکثر محدودیت + عدم توانایی در نمایش بیش از ۵۰۰ مورد + تنظیم محدودیت بارگذاری‌های اخیر + تأیید دومرحله‌ای الان پشتیبانی نمی‌شود. + آیا واقعاً قصد خروج از سامانه را دارید؟ + نشان ویکی‌انبار + تصویر پس‌زمینه + خطای تصویر رسانه + تصویری یافت نشد + بارگذاری تصویر + کوه زائو + لاما + رینبو بریج + لاله + سلفی نه + تصویر اختصاصی + به ویکی‌پدیا خوش‌آمدید + حق‌تکثیر خوش‌آمدگویی + خانه اپرای سیدنی + لغو + باز کردن + بستن + خانه + بارگذاری + در نزدیکی + درباره + تنظیمات + بازخورد + خروج + آموزش + مکان‌های اطراف بدون اجازه دادن به مکان‌یاب مقدور نیست + توضیحی یافت نشد + صفحهٔ دروند در ویکی‌انبار + آیتم ویکی‌داده + خطا در زمان دریافت تصاویر + عنوانی توصیفی و یکتا برای پرونده که به عنوان نام پرونده در نظر گرفته خواهد شد. ترجیحاً به زبان ساده باشد، می‌توانید فاصله هم به کار ببرید. پسوند پرونده را ننویسید. + لطفاً تصویر را تا حد توان شرح دهید. کجا گرفته شده‌است؟ شامل چه چیزی می‌شود؟ لطفاً اشیا یا افراد را شرح دهید. اطلاعاتی که به راحتی قابل مشاهده هستند را صرفه‌نظر کنید. اگر چیزی در تصویر غیر طبیعی به نظر می‌رسد آن را شرح دهید. diff --git a/app/src/main/res/values-sd/strings.xml b/app/src/main/res/values-sd/strings.xml index 00bc35c68..36a914281 100644 --- a/app/src/main/res/values-sd/strings.xml +++ b/app/src/main/res/values-sd/strings.xml @@ -41,7 +41,7 @@ ناقابلِ داخل ٿيڻ - براءِ مھرباني پنھنجو يُوزرنانءُ چڪاسيو ناقابل داخل ٿيڻ - براءِ مھرباني پنھنجو ڳجھولفظ چڪاسيو ھيڪانديون ناڪام ڪوششون. براءِ مھرباني ڪجھ منٽن کانپوءِ ٻيھر ڪوشش ڪريو. - افسوس، ھي يوزر العام تي بندشيل آھي + افسوس، ھي واھپ العام تي بندشيل آھي داخل ٿيڻ ناڪام چاڙھيو ھن سيٽ کي نالو ڏيو diff --git a/app/src/test/java/fr/free/nrw/commons/MediaTest.java b/app/src/test/java/fr/free/nrw/commons/MediaTest.java new file mode 100644 index 000000000..21cfc2c34 --- /dev/null +++ b/app/src/test/java/fr/free/nrw/commons/MediaTest.java @@ -0,0 +1,25 @@ +package fr.free.nrw.commons; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(RobolectricTestRunner.class) +@Config(constants = BuildConfig.class, sdk = 21) +public class MediaTest { + @Test + public void displayTitleShouldStripExtension() { + Media m = new Media("File:Example.jpg"); + assertThat(m.getDisplayTitle(), is("Example")); + } + + @Test + public void displayTitleShouldUseSpaceForUnderscore() { + Media m = new Media("File:Example 1_2.jpg"); + assertThat(m.getDisplayTitle(), is("Example 1 2")); + } +} diff --git a/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java b/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java new file mode 100644 index 000000000..6ae2063da --- /dev/null +++ b/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java @@ -0,0 +1,44 @@ +package fr.free.nrw.commons; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +import fr.free.nrw.commons.location.LatLng; +import fr.free.nrw.commons.nearby.NearbyBaseMarker; +import fr.free.nrw.commons.nearby.Place; + +import static fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(RobolectricTestRunner.class) +@Config(constants = BuildConfig.class, sdk = 21) +public class NearbyControllerTest { + + @Test + public void testNullAttractions() { + LatLng location = new LatLng(0, 0, 0); + + List options = loadAttractionsFromLocationToBaseMarkerOptions( + location, null, RuntimeEnvironment.application); + + assertThat(options.size(), is(0)); + } + + @Test + public void testEmptyList() { + LatLng location = new LatLng(0, 0, 0); + List emptyList = new ArrayList<>(); + + List options = loadAttractionsFromLocationToBaseMarkerOptions( + location, emptyList, RuntimeEnvironment.application); + + assertThat(options.size(), is(0)); + } +} diff --git a/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java b/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java new file mode 100644 index 000000000..455b3fbd0 --- /dev/null +++ b/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java @@ -0,0 +1,70 @@ +package fr.free.nrw.commons; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.net.URLEncoder; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(RobolectricTestRunner.class) +@Config(constants = BuildConfig.class, sdk = 21) +public class PageTitleTest { + @Test + public void displayTextShouldNotBeUnderscored() { + assertThat(new PageTitle("Ex_1 ").getDisplayText(), + is("Ex 1")); + } + + @Test + public void moreThanTwoColons() { + assertThat(new PageTitle("File:sample:a.jpg").getPrefixedText(), + is("File:Sample:a.jpg")); + } + + @Test + public void getTextShouldReturnWithoutNamespace() { + assertThat(new PageTitle("File:sample.jpg").getText(), + is("Sample.jpg")); + } + + + @Test + public void capitalizeNameAfterNamespace() { + assertThat(new PageTitle("File:sample.jpg").getPrefixedText(), + is("File:Sample.jpg")); + } + + @Test + public void prefixedTextShouldBeUnderscored() { + assertThat(new PageTitle("Ex 1 ").getPrefixedText(), + is("Ex_1")); + } + + @Test + public void getMobileUriForTest() { + assertThat(new PageTitle("Test").getMobileUri().toString(), + is(BuildConfig.MOBILE_HOME_URL + "Test")); + } + + @Test + public void spaceBecomesUnderscoreInUri() { + assertThat(new PageTitle("File:Ex 1.jpg").getCanonicalUri().toString(), + is(BuildConfig.HOME_URL + "File:Ex_1.jpg")); + } + + @Test + public void leaveSubpageNamesUncapitalizedInUri() { + assertThat(new PageTitle("User:Ex/subpage").getCanonicalUri().toString(), + is(BuildConfig.HOME_URL + "User:Ex/subpage")); + } + + @Test + public void unicodeUri() throws Throwable { + assertThat(new PageTitle("User:例").getCanonicalUri().toString(), + is(BuildConfig.HOME_URL + "User:" + URLEncoder.encode("例", "utf-8"))); + } +} diff --git a/dependency-injection.md b/dependency-injection.md new file mode 100644 index 000000000..5d3599e54 --- /dev/null +++ b/dependency-injection.md @@ -0,0 +1,41 @@ +## Overview + +At its core, dependency injection is just the principle of `"tell, dont ask"` put into practice; for instance, if a class needs to use the `MediaWikiApi`, it should be handed an instance of the classs rather than reaching out to get it. This has the effect of decoupling code, making it easier to test and reuse. + +## Dependency Injection in the Commons app + +We use Dagger 2 as our dependency injection engine. Dagger is a fully static, compile-time dependency injection framework for both Java and Android. Dagger aims to address many of the development and performance issues that have plagued reflection-based solutions that came before it, but it does come at something of a cost in complexity. + +For more information about Dagger, take a look at the [Dagger user guide](https://google.github.io/dagger/users-guide.html). + +## Dagger configuration in the Commons app + +The top level `CommonsApplicationComponent` pulls together configuration for injection across the app. The most important files to understand + +- if you need to add a new Activity, look at `ActivityBuilderModule` and copy how injection is configured. The `BaseActivity` class will take care of the rest. +- if you are adding a new Fragment, look at `FragmentBuilderModule` +- if you are adding a new ContentProvider, look at `ContentProviderBuilderModule` +- if you are adding a new Service, look at `ServiceBuilderModule` +- other dependencies are configured in `CommonsApplicationModule` + +## "Provider" methods + +Dagger will resolve the method arguments on provider methods in a module (or the constructor arguments when annotated with `@Inject`) and build the objects accordingly - either by calling another provider method or by looking for a constructor on a class that has the `@Inject` annotation. Dagger takes care of managing singletons, just annotate with the `@Singleton` annotation. For instance, + +```java +@Provides +@Singleton +public SessionManager providesSessionManager(MediaWikiApi mediaWikiApi) { + return new SessionManager(application, mediaWikiApi); +} +``` + +If your code injects an interface (in this case, `MediaWikiApi`) then Dagger needs to know which concrete class to use. This comes by way of a provider method: + +```java +@Provides +@Singleton +public MediaWikiApi provideMediaWikiApi() { + return new ApacheHttpClientMediaWikiApi(BuildConfig.WIKIMEDIA_API_HOST); +} +```