mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-30 22:34:02 +01:00
Issue 5811: fixes merge conflicts, replaces used function onActivityResult with an ActivityResultLauncher
This commit is contained in:
parent
40bc11ee61
commit
4663c78953
138 changed files with 1602 additions and 1126 deletions
|
|
@ -174,7 +174,7 @@ dependencies {
|
||||||
kaptTest "androidx.databinding:databinding-compiler:8.0.2"
|
kaptTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||||
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
|
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||||
|
|
||||||
implementation("io.github.coordinates2country:coordinates2country-android:1.3") { exclude group: 'com.google.android', module: 'android' }
|
implementation("io.github.coordinates2country:coordinates2country-android:1.8") { exclude group: 'com.google.android', module: 'android' }
|
||||||
|
|
||||||
//OSMDroid
|
//OSMDroid
|
||||||
implementation ("org.osmdroid:osmdroid-android:$OSMDROID_VERSION")
|
implementation ("org.osmdroid:osmdroid-android:$OSMDROID_VERSION")
|
||||||
|
|
@ -226,7 +226,7 @@ android {
|
||||||
excludes += ['META-INF/androidx.*']
|
excludes += ['META-INF/androidx.*']
|
||||||
}
|
}
|
||||||
resources {
|
resources {
|
||||||
excludes += ['META-INF/androidx.*', 'META-INF/proguard/androidx-annotations.pro']
|
excludes += ['META-INF/androidx.*', 'META-INF/proguard/androidx-annotations.pro', '/META-INF/LICENSE.md', '/META-INF/LICENSE-notice.md']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,7 +380,7 @@ android {
|
||||||
compose true
|
compose true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion '1.3.2'
|
kotlinCompilerExtensionVersion '1.5.8'
|
||||||
}
|
}
|
||||||
namespace 'fr.free.nrw.commons'
|
namespace 'fr.free.nrw.commons'
|
||||||
lint {
|
lint {
|
||||||
|
|
|
||||||
|
|
@ -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.getInstance().languageLookUpTable.codes[0]
|
val langCode = CommonsApplication.instance.languageLookUpTable!!.codes[0]
|
||||||
Intents.intended(
|
Intents.intended(
|
||||||
CoreMatchers.allOf(
|
CoreMatchers.allOf(
|
||||||
IntentMatchers.hasAction(Intent.ACTION_VIEW),
|
IntentMatchers.hasAction(Intent.ACTION_VIEW),
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
|
import org.hamcrest.CoreMatchers.equalTo
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
|
@ -59,7 +61,7 @@ class WelcomeActivityTest {
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
onView(withId(R.id.finishTutorialButton))
|
onView(withId(R.id.finishTutorialButton))
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
assert(activityRule.activity.isDestroyed)
|
assertThat(activityRule.activity.isDestroyed, equalTo(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,10 +71,10 @@ class WelcomeActivityTest {
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
onView(withId(R.id.welcomePager))
|
onView(withId(R.id.welcomePager))
|
||||||
.perform(ViewActions.swipeLeft())
|
.perform(ViewActions.swipeLeft())
|
||||||
assert(true)
|
assertThat(true, equalTo(true))
|
||||||
onView(withId(R.id.welcomePager))
|
onView(withId(R.id.welcomePager))
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
assert(true)
|
assertThat(true, equalTo(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -84,13 +86,13 @@ class WelcomeActivityTest {
|
||||||
.perform(ViewActions.swipeLeft())
|
.perform(ViewActions.swipeLeft())
|
||||||
.perform(ViewActions.swipeLeft())
|
.perform(ViewActions.swipeLeft())
|
||||||
.perform(ViewActions.swipeLeft())
|
.perform(ViewActions.swipeLeft())
|
||||||
assert(true)
|
assertThat(true, equalTo(true))
|
||||||
onView(withId(R.id.welcomePager))
|
onView(withId(R.id.welcomePager))
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
assert(true)
|
assertThat(true, equalTo(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -101,10 +103,10 @@ class WelcomeActivityTest {
|
||||||
if (viewPager.currentItem == 3) {
|
if (viewPager.currentItem == 3) {
|
||||||
onView(withId(R.id.welcomePager))
|
onView(withId(R.id.welcomePager))
|
||||||
.perform(ViewActions.swipeLeft())
|
.perform(ViewActions.swipeLeft())
|
||||||
assert(true)
|
assertThat(true, equalTo(true))
|
||||||
onView(withId(R.id.welcomePager))
|
onView(withId(R.id.welcomePager))
|
||||||
.perform(ViewActions.swipeRight())
|
.perform(ViewActions.swipeRight())
|
||||||
assert(false)
|
assertThat(true, equalTo(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +121,7 @@ class WelcomeActivityTest {
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
onView(withId(R.id.finishTutorialButton))
|
onView(withId(R.id.finishTutorialButton))
|
||||||
.perform(ViewActions.click())
|
.perform(ViewActions.click())
|
||||||
assert(activityRule.activity.isDestroyed)
|
assertThat(activityRule.activity.isDestroyed, equalTo(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
android:maxSdkVersion="29"/>
|
android:maxSdkVersion="29"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
<!-- Permission needed up to Android 5.1, see https://github.com/commons-app/apps-android-commons/pull/5863 -->
|
||||||
|
<uses-permission android:name="android.permission.GET_ACCOUNTS"
|
||||||
|
android:maxSdkVersion="22"/>
|
||||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
|
@ -97,7 +99,6 @@
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:hardwareAccelerated="false"
|
android:hardwareAccelerated="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter android:label="@string/intent_share_upload_label">
|
<intent-filter android:label="@string/intent_share_upload_label">
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
@ -120,7 +121,7 @@
|
||||||
android:name=".contributions.MainActivity"
|
android:name=".contributions.MainActivity"
|
||||||
android:configChanges="screenSize|keyboard|orientation"
|
android:configChanges="screenSize|keyboard|orientation"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name" />
|
/>
|
||||||
<activity
|
<activity
|
||||||
android:name=".settings.SettingsActivity"
|
android:name=".settings.SettingsActivity"
|
||||||
android:label="@string/title_activity_settings" />
|
android:label="@string/title_activity_settings" />
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ class BaseMarker {
|
||||||
val drawable: Drawable = context.resources.getDrawable(drawableResId)
|
val drawable: Drawable = context.resources.getDrawable(drawableResId)
|
||||||
icon =
|
icon =
|
||||||
if (drawable is BitmapDrawable) {
|
if (drawable is BitmapDrawable) {
|
||||||
(drawable as BitmapDrawable).bitmap
|
drawable.bitmap
|
||||||
} else {
|
} else {
|
||||||
val bitmap =
|
val bitmap =
|
||||||
Bitmap.createBitmap(
|
Bitmap.createBitmap(
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,64 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
import static fr.free.nrw.commons.data.DBOpenHelper.CONTRIBUTIONS_TABLE;
|
import android.annotation.SuppressLint
|
||||||
import static org.acra.ReportField.ANDROID_VERSION;
|
import android.app.Activity
|
||||||
import static org.acra.ReportField.APP_VERSION_CODE;
|
import android.app.NotificationChannel
|
||||||
import static org.acra.ReportField.APP_VERSION_NAME;
|
import android.app.NotificationManager
|
||||||
import static org.acra.ReportField.PHONE_MODEL;
|
import android.content.Context
|
||||||
import static org.acra.ReportField.STACK_TRACE;
|
import android.content.Intent
|
||||||
import static org.acra.ReportField.USER_COMMENT;
|
import android.database.sqlite.SQLiteException
|
||||||
|
import android.os.Build
|
||||||
import android.annotation.SuppressLint;
|
import android.os.Process
|
||||||
import android.app.Activity;
|
import android.util.Log
|
||||||
import android.app.NotificationChannel;
|
import androidx.multidex.MultiDexApplication
|
||||||
import android.app.NotificationManager;
|
import com.facebook.drawee.backends.pipeline.Fresco
|
||||||
import android.content.Context;
|
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
||||||
import android.content.Intent;
|
import fr.free.nrw.commons.auth.LoginActivity
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import android.database.sqlite.SQLiteException;
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao
|
||||||
import android.os.Build;
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
import android.os.Process;
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao
|
||||||
import android.util.Log;
|
import fr.free.nrw.commons.category.CategoryDao
|
||||||
import androidx.annotation.NonNull;
|
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler
|
||||||
import androidx.multidex.MultiDexApplication;
|
import fr.free.nrw.commons.concurrency.ThreadPoolService
|
||||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
import fr.free.nrw.commons.contributions.ContributionDao
|
||||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
import fr.free.nrw.commons.data.DBOpenHelper
|
||||||
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||||
import fr.free.nrw.commons.auth.LoginActivity;
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.language.AppLanguageLookUpTable
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table;
|
import fr.free.nrw.commons.logging.FileLoggingTree
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
import fr.free.nrw.commons.logging.LogUtils
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
import fr.free.nrw.commons.media.CustomOkHttpNetworkFetcher
|
||||||
import fr.free.nrw.commons.category.CategoryDao;
|
import fr.free.nrw.commons.settings.Prefs
|
||||||
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler;
|
import fr.free.nrw.commons.upload.FileUtils
|
||||||
import fr.free.nrw.commons.concurrency.ThreadPoolService;
|
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
import io.reactivex.Completable
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import fr.free.nrw.commons.language.AppLanguageLookUpTable;
|
import io.reactivex.internal.functions.Functions
|
||||||
import fr.free.nrw.commons.logging.FileLoggingTree;
|
import io.reactivex.plugins.RxJavaPlugins
|
||||||
import fr.free.nrw.commons.logging.LogUtils;
|
import io.reactivex.schedulers.Schedulers
|
||||||
import fr.free.nrw.commons.media.CustomOkHttpNetworkFetcher;
|
import org.acra.ACRA.init
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import org.acra.ReportField
|
||||||
import fr.free.nrw.commons.upload.FileUtils;
|
import org.acra.annotation.AcraCore
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
import org.acra.annotation.AcraDialog
|
||||||
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar;
|
import org.acra.annotation.AcraMailSender
|
||||||
import io.reactivex.Completable;
|
import org.acra.data.StringFormat
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import timber.log.Timber
|
||||||
import io.reactivex.internal.functions.Functions;
|
import timber.log.Timber.DebugTree
|
||||||
import io.reactivex.plugins.RxJavaPlugins;
|
import java.io.File
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import javax.inject.Inject
|
||||||
import java.io.File;
|
import javax.inject.Named
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import org.acra.ACRA;
|
|
||||||
import org.acra.annotation.AcraCore;
|
|
||||||
import org.acra.annotation.AcraDialog;
|
|
||||||
import org.acra.annotation.AcraMailSender;
|
|
||||||
import org.acra.data.StringFormat;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
@AcraCore(
|
@AcraCore(
|
||||||
buildConfigClass = BuildConfig.class,
|
buildConfigClass = BuildConfig::class,
|
||||||
resReportSendSuccessToast = R.string.crash_dialog_ok_toast,
|
resReportSendSuccessToast = R.string.crash_dialog_ok_toast,
|
||||||
reportFormat = StringFormat.KEY_VALUE_LIST,
|
reportFormat = StringFormat.KEY_VALUE_LIST,
|
||||||
reportContent = {USER_COMMENT, APP_VERSION_CODE, APP_VERSION_NAME, ANDROID_VERSION, PHONE_MODEL,
|
reportContent = [ReportField.USER_COMMENT, ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME, ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, ReportField.STACK_TRACE]
|
||||||
STACK_TRACE}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@AcraMailSender(
|
@AcraMailSender(mailTo = "commons-app-android-private@googlegroups.com", reportAsFile = false)
|
||||||
mailTo = "commons-app-android-private@googlegroups.com",
|
|
||||||
reportAsFile = false
|
|
||||||
)
|
|
||||||
|
|
||||||
@AcraDialog(
|
@AcraDialog(
|
||||||
resTheme = R.style.Theme_AppCompat_Dialog,
|
resTheme = R.style.Theme_AppCompat_Dialog,
|
||||||
|
|
@ -83,137 +67,100 @@ import timber.log.Timber;
|
||||||
resCommentPrompt = R.string.crash_dialog_comment_prompt
|
resCommentPrompt = R.string.crash_dialog_comment_prompt
|
||||||
)
|
)
|
||||||
|
|
||||||
public class CommonsApplication extends MultiDexApplication {
|
class CommonsApplication : MultiDexApplication() {
|
||||||
|
|
||||||
public static final String loginMessageIntentKey = "loginMessage";
|
|
||||||
public static final String loginUsernameIntentKey = "loginUsername";
|
|
||||||
|
|
||||||
public static final String IS_LIMITED_CONNECTION_MODE_ENABLED = "is_limited_connection_mode_enabled";
|
|
||||||
@Inject
|
|
||||||
SessionManager sessionManager;
|
|
||||||
@Inject
|
|
||||||
DBOpenHelper dbOpenHelper;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Named("default_preferences")
|
lateinit var sessionManager: SessionManager
|
||||||
JsonKvStore defaultPrefs;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CommonsCookieJar cookieJar;
|
lateinit var dbOpenHelper: DBOpenHelper
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CustomOkHttpNetworkFetcher customOkHttpNetworkFetcher;
|
@field:Named("default_preferences")
|
||||||
|
lateinit var defaultPrefs: JsonKvStore
|
||||||
/**
|
|
||||||
* Constants begin
|
|
||||||
*/
|
|
||||||
public static final int OPEN_APPLICATION_DETAIL_SETTINGS = 1001;
|
|
||||||
|
|
||||||
public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using [[COM:MOA|Commons Mobile App]]";
|
|
||||||
|
|
||||||
public static final String FEEDBACK_EMAIL = "commons-app-android@googlegroups.com";
|
|
||||||
|
|
||||||
public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App Feedback";
|
|
||||||
|
|
||||||
public static final String REPORT_EMAIL = "commons-app-android-private@googlegroups.com";
|
|
||||||
|
|
||||||
public static final String REPORT_EMAIL_SUBJECT = "Report a violation";
|
|
||||||
|
|
||||||
public static final String NOTIFICATION_CHANNEL_ID_ALL = "CommonsNotificationAll";
|
|
||||||
|
|
||||||
public static final String FEEDBACK_EMAIL_TEMPLATE_HEADER = "-- Technical information --";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constants End
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static CommonsApplication INSTANCE;
|
|
||||||
|
|
||||||
public static CommonsApplication getInstance() {
|
|
||||||
return INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AppLanguageLookUpTable languageLookUpTable;
|
|
||||||
|
|
||||||
public AppLanguageLookUpTable getLanguageLookUpTable() {
|
|
||||||
return languageLookUpTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ContributionDao contributionDao;
|
lateinit var cookieJar: CommonsCookieJar
|
||||||
|
|
||||||
public static Boolean isPaused = false;
|
@Inject
|
||||||
|
lateinit var customOkHttpNetworkFetcher: CustomOkHttpNetworkFetcher
|
||||||
|
|
||||||
|
var languageLookUpTable: AppLanguageLookUpTable? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var contributionDao: ContributionDao
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to declare and initialize various components and dependencies
|
* Used to declare and initialize various components and dependencies
|
||||||
*/
|
*/
|
||||||
@Override
|
override fun onCreate() {
|
||||||
public void onCreate() {
|
super.onCreate()
|
||||||
super.onCreate();
|
|
||||||
|
|
||||||
INSTANCE = this;
|
instance = this
|
||||||
ACRA.init(this);
|
init(this)
|
||||||
|
|
||||||
ApplicationlessInjection
|
ApplicationlessInjection
|
||||||
.getInstance(this)
|
.getInstance(this)
|
||||||
.getCommonsApplicationComponent()
|
.commonsApplicationComponent
|
||||||
.inject(this);
|
.inject(this)
|
||||||
|
|
||||||
initTimber();
|
initTimber()
|
||||||
|
|
||||||
if (!defaultPrefs.getBoolean("has_user_manually_removed_location")) {
|
if (!defaultPrefs.getBoolean("has_user_manually_removed_location")) {
|
||||||
Set<String> defaultExifTagsSet = defaultPrefs.getStringSet(Prefs.MANAGED_EXIF_TAGS);
|
var defaultExifTagsSet = defaultPrefs.getStringSet(Prefs.MANAGED_EXIF_TAGS)
|
||||||
if (null == defaultExifTagsSet) {
|
if (null == defaultExifTagsSet) {
|
||||||
defaultExifTagsSet = new HashSet<>();
|
defaultExifTagsSet = HashSet()
|
||||||
}
|
}
|
||||||
defaultExifTagsSet.add(getString(R.string.exif_tag_location));
|
defaultExifTagsSet.add(getString(R.string.exif_tag_location))
|
||||||
defaultPrefs.putStringSet(Prefs.MANAGED_EXIF_TAGS, defaultExifTagsSet);
|
defaultPrefs.putStringSet(Prefs.MANAGED_EXIF_TAGS, defaultExifTagsSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set DownsampleEnabled to True to downsample the image in case it's heavy
|
// Set DownsampleEnabled to True to downsample the image in case it's heavy
|
||||||
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
|
val config = ImagePipelineConfig.newBuilder(this)
|
||||||
.setNetworkFetcher(customOkHttpNetworkFetcher)
|
.setNetworkFetcher(customOkHttpNetworkFetcher)
|
||||||
.setDownsampleEnabled(true)
|
.setDownsampleEnabled(true)
|
||||||
.build();
|
.build()
|
||||||
try {
|
try {
|
||||||
Fresco.initialize(this, config);
|
Fresco.initialize(this, config)
|
||||||
} catch (Exception e) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e);
|
Timber.e(e)
|
||||||
// TODO: Remove when we're able to initialize Fresco in test builds.
|
// TODO: Remove when we're able to initialize Fresco in test builds.
|
||||||
}
|
}
|
||||||
|
|
||||||
createNotificationChannel(this);
|
createNotificationChannel(this)
|
||||||
|
|
||||||
languageLookUpTable = new AppLanguageLookUpTable(this);
|
languageLookUpTable = AppLanguageLookUpTable(this)
|
||||||
|
|
||||||
// This handler will catch exceptions thrown from Observables after they are disposed,
|
// This handler will catch exceptions thrown from Observables after they are disposed,
|
||||||
// or from Observables that are (deliberately or not) missing an onError handler.
|
// or from Observables that are (deliberately or not) missing an onError handler.
|
||||||
RxJavaPlugins.setErrorHandler(Functions.emptyConsumer());
|
RxJavaPlugins.setErrorHandler(Functions.emptyConsumer())
|
||||||
|
|
||||||
// Fire progress callbacks for every 3% of uploaded content
|
// Fire progress callbacks for every 3% of uploaded content
|
||||||
System.setProperty("in.yuvi.http.fluent.PROGRESS_TRIGGER_THRESHOLD", "3.0");
|
System.setProperty("in.yuvi.http.fluent.PROGRESS_TRIGGER_THRESHOLD", "3.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plants debug and file logging tree. Timber lets you plant your own logging trees.
|
* Plants debug and file logging tree. Timber lets you plant your own logging trees.
|
||||||
*/
|
*/
|
||||||
private void initTimber() {
|
private fun initTimber() {
|
||||||
boolean isBeta = ConfigUtils.isBetaFlavour();
|
val isBeta = isBetaFlavour
|
||||||
String logFileName =
|
val logFileName =
|
||||||
isBeta ? "CommonsBetaAppLogs" : "CommonsAppLogs";
|
if (isBeta) "CommonsBetaAppLogs" else "CommonsAppLogs"
|
||||||
String logDirectory = LogUtils.getLogDirectory();
|
val logDirectory = LogUtils.getLogDirectory()
|
||||||
//Delete stale logs if they have exceeded the specified size
|
//Delete stale logs if they have exceeded the specified size
|
||||||
deleteStaleLogs(logFileName, logDirectory);
|
deleteStaleLogs(logFileName, logDirectory)
|
||||||
|
|
||||||
FileLoggingTree tree = new FileLoggingTree(
|
val tree = FileLoggingTree(
|
||||||
Log.VERBOSE,
|
Log.VERBOSE,
|
||||||
logFileName,
|
logFileName,
|
||||||
logDirectory,
|
logDirectory,
|
||||||
1000,
|
1000,
|
||||||
getFileLoggingThreadPool());
|
fileLoggingThreadPool
|
||||||
|
)
|
||||||
|
|
||||||
Timber.plant(tree);
|
Timber.plant(tree)
|
||||||
Timber.plant(new Timber.DebugTree());
|
Timber.plant(DebugTree())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -223,48 +170,27 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* @param logFileName
|
* @param logFileName
|
||||||
* @param logDirectory
|
* @param logDirectory
|
||||||
*/
|
*/
|
||||||
private void deleteStaleLogs(String logFileName, String logDirectory) {
|
private fun deleteStaleLogs(logFileName: String, logDirectory: String) {
|
||||||
try {
|
try {
|
||||||
File file = new File(logDirectory + "/zip/" + logFileName + ".zip");
|
val file = File("$logDirectory/zip/$logFileName.zip")
|
||||||
if (file.exists() && file.getTotalSpace() > 1000000) {// In Kbs
|
if (file.exists() && file.totalSpace > 1000000) { // In Kbs
|
||||||
file.delete();
|
file.delete()
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e);
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRoboUnitTest() {
|
private val fileLoggingThreadPool: ThreadPoolService
|
||||||
return "robolectric".equals(Build.FINGERPRINT);
|
get() = ThreadPoolService.Builder("file-logging-thread")
|
||||||
}
|
|
||||||
|
|
||||||
private ThreadPoolService getFileLoggingThreadPool() {
|
|
||||||
return new ThreadPoolService.Builder("file-logging-thread")
|
|
||||||
.setPriority(Process.THREAD_PRIORITY_LOWEST)
|
.setPriority(Process.THREAD_PRIORITY_LOWEST)
|
||||||
.setPoolSize(1)
|
.setPoolSize(1)
|
||||||
.setExceptionHandler(new BackgroundPoolExceptionHandler())
|
.setExceptionHandler(BackgroundPoolExceptionHandler())
|
||||||
.build();
|
.build()
|
||||||
}
|
|
||||||
|
|
||||||
public static void createNotificationChannel(@NonNull Context context) {
|
val userAgent: String
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
get() = ("Commons/" + this.getVersionNameWithSha()
|
||||||
NotificationManager manager = (NotificationManager) context
|
+ " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE)
|
||||||
.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
NotificationChannel channel = manager
|
|
||||||
.getNotificationChannel(NOTIFICATION_CHANNEL_ID_ALL);
|
|
||||||
if (channel == null) {
|
|
||||||
channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID_ALL,
|
|
||||||
context.getString(R.string.notifications_channel_name_all),
|
|
||||||
NotificationManager.IMPORTANCE_DEFAULT);
|
|
||||||
manager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserAgent() {
|
|
||||||
return "Commons/" + ConfigUtils.getVersionNameWithSha(this)
|
|
||||||
+ " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clears data of current application
|
* clears data of current application
|
||||||
|
|
@ -273,88 +199,88 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* @param logoutListener Implementation of interface LogoutListener
|
* @param logoutListener Implementation of interface LogoutListener
|
||||||
*/
|
*/
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public void clearApplicationData(Context context, LogoutListener logoutListener) {
|
fun clearApplicationData(context: Context, logoutListener: LogoutListener) {
|
||||||
File cacheDirectory = context.getCacheDir();
|
val cacheDirectory = context.cacheDir
|
||||||
File applicationDirectory = new File(cacheDirectory.getParent());
|
val applicationDirectory = File(cacheDirectory.parent)
|
||||||
if (applicationDirectory.exists()) {
|
if (applicationDirectory.exists()) {
|
||||||
String[] fileNames = applicationDirectory.list();
|
val fileNames = applicationDirectory.list()
|
||||||
for (String fileName : fileNames) {
|
for (fileName in fileNames) {
|
||||||
if (!fileName.equals("lib")) {
|
if (fileName != "lib") {
|
||||||
FileUtils.deleteFile(new File(applicationDirectory, fileName));
|
FileUtils.deleteFile(File(applicationDirectory, fileName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionManager.logout()
|
sessionManager.logout()
|
||||||
.andThen(Completable.fromAction(() -> cookieJar.clear()))
|
.andThen(Completable.fromAction { cookieJar.clear() })
|
||||||
.andThen(Completable.fromAction(() -> {
|
.andThen(Completable.fromAction {
|
||||||
Timber.d("All accounts have been removed");
|
Timber.d("All accounts have been removed")
|
||||||
clearImageCache();
|
clearImageCache()
|
||||||
//TODO: fix preference manager
|
//TODO: fix preference manager
|
||||||
defaultPrefs.clearAll();
|
defaultPrefs.clearAll()
|
||||||
defaultPrefs.putBoolean("firstrun", false);
|
defaultPrefs.putBoolean("firstrun", false)
|
||||||
updateAllDatabases();
|
updateAllDatabases()
|
||||||
}
|
})
|
||||||
))
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(logoutListener::onLogoutComplete, Timber::e);
|
.subscribe({ logoutListener.onLogoutComplete() }, { t: Throwable? -> Timber.e(t) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all images cache held by Fresco
|
* Clear all images cache held by Fresco
|
||||||
*/
|
*/
|
||||||
private void clearImageCache() {
|
private fun clearImageCache() {
|
||||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
val imagePipeline = Fresco.getImagePipeline()
|
||||||
imagePipeline.clearCaches();
|
imagePipeline.clearCaches()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes all tables and re-creates them.
|
* Deletes all tables and re-creates them.
|
||||||
*/
|
*/
|
||||||
private void updateAllDatabases() {
|
private fun updateAllDatabases() {
|
||||||
dbOpenHelper.getReadableDatabase().close();
|
dbOpenHelper.readableDatabase.close()
|
||||||
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
val db = dbOpenHelper.writableDatabase
|
||||||
|
|
||||||
CategoryDao.Table.onDelete(db);
|
CategoryDao.Table.onDelete(db)
|
||||||
dbOpenHelper.deleteTable(db,
|
dbOpenHelper.deleteTable(
|
||||||
CONTRIBUTIONS_TABLE);//Delete the contributions table in the existing db on older versions
|
db,
|
||||||
|
DBOpenHelper.CONTRIBUTIONS_TABLE
|
||||||
|
) //Delete the contributions table in the existing db on older versions
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contributionDao.deleteAll();
|
contributionDao.deleteAll()
|
||||||
} catch (SQLiteException e) {
|
} catch (e: SQLiteException) {
|
||||||
Timber.e(e);
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
BookmarkPicturesDao.Table.onDelete(db);
|
BookmarkPicturesDao.Table.onDelete(db)
|
||||||
BookmarkLocationsDao.Table.onDelete(db);
|
BookmarkLocationsDao.Table.onDelete(db)
|
||||||
Table.onDelete(db);
|
BookmarkItemsDao.Table.onDelete(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface used to get log-out events
|
* Interface used to get log-out events
|
||||||
*/
|
*/
|
||||||
public interface LogoutListener {
|
interface LogoutListener {
|
||||||
|
fun onLogoutComplete()
|
||||||
void onLogoutComplete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This listener is responsible for handling post-logout actions, specifically invoking the LoginActivity
|
* This listener is responsible for handling post-logout actions, specifically invoking the LoginActivity
|
||||||
* with relevant intent parameters. It does not perform the actual logout operation.
|
* with relevant intent parameters. It does not perform the actual logout operation.
|
||||||
*/
|
*/
|
||||||
public static class BaseLogoutListener implements CommonsApplication.LogoutListener {
|
open class BaseLogoutListener : LogoutListener {
|
||||||
|
var ctx: Context
|
||||||
Context ctx;
|
var loginMessage: String? = null
|
||||||
String loginMessage, userName;
|
var userName: String? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for BaseLogoutListener.
|
* Constructor for BaseLogoutListener.
|
||||||
*
|
*
|
||||||
* @param ctx Application context
|
* @param ctx Application context
|
||||||
*/
|
*/
|
||||||
public BaseLogoutListener(final Context ctx) {
|
constructor(ctx: Context) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -364,28 +290,29 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* @param loginMessage Message to be displayed on the login page
|
* @param loginMessage Message to be displayed on the login page
|
||||||
* @param loginUsername Username to be pre-filled on the login page
|
* @param loginUsername Username to be pre-filled on the login page
|
||||||
*/
|
*/
|
||||||
public BaseLogoutListener(final Context ctx, final String loginMessage,
|
constructor(
|
||||||
final String loginUsername) {
|
ctx: Context, loginMessage: String?,
|
||||||
this.ctx = ctx;
|
loginUsername: String?
|
||||||
this.loginMessage = loginMessage;
|
) {
|
||||||
this.userName = loginUsername;
|
this.ctx = ctx
|
||||||
|
this.loginMessage = loginMessage
|
||||||
|
this.userName = loginUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun onLogoutComplete() {
|
||||||
public void onLogoutComplete() {
|
Timber.d("Logout complete callback received.")
|
||||||
Timber.d("Logout complete callback received.");
|
val loginIntent = Intent(ctx, LoginActivity::class.java)
|
||||||
final Intent loginIntent = new Intent(ctx, LoginActivity.class);
|
|
||||||
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
|
||||||
if (loginMessage != null) {
|
if (loginMessage != null) {
|
||||||
loginIntent.putExtra(loginMessageIntentKey, loginMessage);
|
loginIntent.putExtra(LOGIN_MESSAGE_INTENT_KEY, loginMessage)
|
||||||
}
|
}
|
||||||
if (userName != null) {
|
if (userName != null) {
|
||||||
loginIntent.putExtra(loginUsernameIntentKey, userName);
|
loginIntent.putExtra(LOGIN_USERNAME_INTENT_KEY, userName)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.startActivity(loginIntent);
|
ctx.startActivity(loginIntent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,9 +320,8 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* This class is an extension of BaseLogoutListener, providing additional functionality or customization
|
* This class is an extension of BaseLogoutListener, providing additional functionality or customization
|
||||||
* for the logout process. It includes specific actions to be taken during logout, such as handling redirection to the login screen.
|
* for the logout process. It includes specific actions to be taken during logout, such as handling redirection to the login screen.
|
||||||
*/
|
*/
|
||||||
public static class ActivityLogoutListener extends BaseLogoutListener {
|
class ActivityLogoutListener : BaseLogoutListener {
|
||||||
|
var activity: Activity
|
||||||
Activity activity;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -404,9 +330,8 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* @param activity The activity context from which the logout is initiated. Used to perform actions such as finishing the activity.
|
* @param activity The activity context from which the logout is initiated. Used to perform actions such as finishing the activity.
|
||||||
* @param ctx The application context, used for invoking the LoginActivity and passing relevant intent parameters as part of the post-logout process.
|
* @param ctx The application context, used for invoking the LoginActivity and passing relevant intent parameters as part of the post-logout process.
|
||||||
*/
|
*/
|
||||||
public ActivityLogoutListener(final Activity activity, final Context ctx) {
|
constructor(activity: Activity, ctx: Context) : super(ctx) {
|
||||||
super(ctx);
|
this.activity = activity
|
||||||
this.activity = activity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -417,16 +342,72 @@ public class CommonsApplication extends MultiDexApplication {
|
||||||
* @param loginMessage Message to be displayed on the login page after logout.
|
* @param loginMessage Message to be displayed on the login page after logout.
|
||||||
* @param loginUsername Username to be pre-filled on the login page after logout.
|
* @param loginUsername Username to be pre-filled on the login page after logout.
|
||||||
*/
|
*/
|
||||||
public ActivityLogoutListener(final Activity activity, final Context ctx,
|
constructor(
|
||||||
final String loginMessage, final String loginUsername) {
|
activity: Activity, ctx: Context?,
|
||||||
super(activity, loginMessage, loginUsername);
|
loginMessage: String?, loginUsername: String?
|
||||||
this.activity = activity;
|
) : super(activity, loginMessage, loginUsername) {
|
||||||
|
this.activity = activity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun onLogoutComplete() {
|
||||||
public void onLogoutComplete() {
|
super.onLogoutComplete()
|
||||||
super.onLogoutComplete();
|
activity.finish()
|
||||||
activity.finish();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val LOGIN_MESSAGE_INTENT_KEY: String = "loginMessage"
|
||||||
|
const val LOGIN_USERNAME_INTENT_KEY: String = "loginUsername"
|
||||||
|
|
||||||
|
const val IS_LIMITED_CONNECTION_MODE_ENABLED: String = "is_limited_connection_mode_enabled"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants begin
|
||||||
|
*/
|
||||||
|
const val OPEN_APPLICATION_DETAIL_SETTINGS: Int = 1001
|
||||||
|
|
||||||
|
const val DEFAULT_EDIT_SUMMARY: String = "Uploaded using [[COM:MOA|Commons Mobile App]]"
|
||||||
|
|
||||||
|
const val FEEDBACK_EMAIL: String = "commons-app-android@googlegroups.com"
|
||||||
|
|
||||||
|
const val FEEDBACK_EMAIL_SUBJECT: String = "Commons Android App Feedback"
|
||||||
|
|
||||||
|
const val REPORT_EMAIL: String = "commons-app-android-private@googlegroups.com"
|
||||||
|
|
||||||
|
const val REPORT_EMAIL_SUBJECT: String = "Report a violation"
|
||||||
|
|
||||||
|
const val NOTIFICATION_CHANNEL_ID_ALL: String = "CommonsNotificationAll"
|
||||||
|
|
||||||
|
const val FEEDBACK_EMAIL_TEMPLATE_HEADER: String = "-- Technical information --"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants End
|
||||||
|
*/
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
lateinit var instance: CommonsApplication
|
||||||
|
private set
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var isPaused: Boolean = false
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun createNotificationChannel(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val manager = context
|
||||||
|
.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
var channel = manager
|
||||||
|
.getNotificationChannel(NOTIFICATION_CHANNEL_ID_ALL)
|
||||||
|
if (channel == null) {
|
||||||
|
channel = NotificationChannel(
|
||||||
|
NOTIFICATION_CHANNEL_ID_ALL,
|
||||||
|
context.getString(R.string.notifications_channel_name_all),
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
)
|
||||||
|
manager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
||||||
|
|
@ -301,7 +302,8 @@ public class LocationPickerActivity extends BaseActivity implements
|
||||||
modifyLocationButton = findViewById(R.id.modify_location);
|
modifyLocationButton = findViewById(R.id.modify_location);
|
||||||
removeLocationButton = findViewById(R.id.remove_location);
|
removeLocationButton = findViewById(R.id.remove_location);
|
||||||
showInMapButton = findViewById(R.id.show_in_map);
|
showInMapButton = findViewById(R.id.show_in_map);
|
||||||
showInMapButton.setText(getResources().getString(R.string.show_in_map_app).toUpperCase());
|
showInMapButton.setText(getResources().getString(R.string.show_in_map_app).toUpperCase(
|
||||||
|
Locale.ROOT));
|
||||||
shadow = findViewById(R.id.location_picker_image_view_shadow);
|
shadow = findViewById(R.id.location_picker_image_view_shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package fr.free.nrw.commons
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import fr.free.nrw.commons.location.LatLng
|
import fr.free.nrw.commons.location.LatLng
|
||||||
import fr.free.nrw.commons.wikidata.model.page.PageTitle
|
import fr.free.nrw.commons.wikidata.model.page.PageTitle
|
||||||
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
@ -124,6 +125,7 @@ class Media constructor(
|
||||||
* Gets the categories the file falls under.
|
* Gets the categories the file falls under.
|
||||||
* @return file categories as an ArrayList of Strings
|
* @return file categories as an ArrayList of Strings
|
||||||
*/
|
*/
|
||||||
|
@IgnoredOnParcel
|
||||||
var addedCategories: List<String>? = null
|
var addedCategories: List<String>? = null
|
||||||
// TODO added categories should be removed. It is added for a short fix. On category update,
|
// TODO added categories should be removed. It is added for a short fix. On category update,
|
||||||
// categories should be re-fetched instead
|
// categories should be re-fetched instead
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class ThanksClient
|
||||||
revisionId.toString(), // Rev
|
revisionId.toString(), // Rev
|
||||||
null, // Log
|
null, // Log
|
||||||
csrfTokenClient.getTokenBlocking(), // Token
|
csrfTokenClient.getTokenBlocking(), // Token
|
||||||
CommonsApplication.getInstance().userAgent, // Source
|
CommonsApplication.instance.userAgent, // Source
|
||||||
).map { mwThankPostResponse ->
|
).map { mwThankPostResponse ->
|
||||||
mwThankPostResponse.result?.success == 1
|
mwThankPostResponse.result?.success == 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ import timber.log.Timber;
|
||||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||||
import static fr.free.nrw.commons.CommonsApplication.loginMessageIntentKey;
|
import static fr.free.nrw.commons.CommonsApplication.LOGIN_MESSAGE_INTENT_KEY;
|
||||||
import static fr.free.nrw.commons.CommonsApplication.loginUsernameIntentKey;
|
import static fr.free.nrw.commons.CommonsApplication.LOGIN_USERNAME_INTENT_KEY;
|
||||||
|
|
||||||
public class LoginActivity extends AccountAuthenticatorActivity {
|
public class LoginActivity extends AccountAuthenticatorActivity {
|
||||||
|
|
||||||
|
|
@ -94,8 +94,8 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
||||||
binding = ActivityLoginBinding.inflate(getLayoutInflater());
|
binding = ActivityLoginBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
String message = getIntent().getStringExtra(loginMessageIntentKey);
|
String message = getIntent().getStringExtra(LOGIN_MESSAGE_INTENT_KEY);
|
||||||
String username = getIntent().getStringExtra(loginUsernameIntentKey);
|
String username = getIntent().getStringExtra(LOGIN_USERNAME_INTENT_KEY);
|
||||||
|
|
||||||
binding.loginUsername.addTextChangedListener(textWatcher);
|
binding.loginUsername.addTextChangedListener(textWatcher);
|
||||||
binding.loginPassword.addTextChangedListener(textWatcher);
|
binding.loginPassword.addTextChangedListener(textWatcher);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.bookmarks.items;
|
package fr.free.nrw.commons.bookmarks.items;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -134,6 +135,7 @@ public class BookmarkItemsDao {
|
||||||
* @param cursor : Object for storing database data
|
* @param cursor : Object for storing database data
|
||||||
* @return DepictedItem
|
* @return DepictedItem
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("Range")
|
||||||
DepictedItem fromCursor(final Cursor cursor) {
|
DepictedItem fromCursor(final Cursor cursor) {
|
||||||
final String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
final String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
||||||
final String description
|
final String description
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
package fr.free.nrw.commons.bookmarks.locations;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -146,6 +147,7 @@ public class BookmarkLocationsDao {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("Range")
|
||||||
@NonNull
|
@NonNull
|
||||||
Place fromCursor(final Cursor cursor) {
|
Place fromCursor(final Cursor cursor) {
|
||||||
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
|
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import android.view.ViewGroup;
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
import androidx.activity.result.ActivityResultCallback;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
@ -33,6 +34,23 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
||||||
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
||||||
private PlaceAdapter adapter;
|
private PlaceAdapter adapter;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
contributionController.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(Map<String, Boolean> result) {
|
public void onActivityResult(Map<String, Boolean> result) {
|
||||||
|
|
@ -45,7 +63,7 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
contributionController.locationPermissionCallback.onLocationPermissionGranted();
|
contributionController.locationPermissionCallback.onLocationPermissionGranted();
|
||||||
} else {
|
} else {
|
||||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher);
|
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
} else {
|
} else {
|
||||||
contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied));
|
contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied));
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +101,9 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
},
|
},
|
||||||
commonPlaceClickActions,
|
commonPlaceClickActions,
|
||||||
inAppCameraLocationPermissionLauncher
|
inAppCameraLocationPermissionLauncher,
|
||||||
|
galleryPickLauncherForResult,
|
||||||
|
cameraPickLauncherForResult
|
||||||
);
|
);
|
||||||
binding.listView.setAdapter(adapter);
|
binding.listView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
@ -109,11 +129,6 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
contributionController.handleActivityResult(getActivity(), requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.bookmarks.pictures;
|
package fr.free.nrw.commons.bookmarks.pictures;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -150,6 +151,7 @@ public class BookmarkPicturesDao {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("Range")
|
||||||
@NonNull
|
@NonNull
|
||||||
Bookmark fromCursor(Cursor cursor) {
|
Bookmark fromCursor(Cursor cursor) {
|
||||||
String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_NAME));
|
String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_NAME));
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ class CategoryClient
|
||||||
}.map {
|
}.map {
|
||||||
it
|
it
|
||||||
.filter { page ->
|
.filter { page ->
|
||||||
page.categoryInfo() == null || !page.categoryInfo().isHidden
|
!page.categoryInfo().isHidden
|
||||||
}.map {
|
}.map {
|
||||||
CategoryItem(
|
CategoryItem(
|
||||||
it.title().replace(CATEGORY_PREFIX, ""),
|
it.title().replace(CATEGORY_PREFIX, ""),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.category;
|
package fr.free.nrw.commons.category;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -111,6 +112,7 @@ public class CategoryDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@SuppressLint("Range")
|
||||||
Category fromCursor(Cursor cursor) {
|
Category fromCursor(Cursor cursor) {
|
||||||
// Hardcoding column positions!
|
// Hardcoding column positions!
|
||||||
return new Category(
|
return new Category(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
|
|
@ -64,10 +65,11 @@ public class ContributionController {
|
||||||
* Check for permissions and initiate camera click
|
* Check for permissions and initiate camera click
|
||||||
*/
|
*/
|
||||||
public void initiateCameraPick(Activity activity,
|
public void initiateCameraPick(Activity activity,
|
||||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||||
|
ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
||||||
if (!useExtStorage) {
|
if (!useExtStorage) {
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,12 +77,12 @@ public class ContributionController {
|
||||||
() -> {
|
() -> {
|
||||||
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
|
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
|
||||||
defaultKvStore.putBoolean("inAppCameraFirstRun", false);
|
defaultKvStore.putBoolean("inAppCameraFirstRun", false);
|
||||||
askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher);
|
askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||||
} else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) {
|
} else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) {
|
||||||
createDialogsAndHandleLocationPermissions(activity,
|
createDialogsAndHandleLocationPermissions(activity,
|
||||||
inAppCameraLocationPermissionLauncher);
|
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||||
} else {
|
} else {
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
|
|
@ -94,7 +96,8 @@ public class ContributionController {
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
private void createDialogsAndHandleLocationPermissions(Activity activity,
|
private void createDialogsAndHandleLocationPermissions(Activity activity,
|
||||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||||
|
ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
locationPermissionCallback = new LocationPermissionCallback() {
|
locationPermissionCallback = new LocationPermissionCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onLocationPermissionDenied(String toastMessage) {
|
public void onLocationPermissionDenied(String toastMessage) {
|
||||||
|
|
@ -103,16 +106,16 @@ public class ContributionController {
|
||||||
toastMessage,
|
toastMessage,
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show();
|
).show();
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationPermissionGranted() {
|
public void onLocationPermissionGranted() {
|
||||||
if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) {
|
if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) {
|
||||||
showLocationOffDialog(activity, R.string.in_app_camera_needs_location,
|
showLocationOffDialog(activity, R.string.in_app_camera_needs_location,
|
||||||
R.string.in_app_camera_location_unavailable);
|
R.string.in_app_camera_location_unavailable, resultLauncher);
|
||||||
} else {
|
} else {
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -135,9 +138,10 @@ public class ContributionController {
|
||||||
* @param activity Activity reference
|
* @param activity Activity reference
|
||||||
* @param dialogTextResource Resource id of text to be shown in dialog
|
* @param dialogTextResource Resource id of text to be shown in dialog
|
||||||
* @param toastTextResource Resource id of text to be shown in toast
|
* @param toastTextResource Resource id of text to be shown in toast
|
||||||
|
* @param resultLauncher
|
||||||
*/
|
*/
|
||||||
private void showLocationOffDialog(Activity activity, int dialogTextResource,
|
private void showLocationOffDialog(Activity activity, int dialogTextResource,
|
||||||
int toastTextResource) {
|
int toastTextResource, ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
DialogUtil
|
DialogUtil
|
||||||
.showAlertDialog(activity,
|
.showAlertDialog(activity,
|
||||||
activity.getString(R.string.ask_to_turn_location_on),
|
activity.getString(R.string.ask_to_turn_location_on),
|
||||||
|
|
@ -148,20 +152,21 @@ public class ContributionController {
|
||||||
() -> {
|
() -> {
|
||||||
Toast.makeText(activity, activity.getString(toastTextResource),
|
Toast.makeText(activity, activity.getString(toastTextResource),
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleShowRationaleFlowCameraLocation(Activity activity,
|
public void handleShowRationaleFlowCameraLocation(Activity activity,
|
||||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||||
|
ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
DialogUtil.showAlertDialog(activity, activity.getString(R.string.location_permission_title),
|
DialogUtil.showAlertDialog(activity, activity.getString(R.string.location_permission_title),
|
||||||
activity.getString(R.string.in_app_camera_location_permission_rationale),
|
activity.getString(R.string.in_app_camera_location_permission_rationale),
|
||||||
activity.getString(android.R.string.ok),
|
activity.getString(android.R.string.ok),
|
||||||
activity.getString(android.R.string.cancel),
|
activity.getString(android.R.string.cancel),
|
||||||
() -> {
|
() -> {
|
||||||
createDialogsAndHandleLocationPermissions(activity,
|
createDialogsAndHandleLocationPermissions(activity,
|
||||||
inAppCameraLocationPermissionLauncher);
|
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||||
},
|
},
|
||||||
() -> locationPermissionCallback.onLocationPermissionDenied(
|
() -> locationPermissionCallback.onLocationPermissionDenied(
|
||||||
activity.getString(R.string.in_app_camera_location_permission_denied)),
|
activity.getString(R.string.in_app_camera_location_permission_denied)),
|
||||||
|
|
@ -181,7 +186,8 @@ public class ContributionController {
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
private void askUserToAllowLocationAccess(Activity activity,
|
private void askUserToAllowLocationAccess(Activity activity,
|
||||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||||
|
ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
DialogUtil.showAlertDialog(activity,
|
DialogUtil.showAlertDialog(activity,
|
||||||
activity.getString(R.string.in_app_camera_location_permission_title),
|
activity.getString(R.string.in_app_camera_location_permission_title),
|
||||||
activity.getString(R.string.in_app_camera_location_access_explanation),
|
activity.getString(R.string.in_app_camera_location_access_explanation),
|
||||||
|
|
@ -190,12 +196,12 @@ public class ContributionController {
|
||||||
() -> {
|
() -> {
|
||||||
defaultKvStore.putBoolean("inAppCameraLocationPref", true);
|
defaultKvStore.putBoolean("inAppCameraLocationPref", true);
|
||||||
createDialogsAndHandleLocationPermissions(activity,
|
createDialogsAndHandleLocationPermissions(activity,
|
||||||
inAppCameraLocationPermissionLauncher);
|
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
ViewUtil.showLongToast(activity, R.string.in_app_camera_location_permission_denied);
|
ViewUtil.showLongToast(activity, R.string.in_app_camera_location_permission_denied);
|
||||||
defaultKvStore.putBoolean("inAppCameraLocationPref", false);
|
defaultKvStore.putBoolean("inAppCameraLocationPref", false);
|
||||||
initiateCameraUpload(activity);
|
initiateCameraUpload(activity, resultLauncher);
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
true);
|
true);
|
||||||
|
|
@ -204,18 +210,18 @@ public class ContributionController {
|
||||||
/**
|
/**
|
||||||
* Initiate gallery picker
|
* Initiate gallery picker
|
||||||
*/
|
*/
|
||||||
public void initiateGalleryPick(final Activity activity, final boolean allowMultipleUploads) {
|
public void initiateGalleryPick(final Activity activity, ActivityResultLauncher<Intent> resultLauncher, final boolean allowMultipleUploads) {
|
||||||
initiateGalleryUpload(activity, allowMultipleUploads);
|
initiateGalleryUpload(activity, resultLauncher, allowMultipleUploads);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate gallery picker with permission
|
* Initiate gallery picker with permission
|
||||||
*/
|
*/
|
||||||
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
|
public void initiateCustomGalleryPickWithPermission(final Activity activity, ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
setPickerConfiguration(activity, true);
|
setPickerConfiguration(activity, true);
|
||||||
|
|
||||||
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
||||||
() -> FilePicker.openCustomSelector(activity, 0),
|
() -> FilePicker.openCustomSelector(activity, resultLauncher, 0),
|
||||||
R.string.storage_permission_title,
|
R.string.storage_permission_title,
|
||||||
R.string.write_storage_permission_rationale,
|
R.string.write_storage_permission_rationale,
|
||||||
PermissionUtils.PERMISSIONS_STORAGE);
|
PermissionUtils.PERMISSIONS_STORAGE);
|
||||||
|
|
@ -225,12 +231,10 @@ public class ContributionController {
|
||||||
/**
|
/**
|
||||||
* Open chooser for gallery uploads
|
* Open chooser for gallery uploads
|
||||||
*/
|
*/
|
||||||
private void initiateGalleryUpload(final Activity activity,
|
private void initiateGalleryUpload(final Activity activity, ActivityResultLauncher<Intent> resultLauncher,
|
||||||
final boolean allowMultipleUploads) {
|
final boolean allowMultipleUploads) {
|
||||||
setPickerConfiguration(activity, allowMultipleUploads);
|
setPickerConfiguration(activity, allowMultipleUploads);
|
||||||
boolean openDocumentIntentPreferred = defaultKvStore.getBoolean(
|
FilePicker.openGallery(activity, resultLauncher, 0, isDocumentPhotoPickerPreferred());
|
||||||
"openDocumentPhotoPickerPref", true);
|
|
||||||
FilePicker.openGallery(activity, 0, openDocumentIntentPreferred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -247,22 +251,43 @@ public class ContributionController {
|
||||||
/**
|
/**
|
||||||
* Initiate camera upload by opening camera
|
* Initiate camera upload by opening camera
|
||||||
*/
|
*/
|
||||||
private void initiateCameraUpload(Activity activity) {
|
private void initiateCameraUpload(Activity activity, ActivityResultLauncher<Intent> resultLauncher) {
|
||||||
setPickerConfiguration(activity, false);
|
setPickerConfiguration(activity, false);
|
||||||
if (defaultKvStore.getBoolean("inAppCameraLocationPref", false)) {
|
if (defaultKvStore.getBoolean("inAppCameraLocationPref", false)) {
|
||||||
locationBeforeImageCapture = locationManager.getLastLocation();
|
locationBeforeImageCapture = locationManager.getLastLocation();
|
||||||
}
|
}
|
||||||
isInAppCameraUpload = true;
|
isInAppCameraUpload = true;
|
||||||
FilePicker.openCameraForImage(activity, 0);
|
FilePicker.openCameraForImage(activity, resultLauncher, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDocumentPhotoPickerPreferred(){
|
||||||
|
return defaultKvStore.getBoolean(
|
||||||
|
"openDocumentPhotoPickerPref", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPictureReturnedFromGallery(ActivityResult result, Activity activity, FilePicker.Callbacks callbacks){
|
||||||
|
|
||||||
|
if(isDocumentPhotoPickerPreferred()){
|
||||||
|
FilePicker.onPictureReturnedFromDocuments(result, activity, callbacks);
|
||||||
|
} else {
|
||||||
|
FilePicker.onPictureReturnedFromGallery(result, activity, callbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPictureReturnedFromCustomSelector(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
|
FilePicker.onPictureReturnedFromCustomSelector(result, activity, callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPictureReturnedFromCamera(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
|
FilePicker.onPictureReturnedFromCamera(result, activity, callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches callback for file picker.
|
* Attaches callback for file picker.
|
||||||
*/
|
*/
|
||||||
public void handleActivityResult(Activity activity, int requestCode, int resultCode,
|
public void handleActivityResultWithCallback(Activity activity, FilePicker.HandleActivityResult handleActivityResult) {
|
||||||
Intent data) {
|
|
||||||
FilePicker.handleActivityResult(requestCode, resultCode, data, activity,
|
handleActivityResult.onHandleActivityResult(new DefaultCallback() {
|
||||||
new DefaultCallback() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCanceled(final ImageSource source, final int type) {
|
public void onCanceled(final ImageSource source, final int type) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_
|
||||||
|
|
||||||
import android.Manifest.permission;
|
import android.Manifest.permission;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
@ -20,6 +21,7 @@ import android.widget.LinearLayout;
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
import androidx.activity.result.ActivityResultCallback;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
@ -96,6 +98,30 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
private int contributionsSize;
|
private int contributionsSize;
|
||||||
private String userName;
|
private String userName;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> customSelectorLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
|
||||||
new RequestMultiplePermissions(),
|
new RequestMultiplePermissions(),
|
||||||
new ActivityResultCallback<Map<String, Boolean>>() {
|
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
|
@ -111,7 +137,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
} else {
|
} else {
|
||||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
||||||
inAppCameraLocationPermissionLauncher);
|
inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
} else {
|
} else {
|
||||||
controller.locationPermissionCallback.onLocationPermissionDenied(
|
controller.locationPermissionCallback.onLocationPermissionDenied(
|
||||||
getActivity().getString(
|
getActivity().getString(
|
||||||
|
|
@ -322,7 +348,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
private void setListeners() {
|
private void setListeners() {
|
||||||
binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
||||||
binding.fabCamera.setOnClickListener(view -> {
|
binding.fabCamera.setOnClickListener(view -> {
|
||||||
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
|
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
animateFAB(isFabOpen);
|
animateFAB(isFabOpen);
|
||||||
});
|
});
|
||||||
binding.fabCamera.setOnLongClickListener(view -> {
|
binding.fabCamera.setOnLongClickListener(view -> {
|
||||||
|
|
@ -330,7 +356,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
binding.fabGallery.setOnClickListener(view -> {
|
binding.fabGallery.setOnClickListener(view -> {
|
||||||
controller.initiateGalleryPick(getActivity(), true);
|
controller.initiateGalleryPick(getActivity(), galleryPickLauncherForResult, true);
|
||||||
animateFAB(isFabOpen);
|
animateFAB(isFabOpen);
|
||||||
});
|
});
|
||||||
binding.fabGallery.setOnLongClickListener(view -> {
|
binding.fabGallery.setOnLongClickListener(view -> {
|
||||||
|
|
@ -343,7 +369,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
||||||
* Launch Custom Selector.
|
* Launch Custom Selector.
|
||||||
*/
|
*/
|
||||||
protected void launchCustomSelector() {
|
protected void launchCustomSelector() {
|
||||||
controller.initiateCustomGalleryPickWithPermission(getActivity());
|
controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult);
|
||||||
animateFAB(isFabOpen);
|
animateFAB(isFabOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -438,13 +438,6 @@ public class MainActivity extends BaseActivity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
Timber.d(data != null ? data.toString() : "onActivityResult data is null");
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
controller.handleActivityResult(this, requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class WikipediaInstructionsDialogFragment : DialogFragment() {
|
||||||
) = DialogAddToWikipediaInstructionsBinding
|
) = DialogAddToWikipediaInstructionsBinding
|
||||||
.inflate(inflater, container, false)
|
.inflate(inflater, container, false)
|
||||||
.apply {
|
.apply {
|
||||||
val contribution: Contribution? = arguments!!.getParcelable(ARG_CONTRIBUTION)
|
val contribution: Contribution? = requireArguments().getParcelable(ARG_CONTRIBUTION)
|
||||||
tvWikicode.setText(contribution?.media?.wikiCode)
|
tvWikicode.setText(contribution?.media?.wikiCode)
|
||||||
instructionsCancel.setOnClickListener { dismiss() }
|
instructionsCancel.setOnClickListener { dismiss() }
|
||||||
instructionsConfirm.setOnClickListener {
|
instructionsConfirm.setOnClickListener {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package fr.free.nrw.commons.customselector.helper
|
package fr.free.nrw.commons.customselector.helper
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
|
|
@ -8,9 +7,10 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.IntentSenderRequest
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.filepicker.Constants
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
@ -22,15 +22,20 @@ object FolderDeletionHelper {
|
||||||
* @param context The context used to show the confirmation dialog and manage deletion.
|
* @param context The context used to show the confirmation dialog and manage deletion.
|
||||||
* @param folder The folder to be deleted.
|
* @param folder The folder to be deleted.
|
||||||
* @param onDeletionComplete Callback invoked with `true` if the folder was
|
* @param onDeletionComplete Callback invoked with `true` if the folder was
|
||||||
|
* @param trashFolderLauncher An ActivityResultLauncher for handling the result of the trash request.
|
||||||
* successfully deleted, `false` otherwise.
|
* successfully deleted, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
fun confirmAndDeleteFolder(context: Context, folder: File, onDeletionComplete: (Boolean) -> Unit) {
|
fun confirmAndDeleteFolder(
|
||||||
|
context: Context,
|
||||||
|
folder: File,
|
||||||
|
trashFolderLauncher: ActivityResultLauncher<IntentSenderRequest>,
|
||||||
|
onDeletionComplete: (Boolean) -> Unit) {
|
||||||
val itemCount = countItemsInFolder(context, folder)
|
val itemCount = countItemsInFolder(context, folder)
|
||||||
val folderPath = folder.absolutePath
|
val folderPath = folder.absolutePath
|
||||||
|
|
||||||
//don't show this dialog on API 30+, it's handled automatically using MediaStore
|
//don't show this dialog on API 30+, it's handled automatically using MediaStore
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
val success = deleteFolderMain(context, folder)
|
val success = deleteFolderMain(context, folder, trashFolderLauncher)
|
||||||
onDeletionComplete(success)
|
onDeletionComplete(success)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -40,7 +45,7 @@ object FolderDeletionHelper {
|
||||||
.setPositiveButton(context.getString(R.string.custom_selector_delete)) { _, _ ->
|
.setPositiveButton(context.getString(R.string.custom_selector_delete)) { _, _ ->
|
||||||
|
|
||||||
//proceed with deletion if user confirms
|
//proceed with deletion if user confirms
|
||||||
val success = deleteFolderMain(context, folder)
|
val success = deleteFolderMain(context, folder, trashFolderLauncher)
|
||||||
onDeletionComplete(success)
|
onDeletionComplete(success)
|
||||||
}
|
}
|
||||||
.setNegativeButton(context.getString(R.string.custom_selector_cancel)) { dialog, _ ->
|
.setNegativeButton(context.getString(R.string.custom_selector_cancel)) { dialog, _ ->
|
||||||
|
|
@ -56,12 +61,17 @@ object FolderDeletionHelper {
|
||||||
*
|
*
|
||||||
* @param context The context used to manage storage operations.
|
* @param context The context used to manage storage operations.
|
||||||
* @param folder The folder to delete.
|
* @param folder The folder to delete.
|
||||||
|
* @param trashFolderLauncher An ActivityResultLauncher for handling the result of the trash request.
|
||||||
* @return `true` if the folder deletion was successful, `false` otherwise.
|
* @return `true` if the folder deletion was successful, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
private fun deleteFolderMain(context: Context, folder: File): Boolean {
|
private fun deleteFolderMain(
|
||||||
|
context: Context,
|
||||||
|
folder: File,
|
||||||
|
trashFolderLauncher: ActivityResultLauncher<IntentSenderRequest>): Boolean
|
||||||
|
{
|
||||||
return when {
|
return when {
|
||||||
//for API 30 and above, use MediaStore
|
//for API 30 and above, use MediaStore
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> trashFolderContents(context, folder)
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> trashFolderContents(context, folder, trashFolderLauncher)
|
||||||
|
|
||||||
//for API 29 ('requestLegacyExternalStorage' is set to true in Manifest)
|
//for API 29 ('requestLegacyExternalStorage' is set to true in Manifest)
|
||||||
// and below use file system
|
// and below use file system
|
||||||
|
|
@ -75,9 +85,14 @@ object FolderDeletionHelper {
|
||||||
*
|
*
|
||||||
* @param context The context used to access the content resolver.
|
* @param context The context used to access the content resolver.
|
||||||
* @param folder The folder whose contents are to be moved to the trash.
|
* @param folder The folder whose contents are to be moved to the trash.
|
||||||
|
* @param trashFolderLauncher An ActivityResultLauncher for handling the result of the trash request.
|
||||||
* @return `true` if the trash request was initiated successfully, `false` otherwise.
|
* @return `true` if the trash request was initiated successfully, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
private fun trashFolderContents(context: Context, folder: File): Boolean {
|
private fun trashFolderContents(
|
||||||
|
context: Context,
|
||||||
|
folder: File,
|
||||||
|
trashFolderLauncher: ActivityResultLauncher<IntentSenderRequest>): Boolean
|
||||||
|
{
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return false
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return false
|
||||||
|
|
||||||
val contentResolver = context.contentResolver
|
val contentResolver = context.contentResolver
|
||||||
|
|
@ -111,11 +126,8 @@ object FolderDeletionHelper {
|
||||||
if (urisToTrash.isNotEmpty()) {
|
if (urisToTrash.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
val trashRequest = MediaStore.createTrashRequest(contentResolver, urisToTrash, true)
|
val trashRequest = MediaStore.createTrashRequest(contentResolver, urisToTrash, true)
|
||||||
(context as? Activity)?.startIntentSenderForResult(
|
val intentSenderRequest = IntentSenderRequest.Builder(trashRequest.intentSender).build()
|
||||||
trashRequest.intentSender,
|
trashFolderLauncher.launch(intentSenderRequest)
|
||||||
Constants.RequestCodes.DELETE_FOLDER_REQUEST_CODE,
|
|
||||||
null, 0, 0, 0
|
|
||||||
)
|
|
||||||
return true
|
return true
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
Timber.tag("DeleteFolder").e(context.getString(R.string.custom_selector_error_trashing_folder_contents, e.message))
|
Timber.tag("DeleteFolder").e(context.getString(R.string.custom_selector_error_trashing_folder_contents, e.message))
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ import android.widget.Button
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -42,7 +45,6 @@ import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||||
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
||||||
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.SHOULD_REFRESH
|
|
||||||
import fr.free.nrw.commons.customselector.helper.FolderDeletionHelper
|
import fr.free.nrw.commons.customselector.helper.FolderDeletionHelper
|
||||||
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
||||||
|
|
@ -50,7 +52,6 @@ import fr.free.nrw.commons.customselector.model.Image
|
||||||
import fr.free.nrw.commons.databinding.ActivityCustomSelectorBinding
|
import fr.free.nrw.commons.databinding.ActivityCustomSelectorBinding
|
||||||
import fr.free.nrw.commons.databinding.CustomSelectorBottomLayoutBinding
|
import fr.free.nrw.commons.databinding.CustomSelectorBottomLayoutBinding
|
||||||
import fr.free.nrw.commons.databinding.CustomSelectorToolbarBinding
|
import fr.free.nrw.commons.databinding.CustomSelectorToolbarBinding
|
||||||
import fr.free.nrw.commons.filepicker.Constants
|
|
||||||
import fr.free.nrw.commons.media.ZoomableActivity
|
import fr.free.nrw.commons.media.ZoomableActivity
|
||||||
import fr.free.nrw.commons.theme.BaseActivity
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
||||||
|
|
@ -65,7 +66,6 @@ import java.io.File
|
||||||
import java.lang.Integer.max
|
import java.lang.Integer.max
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom Selector Activity.
|
* Custom Selector Activity.
|
||||||
*/
|
*/
|
||||||
|
|
@ -155,7 +155,16 @@ class CustomSelectorActivity :
|
||||||
*/
|
*/
|
||||||
private var showOverflowMenu = false
|
private var showOverflowMenu = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for confirmation of delete folder
|
||||||
|
*/
|
||||||
|
private val startForFolderDeletionResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){
|
||||||
|
result -> onDeleteFolderResultReceived(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val startForResult = registerForActivityResult(StartActivityForResult()){ result ->
|
||||||
|
onFullScreenDataReceived(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,9 +193,9 @@ class CustomSelectorActivity :
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
|
|
@ -215,7 +224,6 @@ class CustomSelectorActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(
|
override fun onRequestPermissionsResult(
|
||||||
requestCode: Int,
|
requestCode: Int,
|
||||||
permissions: Array<out String>,
|
permissions: Array<out String>,
|
||||||
|
|
@ -237,35 +245,24 @@ class CustomSelectorActivity :
|
||||||
/**
|
/**
|
||||||
* When data will be send from full screen mode, it will be passed to fragment
|
* When data will be send from full screen mode, it will be passed to fragment
|
||||||
*/
|
*/
|
||||||
override fun onActivityResult(
|
private fun onFullScreenDataReceived(result: ActivityResult){
|
||||||
requestCode: Int,
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
resultCode: Int,
|
|
||||||
data: Intent?,
|
|
||||||
) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
if (requestCode == Constants.RequestCodes.RECEIVE_DATA_FROM_FULL_SCREEN_MODE &&
|
|
||||||
resultCode == Activity.RESULT_OK
|
|
||||||
) {
|
|
||||||
val selectedImages: ArrayList<Image> =
|
val selectedImages: ArrayList<Image> =
|
||||||
data!!
|
result.data!!
|
||||||
.getParcelableArrayListExtra(CustomSelectorConstants.NEW_SELECTED_IMAGES)!!
|
.getParcelableArrayListExtra(CustomSelectorConstants.NEW_SELECTED_IMAGES)!!
|
||||||
val shouldRefresh = data.getBooleanExtra(SHOULD_REFRESH, false)
|
viewModel?.selectedImages?.value = selectedImages
|
||||||
imageFragment?.passSelectedImages(selectedImages, shouldRefresh)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode == Constants.RequestCodes.DELETE_FOLDER_REQUEST_CODE &&
|
private fun onDeleteFolderResultReceived(result: ActivityResult){
|
||||||
resultCode == Activity.RESULT_OK) {
|
if (result.resultCode == Activity.RESULT_OK){
|
||||||
|
|
||||||
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
||||||
navigateToCustomSelector()
|
navigateToCustomSelector()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show Custom Selector Welcome Dialog.
|
* Show Custom Selector Welcome Dialog.
|
||||||
*/
|
*/
|
||||||
|
|
@ -438,7 +435,7 @@ class CustomSelectorActivity :
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the toolbar, back listener, done listener, overflow menu listener.
|
* Set up the toolbar, back listener, done listener.
|
||||||
*/
|
*/
|
||||||
private fun setUpToolbar() {
|
private fun setUpToolbar() {
|
||||||
val back: ImageButton = findViewById(R.id.back)
|
val back: ImageButton = findViewById(R.id.back)
|
||||||
|
|
@ -489,9 +486,9 @@ class CustomSelectorActivity :
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderDeletionHelper.confirmAndDeleteFolder(this, folder) { success ->
|
FolderDeletionHelper.confirmAndDeleteFolder(this, folder, startForFolderDeletionResult) { success ->
|
||||||
if (success) {
|
if (success) {
|
||||||
// For API 30+, navigation is handled in 'onActivityResult'
|
//for API 30+, navigation is handled in 'onDeleteFolderResultReceived'
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||||
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
||||||
navigateToCustomSelector()
|
navigateToCustomSelector()
|
||||||
|
|
@ -542,9 +539,8 @@ class CustomSelectorActivity :
|
||||||
override fun onFolderClick(
|
override fun onFolderClick(
|
||||||
folderId: Long,
|
folderId: Long,
|
||||||
folderName: String,
|
folderName: String,
|
||||||
lastItemId: Long
|
lastItemId: Long,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.add(R.id.fragment_container, ImageFragment.newInstance(folderId, lastItemId))
|
.add(R.id.fragment_container, ImageFragment.newInstance(folderId, lastItemId))
|
||||||
|
|
@ -563,7 +559,6 @@ class CustomSelectorActivity :
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* override Selected Images Change, update view model selected images and change UI.
|
* override Selected Images Change, update view model selected images and change UI.
|
||||||
*/
|
*/
|
||||||
|
|
@ -629,7 +624,7 @@ class CustomSelectorActivity :
|
||||||
selectedImages,
|
selectedImages,
|
||||||
)
|
)
|
||||||
intent.putExtra(CustomSelectorConstants.BUCKET_ID, bucketId)
|
intent.putExtra(CustomSelectorConstants.BUCKET_ID, bucketId)
|
||||||
startActivityForResult(intent, Constants.RequestCodes.RECEIVE_DATA_FROM_FULL_SCREEN_MODE)
|
startForResult.launch(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -738,15 +733,13 @@ fun partialStorageAccessIndicator(
|
||||||
OutlinedCard(
|
OutlinedCard(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
colors =
|
colors =
|
||||||
CardDefaults.cardColors(
|
CardDefaults.cardColors(
|
||||||
containerColor = colorResource(R.color.primarySuperLightColor),
|
containerColor = colorResource(R.color.primarySuperLightColor),
|
||||||
),
|
),
|
||||||
border = BorderStroke(0.5.dp, color = colorResource(R.color.primaryColor)),
|
border = BorderStroke(0.5.dp, color = colorResource(R.color.primaryColor)),
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(8.dp),
|
||||||
) {
|
) {
|
||||||
Row(modifier = Modifier
|
Row(modifier = Modifier.padding(16.dp).fillMaxWidth()) {
|
||||||
.padding(16.dp)
|
|
||||||
.fillMaxWidth()) {
|
|
||||||
Text(
|
Text(
|
||||||
text = "You've given access to a select number of photos",
|
text = "You've given access to a select number of photos",
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
|
|
@ -755,9 +748,9 @@ fun partialStorageAccessIndicator(
|
||||||
onClick = onManage,
|
onClick = onManage,
|
||||||
modifier = Modifier.align(Alignment.Bottom),
|
modifier = Modifier.align(Alignment.Bottom),
|
||||||
colors =
|
colors =
|
||||||
ButtonDefaults.buttonColors(
|
ButtonDefaults.buttonColors(
|
||||||
containerColor = colorResource(R.color.primaryColor),
|
containerColor = colorResource(R.color.primaryColor),
|
||||||
),
|
),
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(8.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -779,9 +772,9 @@ fun partialStorageAccessIndicatorPreview() {
|
||||||
isVisible = true,
|
isVisible = true,
|
||||||
onManage = {},
|
onManage = {},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -279,11 +279,17 @@ class ImageFragment :
|
||||||
filteredImages = ImageHelper.filterImages(images, bucketId)
|
filteredImages = ImageHelper.filterImages(images, bucketId)
|
||||||
allImages = ArrayList(filteredImages)
|
allImages = ArrayList(filteredImages)
|
||||||
imageAdapter.init(filteredImages, allImages, TreeMap(), uploadingContributions)
|
imageAdapter.init(filteredImages, allImages, TreeMap(), uploadingContributions)
|
||||||
|
viewModel?.selectedImages?.value?.let { selectedImages ->
|
||||||
|
imageAdapter.setSelectedImages(selectedImages)
|
||||||
|
}
|
||||||
|
imageAdapter.notifyDataSetChanged()
|
||||||
selectorRV?.let {
|
selectorRV?.let {
|
||||||
it.visibility = View.VISIBLE
|
it.visibility = View.VISIBLE
|
||||||
lastItemId?.let { pos ->
|
if (switch?.isChecked == false) {
|
||||||
(it.layoutManager as GridLayoutManager)
|
lastItemId?.let { pos ->
|
||||||
.scrollToPosition(ImageHelper.getIndexFromId(filteredImages, pos))
|
(it.layoutManager as GridLayoutManager)
|
||||||
|
.scrollToPosition(ImageHelper.getIndexFromId(filteredImages, pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -382,14 +388,6 @@ class ImageFragment :
|
||||||
selectedImages: ArrayList<Image>,
|
selectedImages: ArrayList<Image>,
|
||||||
shouldRefresh: Boolean,
|
shouldRefresh: Boolean,
|
||||||
) {
|
) {
|
||||||
imageAdapter.setSelectedImages(selectedImages)
|
|
||||||
|
|
||||||
val uploadingContributions = getUploadingContributions()
|
|
||||||
|
|
||||||
if (!showAlreadyActionedImages && shouldRefresh) {
|
|
||||||
imageAdapter.init(filteredImages, allImages, TreeMap(), uploadingContributions)
|
|
||||||
imageAdapter.setSelectedImages(selectedImages)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import fr.free.nrw.commons.utils.CustomSelectorUtils
|
||||||
import fr.free.nrw.commons.utils.CustomSelectorUtils.Companion.checkWhetherFileExistsOnCommonsUsingSHA1
|
import fr.free.nrw.commons.utils.CustomSelectorUtils.Companion.checkWhetherFileExistsOnCommonsUsingSHA1
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.speech.RecognizerIntent
|
import android.speech.RecognizerIntent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.free.nrw.commons.CommonsApplication
|
import fr.free.nrw.commons.CommonsApplication
|
||||||
|
|
@ -70,10 +72,14 @@ class DescriptionEditActivity :
|
||||||
|
|
||||||
private lateinit var binding: ActivityDescriptionEditBinding
|
private lateinit var binding: ActivityDescriptionEditBinding
|
||||||
|
|
||||||
private val requestCodeForVoiceInput = 1213
|
|
||||||
|
|
||||||
private var descriptionAndCaptions: ArrayList<UploadMediaDetail>? = null
|
private var descriptionAndCaptions: ArrayList<UploadMediaDetail>? = null
|
||||||
|
|
||||||
|
private val voiceInputResultLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result: ActivityResult ->
|
||||||
|
onVoiceInput(result)
|
||||||
|
}
|
||||||
|
|
||||||
@Inject lateinit var descriptionEditHelper: DescriptionEditHelper
|
@Inject lateinit var descriptionEditHelper: DescriptionEditHelper
|
||||||
|
|
||||||
@Inject lateinit var sessionManager: SessionManager
|
@Inject lateinit var sessionManager: SessionManager
|
||||||
|
|
@ -115,6 +121,7 @@ class DescriptionEditActivity :
|
||||||
savedLanguageValue,
|
savedLanguageValue,
|
||||||
descriptionAndCaptions,
|
descriptionAndCaptions,
|
||||||
recentLanguagesDao,
|
recentLanguagesDao,
|
||||||
|
voiceInputResultLauncher
|
||||||
)
|
)
|
||||||
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
||||||
showInfoAlert(
|
showInfoAlert(
|
||||||
|
|
@ -149,6 +156,15 @@ class DescriptionEditActivity :
|
||||||
|
|
||||||
override fun onPrimaryCaptionTextChange(isNotEmpty: Boolean) {}
|
override fun onPrimaryCaptionTextChange(isNotEmpty: Boolean) {}
|
||||||
|
|
||||||
|
private fun onVoiceInput(result: ActivityResult) {
|
||||||
|
if (result.resultCode == RESULT_OK && result.data != null) {
|
||||||
|
val resultData = result.data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
|
||||||
|
uploadMediaDetailAdapter.handleSpeechResult(resultData!![0])
|
||||||
|
} else {
|
||||||
|
Timber.e("Error %s", result.resultCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds new language item to RecyclerView
|
* Adds new language item to RecyclerView
|
||||||
*/
|
*/
|
||||||
|
|
@ -221,7 +237,7 @@ class DescriptionEditActivity :
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
descriptionEditHelper
|
descriptionEditHelper
|
||||||
?.addDescription(
|
.addDescription(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
media,
|
media,
|
||||||
updatedWikiText,
|
updatedWikiText,
|
||||||
|
|
@ -234,7 +250,7 @@ class DescriptionEditActivity :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: InvalidLoginTokenException) {
|
} catch (e: InvalidLoginTokenException) {
|
||||||
val username: String? = sessionManager?.userName
|
val username: String? = sessionManager.userName
|
||||||
val logoutListener =
|
val logoutListener =
|
||||||
CommonsApplication.BaseLogoutListener(
|
CommonsApplication.BaseLogoutListener(
|
||||||
this,
|
this,
|
||||||
|
|
@ -242,7 +258,7 @@ class DescriptionEditActivity :
|
||||||
username,
|
username,
|
||||||
)
|
)
|
||||||
|
|
||||||
val commonsApplication = CommonsApplication.getInstance()
|
val commonsApplication = CommonsApplication.instance
|
||||||
if (commonsApplication != null) {
|
if (commonsApplication != null) {
|
||||||
commonsApplication.clearApplicationData(this, logoutListener)
|
commonsApplication.clearApplicationData(this, logoutListener)
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +268,7 @@ class DescriptionEditActivity :
|
||||||
for (mediaDetail in uploadMediaDetails) {
|
for (mediaDetail in uploadMediaDetails) {
|
||||||
try {
|
try {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
descriptionEditHelper!!
|
descriptionEditHelper
|
||||||
.addCaption(
|
.addCaption(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
media,
|
media,
|
||||||
|
|
@ -275,7 +291,7 @@ class DescriptionEditActivity :
|
||||||
username,
|
username,
|
||||||
)
|
)
|
||||||
|
|
||||||
val commonsApplication = CommonsApplication.getInstance()
|
val commonsApplication = CommonsApplication.instance
|
||||||
if (commonsApplication != null) {
|
if (commonsApplication != null) {
|
||||||
commonsApplication.clearApplicationData(this, logoutListener)
|
commonsApplication.clearApplicationData(this, logoutListener)
|
||||||
}
|
}
|
||||||
|
|
@ -292,22 +308,6 @@ class DescriptionEditActivity :
|
||||||
progressDialog!!.show()
|
progressDialog!!.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(
|
|
||||||
requestCode: Int,
|
|
||||||
resultCode: Int,
|
|
||||||
data: Intent?,
|
|
||||||
) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
if (requestCode == requestCodeForVoiceInput) {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
val result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
|
|
||||||
uploadMediaDetailAdapter.handleSpeechResult(result!![0])
|
|
||||||
} else {
|
|
||||||
Timber.e("Error %s", resultCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ class TransformImageImpl : TransformImage {
|
||||||
} catch (e: LLJTranException) {
|
} catch (e: LLJTranException) {
|
||||||
Timber.tag("Error").d(e)
|
Timber.tag("Error").d(e)
|
||||||
return null
|
return null
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotated) {
|
if (rotated) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import fr.free.nrw.commons.theme.BaseActivity;
|
||||||
import fr.free.nrw.commons.utils.ActivityUtils;
|
import fr.free.nrw.commons.utils.ActivityUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
|
@ -112,13 +113,13 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
|
||||||
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
|
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
|
||||||
mapRootFragment = new ExploreMapRootFragment(mapArguments);
|
mapRootFragment = new ExploreMapRootFragment(mapArguments);
|
||||||
fragmentList.add(featuredRootFragment);
|
fragmentList.add(featuredRootFragment);
|
||||||
titleList.add(getString(R.string.explore_tab_title_featured).toUpperCase());
|
titleList.add(getString(R.string.explore_tab_title_featured).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
fragmentList.add(mobileRootFragment);
|
fragmentList.add(mobileRootFragment);
|
||||||
titleList.add(getString(R.string.explore_tab_title_mobile).toUpperCase());
|
titleList.add(getString(R.string.explore_tab_title_mobile).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
fragmentList.add(mapRootFragment);
|
fragmentList.add(mapRootFragment);
|
||||||
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase());
|
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
((MainActivity)getActivity()).showTabs();
|
((MainActivity)getActivity()).showTabs();
|
||||||
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -95,11 +96,11 @@ public class SearchActivity extends BaseActivity
|
||||||
searchDepictionsFragment = new SearchDepictionsFragment();
|
searchDepictionsFragment = new SearchDepictionsFragment();
|
||||||
searchCategoryFragment= new SearchCategoryFragment();
|
searchCategoryFragment= new SearchCategoryFragment();
|
||||||
fragmentList.add(searchMediaFragment);
|
fragmentList.add(searchMediaFragment);
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_media).toUpperCase());
|
titleList.add(getResources().getString(R.string.search_tab_title_media).toUpperCase(Locale.ROOT));
|
||||||
fragmentList.add(searchCategoryFragment);
|
fragmentList.add(searchCategoryFragment);
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_categories).toUpperCase());
|
titleList.add(getResources().getString(R.string.search_tab_title_categories).toUpperCase(Locale.ROOT));
|
||||||
fragmentList.add(searchDepictionsFragment);
|
fragmentList.add(searchDepictionsFragment);
|
||||||
titleList.add(getResources().getString(R.string.search_tab_title_depictions).toUpperCase());
|
titleList.add(getResources().getString(R.string.search_tab_title_depictions).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
viewPagerAdapter.setTabData(fragmentList, titleList);
|
||||||
viewPagerAdapter.notifyDataSetChanged();
|
viewPagerAdapter.notifyDataSetChanged();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@ class CategoriesMediaFragment : PageableMediaFragment() {
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
onQueryUpdated("$CATEGORY_PREFIX${requireArguments().getString("categoryName")!!}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,6 @@ class ParentCategoriesFragment : PageableCategoryFragment() {
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
onQueryUpdated("$CATEGORY_PREFIX${requireArguments().getString("categoryName")!!}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ class SubCategoriesFragment : PageableCategoryFragment() {
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated("$CATEGORY_PREFIX${arguments!!.getString("categoryName")!!}")
|
onQueryUpdated("$CATEGORY_PREFIX${requireArguments().getString("categoryName")!!}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ class ChildDepictionsFragment : PageableDepictionsFragment() {
|
||||||
override val injectedPresenter
|
override val injectedPresenter
|
||||||
get() = presenter
|
get() = presenter
|
||||||
|
|
||||||
override fun getEmptyText(query: String) = getString(R.string.no_child_classes, arguments!!.getString("wikidataItemName")!!)
|
override fun getEmptyText(query: String) = getString(R.string.no_child_classes, requireArguments().getString("wikidataItemName")!!)
|
||||||
|
|
||||||
override fun onViewCreated(
|
override fun onViewCreated(
|
||||||
view: View,
|
view: View,
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,6 @@ class DepictedImagesFragment : PageableMediaFragment() {
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ class ParentDepictionsFragment : PageableDepictionsFragment() {
|
||||||
override val injectedPresenter
|
override val injectedPresenter
|
||||||
get() = presenter
|
get() = presenter
|
||||||
|
|
||||||
override fun getEmptyText(query: String) = getString(R.string.no_parent_classes, arguments!!.getString("wikidataItemName")!!)
|
override fun getEmptyText(query: String) = getString(R.string.no_parent_classes, requireArguments().getString("wikidataItemName")!!)
|
||||||
|
|
||||||
override fun onViewCreated(
|
override fun onViewCreated(
|
||||||
view: View,
|
view: View,
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ class MediaConverter
|
||||||
metadata.licenseShortName(),
|
metadata.licenseShortName(),
|
||||||
metadata.prefixedLicenseUrl,
|
metadata.prefixedLicenseUrl,
|
||||||
getAuthor(metadata),
|
getAuthor(metadata),
|
||||||
imageInfo.user,
|
getAuthor(metadata),
|
||||||
MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories),
|
MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories),
|
||||||
metadata.latLng,
|
metadata.latLng,
|
||||||
entity.labels().mapValues { it.value.value() },
|
entity.labels().mapValues { it.value.value() },
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.explore.recentsearches;
|
package fr.free.nrw.commons.explore.recentsearches;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -178,6 +179,7 @@ public class RecentSearchesDao {
|
||||||
* @return RecentSearch object
|
* @return RecentSearch object
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@SuppressLint("Range")
|
||||||
RecentSearch fromCursor(Cursor cursor) {
|
RecentSearch fromCursor(Cursor cursor) {
|
||||||
// Hardcoding column positions!
|
// Hardcoding column positions!
|
||||||
return new RecentSearch(
|
return new RecentSearch(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import fr.free.nrw.commons.databinding.FragmentSearchHistoryBinding;
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||||
import fr.free.nrw.commons.explore.SearchActivity;
|
import fr.free.nrw.commons.explore.SearchActivity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -90,7 +91,7 @@ public class RecentSearchesFragment extends CommonsDaggerSupportFragment {
|
||||||
private void showDeleteAlertDialog(@NonNull final Context context, final int position) {
|
private void showDeleteAlertDialog(@NonNull final Context context, final int position) {
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
.setMessage(R.string.delete_search_dialog)
|
.setMessage(R.string.delete_search_dialog)
|
||||||
.setPositiveButton(getString(R.string.delete).toUpperCase(),
|
.setPositiveButton(getString(R.string.delete).toUpperCase(Locale.ROOT),
|
||||||
((dialog, which) -> setDeletePositiveButton(context, dialog, position)))
|
((dialog, which) -> setDeletePositiveButton(context, dialog, position)))
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.create()
|
.create()
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,12 @@ public interface Constants {
|
||||||
String DEFAULT_FOLDER_NAME = "CommonsContributions";
|
String DEFAULT_FOLDER_NAME = "CommonsContributions";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the request codes utilised by the FilePicker
|
* Provides the request codes for permission handling
|
||||||
*/
|
*/
|
||||||
interface RequestCodes {
|
interface RequestCodes {
|
||||||
int LOCATION = 1;
|
int LOCATION = 1;
|
||||||
int STORAGE = 2;
|
int STORAGE = 2;
|
||||||
int FILE_PICKER_IMAGE_IDENTIFICATOR = 0b1101101100; //876
|
|
||||||
int SOURCE_CHOOSER = 1 << 15;
|
|
||||||
|
|
||||||
int PICK_PICTURE_FROM_CUSTOM_SELECTOR = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 10);
|
|
||||||
int PICK_PICTURE_FROM_DOCUMENTS = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 11);
|
|
||||||
int PICK_PICTURE_FROM_GALLERY = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 12);
|
|
||||||
int TAKE_PICTURE = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 13);
|
|
||||||
int CAPTURE_VIDEO = FILE_PICKER_IMAGE_IDENTIFICATOR + (1 << 14);
|
|
||||||
|
|
||||||
int RECEIVE_DATA_FROM_FULL_SCREEN_MODE = 1 << 9;
|
|
||||||
|
|
||||||
int DELETE_FOLDER_REQUEST_CODE = 1 << 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import android.content.pm.ResolveInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
@ -107,25 +109,25 @@ public class FilePicker implements Constants {
|
||||||
*
|
*
|
||||||
* @param type Custom type of your choice, which will be returned with the images
|
* @param type Custom type of your choice, which will be returned with the images
|
||||||
*/
|
*/
|
||||||
public static void openGallery(Activity activity, int type, boolean openDocumentIntentPreferred) {
|
public static void openGallery(Activity activity, ActivityResultLauncher<Intent> resultLauncher, int type, boolean openDocumentIntentPreferred) {
|
||||||
Intent intent = createGalleryIntent(activity, type, openDocumentIntentPreferred);
|
Intent intent = createGalleryIntent(activity, type, openDocumentIntentPreferred);
|
||||||
activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_GALLERY);
|
resultLauncher.launch(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens Custom Selector
|
* Opens Custom Selector
|
||||||
*/
|
*/
|
||||||
public static void openCustomSelector(Activity activity, int type) {
|
public static void openCustomSelector(Activity activity, ActivityResultLauncher<Intent> resultLauncher, int type) {
|
||||||
Intent intent = createCustomSelectorIntent(activity, type);
|
Intent intent = createCustomSelectorIntent(activity, type);
|
||||||
activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR);
|
resultLauncher.launch(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the camera app to pick image clicked by user
|
* Opens the camera app to pick image clicked by user
|
||||||
*/
|
*/
|
||||||
public static void openCameraForImage(Activity activity, int type) {
|
public static void openCameraForImage(Activity activity, ActivityResultLauncher<Intent> resultLauncher, int type) {
|
||||||
Intent intent = createCameraForImageIntent(activity, type);
|
Intent intent = createCameraForImageIntent(activity, type);
|
||||||
activity.startActivityForResult(intent, RequestCodes.TAKE_PICTURE);
|
resultLauncher.launch(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -148,47 +150,6 @@ public class FilePicker implements Constants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Any activity can use this method to attach their callback to the file picker
|
|
||||||
*/
|
|
||||||
public static void handleActivityResult(int requestCode, int resultCode, Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
|
||||||
boolean isHandledPickedFile = (requestCode & RequestCodes.FILE_PICKER_IMAGE_IDENTIFICATOR) > 0;
|
|
||||||
if (isHandledPickedFile) {
|
|
||||||
requestCode &= ~RequestCodes.SOURCE_CHOOSER;
|
|
||||||
if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY ||
|
|
||||||
requestCode == RequestCodes.TAKE_PICTURE ||
|
|
||||||
requestCode == RequestCodes.CAPTURE_VIDEO ||
|
|
||||||
requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS ||
|
|
||||||
requestCode == RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
if (requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS && !isPhoto(data)) {
|
|
||||||
onPictureReturnedFromDocuments(data, activity, callbacks);
|
|
||||||
} else if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY && !isPhoto(data)) {
|
|
||||||
onPictureReturnedFromGallery(data, activity, callbacks);
|
|
||||||
} else if (requestCode == RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR) {
|
|
||||||
onPictureReturnedFromCustomSelector(data, activity, callbacks);
|
|
||||||
} else if (requestCode == RequestCodes.TAKE_PICTURE) {
|
|
||||||
onPictureReturnedFromCamera(activity, callbacks);
|
|
||||||
} else if (requestCode == RequestCodes.CAPTURE_VIDEO) {
|
|
||||||
onVideoReturnedFromCamera(activity, callbacks);
|
|
||||||
} else if (isPhoto(data)) {
|
|
||||||
onPictureReturnedFromCamera(activity, callbacks);
|
|
||||||
} else {
|
|
||||||
onPictureReturnedFromDocuments(data, activity, callbacks);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (requestCode == RequestCodes.PICK_PICTURE_FROM_DOCUMENTS) {
|
|
||||||
callbacks.onCanceled(FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
|
||||||
} else if (requestCode == RequestCodes.PICK_PICTURE_FROM_GALLERY) {
|
|
||||||
callbacks.onCanceled(FilePicker.ImageSource.GALLERY, restoreType(activity));
|
|
||||||
} else {
|
|
||||||
callbacks.onCanceled(FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<UploadableFile> handleExternalImagesPicked(Intent data, Activity activity) {
|
public static List<UploadableFile> handleExternalImagesPicked(Intent data, Activity activity) {
|
||||||
try {
|
try {
|
||||||
return getFilesFromGalleryPictures(data, activity);
|
return getFilesFromGalleryPictures(data, activity);
|
||||||
|
|
@ -241,18 +202,22 @@ public class FilePicker implements Constants {
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onPictureReturnedFromDocuments(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
public static void onPictureReturnedFromDocuments(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
try {
|
if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){
|
||||||
Uri photoPath = data.getData();
|
try {
|
||||||
UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath);
|
Uri photoPath = result.getData().getData();
|
||||||
callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath);
|
||||||
|
callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||||
|
|
||||||
if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) {
|
if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) {
|
||||||
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} else {
|
||||||
e.printStackTrace();
|
callbacks.onCanceled(FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,14 +225,18 @@ public class FilePicker implements Constants {
|
||||||
* onPictureReturnedFromCustomSelector.
|
* onPictureReturnedFromCustomSelector.
|
||||||
* Retrieve and forward the images to upload wizard through callback.
|
* Retrieve and forward the images to upload wizard through callback.
|
||||||
*/
|
*/
|
||||||
private static void onPictureReturnedFromCustomSelector(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
public static void onPictureReturnedFromCustomSelector(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
try {
|
if(result.getResultCode() == Activity.RESULT_OK){
|
||||||
List<UploadableFile> files = getFilesFromCustomSelector(data, activity);
|
try {
|
||||||
callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
List<UploadableFile> files = getFilesFromCustomSelector(result.getData(), activity);
|
||||||
} catch (Exception e) {
|
callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||||
e.printStackTrace();
|
} catch (Exception e) {
|
||||||
callbacks.onImagePickerError(e, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
e.printStackTrace();
|
||||||
}
|
callbacks.onImagePickerError(e, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callbacks.onCanceled(ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -290,13 +259,17 @@ public class FilePicker implements Constants {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onPictureReturnedFromGallery(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
public static void onPictureReturnedFromGallery(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
try {
|
if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){
|
||||||
List<UploadableFile> files = getFilesFromGalleryPictures(data, activity);
|
try {
|
||||||
callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
List<UploadableFile> files = getFilesFromGalleryPictures(result.getData(), activity);
|
||||||
} catch (Exception e) {
|
callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||||
e.printStackTrace();
|
} catch (Exception e) {
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
e.printStackTrace();
|
||||||
|
callbacks.onImagePickerError(e, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
callbacks.onCanceled(FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,69 +295,40 @@ public class FilePicker implements Constants {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void onPictureReturnedFromCamera(Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
public static void onPictureReturnedFromCamera(ActivityResult activityResult, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||||
try {
|
if(activityResult.getResultCode() == Activity.RESULT_OK){
|
||||||
String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null);
|
try {
|
||||||
if (!TextUtils.isEmpty(lastImageUri)) {
|
String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null);
|
||||||
revokeWritePermission(activity, Uri.parse(lastImageUri));
|
if (!TextUtils.isEmpty(lastImageUri)) {
|
||||||
}
|
revokeWritePermission(activity, Uri.parse(lastImageUri));
|
||||||
|
|
||||||
UploadableFile photoFile = FilePicker.takenCameraPicture(activity);
|
|
||||||
List<UploadableFile> files = new ArrayList<>();
|
|
||||||
files.add(photoFile);
|
|
||||||
|
|
||||||
if (photoFile == null) {
|
|
||||||
Exception e = new IllegalStateException("Unable to get the picture returned from camera");
|
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
|
||||||
} else {
|
|
||||||
if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) {
|
|
||||||
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
UploadableFile photoFile = FilePicker.takenCameraPicture(activity);
|
||||||
}
|
List<UploadableFile> files = new ArrayList<>();
|
||||||
|
files.add(photoFile);
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
if (photoFile == null) {
|
||||||
|
Exception e = new IllegalStateException("Unable to get the picture returned from camera");
|
||||||
|
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||||
|
} else {
|
||||||
|
if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) {
|
||||||
|
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
.edit()
|
.edit()
|
||||||
.remove(KEY_LAST_CAMERA_PHOTO)
|
.remove(KEY_LAST_CAMERA_PHOTO)
|
||||||
.remove(KEY_PHOTO_URI)
|
.remove(KEY_PHOTO_URI)
|
||||||
.apply();
|
.apply();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void onVideoReturnedFromCamera(Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
|
||||||
try {
|
|
||||||
String lastVideoUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_VIDEO_URI, null);
|
|
||||||
if (!TextUtils.isEmpty(lastVideoUri)) {
|
|
||||||
revokeWritePermission(activity, Uri.parse(lastVideoUri));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
UploadableFile photoFile = FilePicker.takenCameraVideo(activity);
|
callbacks.onCanceled(FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||||
List<UploadableFile> files = new ArrayList<>();
|
|
||||||
files.add(photoFile);
|
|
||||||
|
|
||||||
if (photoFile == null) {
|
|
||||||
Exception e = new IllegalStateException("Unable to get the video returned from camera");
|
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity));
|
|
||||||
} else {
|
|
||||||
if (configuration(activity).shouldCopyTakenPhotosToPublicGalleryAppFolder()) {
|
|
||||||
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
callbacks.onImagesPicked(files, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity));
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
|
||||||
.edit()
|
|
||||||
.remove(KEY_LAST_CAMERA_VIDEO)
|
|
||||||
.remove(KEY_VIDEO_URI)
|
|
||||||
.apply();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_VIDEO, restoreType(activity));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,4 +348,8 @@ public class FilePicker implements Constants {
|
||||||
|
|
||||||
void onCanceled(FilePicker.ImageSource source, int type);
|
void onCanceled(FilePicker.ImageSource source, int type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface HandleActivityResult{
|
||||||
|
void onHandleActivityResult(FilePicker.Callbacks callbacks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
package fr.free.nrw.commons.media;
|
package fr.free.nrw.commons.media;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_CANCELED;
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_NEEDING_CATEGORIES;
|
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_NEEDING_CATEGORIES;
|
||||||
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_UNCATEGORISED;
|
import static fr.free.nrw.commons.category.CategoryClientKt.CATEGORY_UNCATEGORISED;
|
||||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION;
|
import static fr.free.nrw.commons.description.EditDescriptionConstants.LIST_OF_DESCRIPTION_AND_CAPTION;
|
||||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.UPDATED_WIKITEXT;
|
|
||||||
import static fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT;
|
import static fr.free.nrw.commons.description.EditDescriptionConstants.WIKITEXT;
|
||||||
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION;
|
import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION;
|
||||||
import static fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources;
|
import static fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources;
|
||||||
|
|
@ -112,8 +109,6 @@ import timber.log.Timber;
|
||||||
public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
CategoryEditHelper.Callback {
|
CategoryEditHelper.Callback {
|
||||||
|
|
||||||
private static final int REQUEST_CODE = 1001;
|
|
||||||
private static final int REQUEST_CODE_EDIT_DESCRIPTION = 1002;
|
|
||||||
private static final String IMAGE_BACKGROUND_COLOR = "image_background_color";
|
private static final String IMAGE_BACKGROUND_COLOR = "image_background_color";
|
||||||
static final int DEFAULT_IMAGE_BACKGROUND_COLOR = 0;
|
static final int DEFAULT_IMAGE_BACKGROUND_COLOR = 0;
|
||||||
|
|
||||||
|
|
@ -277,6 +272,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
|
|
||||||
if (!sessionManager.isUserLoggedIn()) {
|
if (!sessionManager.isUserLoggedIn()) {
|
||||||
binding.categoryEditButton.setVisibility(GONE);
|
binding.categoryEditButton.setVisibility(GONE);
|
||||||
|
binding.descriptionEdit.setVisibility(GONE);
|
||||||
|
binding.depictionsEditButton.setVisibility(GONE);
|
||||||
|
} else {
|
||||||
|
binding.categoryEditButton.setVisibility(VISIBLE);
|
||||||
|
binding.descriptionEdit.setVisibility(VISIBLE);
|
||||||
|
binding.depictionsEditButton.setVisibility(VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(applicationKvStore.getBoolean("login_skipped")){
|
if(applicationKvStore.getBoolean("login_skipped")){
|
||||||
|
|
@ -405,7 +406,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
binding.progressBarEdit.setVisibility(GONE);
|
binding.progressBarEdit.setVisibility(GONE);
|
||||||
binding.descriptionEdit.setVisibility(VISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -605,8 +605,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
// Check if the presented category is about need of category
|
// Check if the presented category is about need of category
|
||||||
if (categoriesPresent) {
|
if (categoriesPresent) {
|
||||||
for (String category : media.getCategories()) {
|
for (String category : media.getCategories()) {
|
||||||
if (category.toLowerCase().contains(CATEGORY_NEEDING_CATEGORIES) ||
|
if (category.toLowerCase(Locale.ROOT).contains(CATEGORY_NEEDING_CATEGORIES) ||
|
||||||
category.toLowerCase().contains(CATEGORY_UNCATEGORISED)) {
|
category.toLowerCase(Locale.ROOT).contains(CATEGORY_UNCATEGORISED)) {
|
||||||
categoriesPresent = false;
|
categoriesPresent = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -683,7 +683,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
// Stick in a filler element.
|
// Stick in a filler element.
|
||||||
allCategories.add(getString(R.string.detail_panel_cats_none));
|
allCategories.add(getString(R.string.detail_panel_cats_none));
|
||||||
}
|
}
|
||||||
binding.categoryEditButton.setVisibility(VISIBLE);
|
if(sessionManager.isUserLoggedIn()) {
|
||||||
|
binding.categoryEditButton.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
rebuildCatList(allCategories);
|
rebuildCatList(allCategories);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1065,81 +1067,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||||
return captionList;
|
return captionList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the result from another activity and act accordingly.
|
|
||||||
* @param requestCode
|
|
||||||
* @param resultCode
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(final int requestCode, final int resultCode,
|
|
||||||
@Nullable final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
|
|
||||||
if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_OK) {
|
|
||||||
final String updatedWikiText = data.getStringExtra(UPDATED_WIKITEXT);
|
|
||||||
|
|
||||||
try {
|
|
||||||
compositeDisposable.add(descriptionEditHelper.addDescription(getContext(), media,
|
|
||||||
updatedWikiText)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(s -> {
|
|
||||||
Timber.d("Descriptions are added.");
|
|
||||||
}));
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
|
|
||||||
final String username = sessionManager.getUserName();
|
|
||||||
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
|
|
||||||
getActivity(),
|
|
||||||
requireActivity().getString(R.string.invalid_login_message),
|
|
||||||
username
|
|
||||||
);
|
|
||||||
|
|
||||||
CommonsApplication.getInstance().clearApplicationData(
|
|
||||||
requireActivity(), logoutListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final ArrayList<UploadMediaDetail> uploadMediaDetails
|
|
||||||
= data.getParcelableArrayListExtra(LIST_OF_DESCRIPTION_AND_CAPTION);
|
|
||||||
|
|
||||||
LinkedHashMap<String, String> updatedCaptions = new LinkedHashMap<>();
|
|
||||||
for (UploadMediaDetail mediaDetail:
|
|
||||||
uploadMediaDetails) {
|
|
||||||
try {
|
|
||||||
compositeDisposable.add(descriptionEditHelper.addCaption(getContext(), media,
|
|
||||||
mediaDetail.getLanguageCode(), mediaDetail.getCaptionText())
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(s -> {
|
|
||||||
updateCaptions(mediaDetail, updatedCaptions);
|
|
||||||
Timber.d("Caption is added.");
|
|
||||||
}));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e.getLocalizedMessage().equals(CsrfTokenClient.ANONYMOUS_TOKEN_MESSAGE)) {
|
|
||||||
final String username = sessionManager.getUserName();
|
|
||||||
final CommonsApplication.BaseLogoutListener logoutListener = new CommonsApplication.BaseLogoutListener(
|
|
||||||
getActivity(),
|
|
||||||
requireActivity().getString(R.string.invalid_login_message),
|
|
||||||
username
|
|
||||||
);
|
|
||||||
|
|
||||||
CommonsApplication.getInstance().clearApplicationData(
|
|
||||||
requireActivity(), logoutListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.progressBarEdit.setVisibility(GONE);
|
|
||||||
binding.descriptionEdit.setVisibility(VISIBLE);
|
|
||||||
|
|
||||||
} else if (requestCode == REQUEST_CODE_EDIT_DESCRIPTION && resultCode == RESULT_CANCELED) {
|
|
||||||
binding.progressBarEdit.setVisibility(GONE);
|
|
||||||
binding.descriptionEdit.setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds caption to the map and updates captions
|
* Adds caption to the map and updates captions
|
||||||
* @param mediaDetail UploadMediaDetail
|
* @param mediaDetail UploadMediaDetail
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
onSwipe()
|
onSwipe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.zoomProgressBar?.let {
|
binding.zoomProgressBar.let {
|
||||||
it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
|
it.visibility = if (result.status is CallbackStatus.FETCHING) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +234,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
sharedPreferences.getBoolean(ImageHelper.SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY, true)
|
sharedPreferences.getBoolean(ImageHelper.SHOW_ALREADY_ACTIONED_IMAGES_PREFERENCE_KEY, true)
|
||||||
|
|
||||||
if (!images.isNullOrEmpty()) {
|
if (!images.isNullOrEmpty()) {
|
||||||
binding.zoomable!!.setOnTouchListener(
|
binding.zoomable.setOnTouchListener(
|
||||||
object : OnSwipeTouchListener(this) {
|
object : OnSwipeTouchListener(this) {
|
||||||
// Swipe left to view next image in the folder. (if available)
|
// Swipe left to view next image in the folder. (if available)
|
||||||
override fun onSwipeLeft() {
|
override fun onSwipeLeft() {
|
||||||
|
|
@ -271,7 +271,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
* Handles down swipe action
|
* Handles down swipe action
|
||||||
*/
|
*/
|
||||||
private fun onDownSwiped() {
|
private fun onDownSwiped() {
|
||||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,7 +341,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
* Handles up swipe action
|
* Handles up swipe action
|
||||||
*/
|
*/
|
||||||
private fun onUpSwiped() {
|
private fun onUpSwiped() {
|
||||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -414,7 +414,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
* Handles right swipe action
|
* Handles right swipe action
|
||||||
*/
|
*/
|
||||||
private fun onRightSwiped(showAlreadyActionedImages: Boolean) {
|
private fun onRightSwiped(showAlreadyActionedImages: Boolean) {
|
||||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,7 +451,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
* Handles left swipe action
|
* Handles left swipe action
|
||||||
*/
|
*/
|
||||||
private fun onLeftSwiped(showAlreadyActionedImages: Boolean) {
|
private fun onLeftSwiped(showAlreadyActionedImages: Boolean) {
|
||||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -646,7 +646,7 @@ class ZoomableActivity : BaseActivity() {
|
||||||
.setProgressBarImage(ProgressBarDrawable())
|
.setProgressBarImage(ProgressBarDrawable())
|
||||||
.setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
.setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||||
.build()
|
.build()
|
||||||
with(binding.zoomable!!) {
|
with(binding.zoomable) {
|
||||||
setHierarchy(hierarchy)
|
setHierarchy(hierarchy)
|
||||||
setAllowTouchInterceptionWhileZoomed(true)
|
setAllowTouchInterceptionWhileZoomed(true)
|
||||||
setIsLongpressEnabled(false)
|
setIsLongpressEnabled(false)
|
||||||
|
|
@ -658,10 +658,10 @@ class ZoomableActivity : BaseActivity() {
|
||||||
.setUri(imageUri)
|
.setUri(imageUri)
|
||||||
.setControllerListener(loadingListener)
|
.setControllerListener(loadingListener)
|
||||||
.build()
|
.build()
|
||||||
binding.zoomable!!.controller = controller
|
binding.zoomable.controller = controller
|
||||||
|
|
||||||
if (photoBackgroundColor != null) {
|
if (photoBackgroundColor != null) {
|
||||||
binding.zoomable!!.setBackgroundColor(photoBackgroundColor!!)
|
binding.zoomable.setBackgroundColor(photoBackgroundColor!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!images.isNullOrEmpty()) {
|
if (!images.isNullOrEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -285,7 +285,7 @@ public class OkHttpJsonApiClient {
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
Timber.d("Fetching nearby items at radius %s", radius);
|
Timber.d("Fetching nearby items at radius %s", radius);
|
||||||
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
|
Timber.d("CUSTOM_SPARQL: %s", String.valueOf(customQuery != null));
|
||||||
final String wikidataQuery;
|
final String wikidataQuery;
|
||||||
if (customQuery != null) {
|
if (customQuery != null) {
|
||||||
wikidataQuery = customQuery;
|
wikidataQuery = customQuery;
|
||||||
|
|
@ -344,7 +344,7 @@ public class OkHttpJsonApiClient {
|
||||||
final boolean shouldQueryForMonuments, final String customQuery)
|
final boolean shouldQueryForMonuments, final String customQuery)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
|
Timber.d("CUSTOM_SPARQL: %s", String.valueOf(customQuery != null));
|
||||||
|
|
||||||
final String wikidataQuery;
|
final String wikidataQuery;
|
||||||
if (customQuery != null) {
|
if (customQuery != null) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class NearbyFilterSearchRecyclerViewAdapter
|
public class NearbyFilterSearchRecyclerViewAdapter
|
||||||
extends RecyclerView.Adapter<NearbyFilterSearchRecyclerViewAdapter.RecyclerViewHolder>
|
extends RecyclerView.Adapter<NearbyFilterSearchRecyclerViewAdapter.RecyclerViewHolder>
|
||||||
|
|
@ -121,11 +122,11 @@ public class NearbyFilterSearchRecyclerViewAdapter
|
||||||
results.count = labels.size();
|
results.count = labels.size();
|
||||||
results.values = labels;
|
results.values = labels;
|
||||||
} else {
|
} else {
|
||||||
constraint = constraint.toString().toLowerCase();
|
constraint = constraint.toString().toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
for (Label label : labels) {
|
for (Label label : labels) {
|
||||||
String data = label.toString();
|
String data = label.toString();
|
||||||
if (data.toLowerCase().startsWith(constraint.toString())) {
|
if (data.toLowerCase(Locale.ROOT).startsWith(constraint.toString())) {
|
||||||
filteredArrayList.add(Label.fromText(label.getText()));
|
filteredArrayList.add(Label.fromText(label.getText()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby
|
package fr.free.nrw.commons.nearby
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
|
|
@ -17,9 +18,9 @@ import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
||||||
fun placeAdapterDelegate(
|
fun placeAdapterDelegate(
|
||||||
bookmarkLocationDao: BookmarkLocationsDao,
|
bookmarkLocationDao: BookmarkLocationsDao,
|
||||||
onItemClick: ((Place) -> Unit)? = null,
|
onItemClick: ((Place) -> Unit)? = null,
|
||||||
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>) -> Unit,
|
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
|
||||||
onCameraLongPressed: () -> Boolean,
|
onCameraLongPressed: () -> Boolean,
|
||||||
onGalleryClicked: (Place) -> Unit,
|
onGalleryClicked: (Place, ActivityResultLauncher<Intent>) -> Unit,
|
||||||
onGalleryLongPressed: () -> Boolean,
|
onGalleryLongPressed: () -> Boolean,
|
||||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||||
onBookmarkLongPressed: () -> Boolean,
|
onBookmarkLongPressed: () -> Boolean,
|
||||||
|
|
@ -28,6 +29,8 @@ fun placeAdapterDelegate(
|
||||||
onDirectionsClicked: (Place) -> Unit,
|
onDirectionsClicked: (Place) -> Unit,
|
||||||
onDirectionsLongPressed: () -> Boolean,
|
onDirectionsLongPressed: () -> Boolean,
|
||||||
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
||||||
|
cameraPickLauncherForResult: ActivityResultLauncher<Intent>,
|
||||||
|
galleryPickLauncherForResult: ActivityResultLauncher<Intent>
|
||||||
) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ layoutInflater, parent ->
|
) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ layoutInflater, parent ->
|
||||||
ItemPlaceBinding.inflate(layoutInflater, parent, false)
|
ItemPlaceBinding.inflate(layoutInflater, parent, false)
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -44,10 +47,10 @@ fun placeAdapterDelegate(
|
||||||
onItemClick?.invoke(item)
|
onItemClick?.invoke(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher) }
|
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult) }
|
||||||
nearbyButtonLayout.cameraButton.setOnLongClickListener { onCameraLongPressed() }
|
nearbyButtonLayout.cameraButton.setOnLongClickListener { onCameraLongPressed() }
|
||||||
|
|
||||||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) }
|
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) }
|
||||||
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
||||||
bookmarkButtonImage.setOnClickListener {
|
bookmarkButtonImage.setOnClickListener {
|
||||||
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import androidx.room.Dao;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.OnConflictStrategy;
|
import androidx.room.OnConflictStrategy;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,8 +37,21 @@ public abstract class PlaceDao {
|
||||||
*/
|
*/
|
||||||
public Completable save(final Place place) {
|
public Completable save(final Place place) {
|
||||||
return Completable
|
return Completable
|
||||||
.fromAction(() -> {
|
.fromAction(() -> saveSynchronous(place));
|
||||||
saveSynchronous(place);
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Deletes all Place objects from the database.
|
||||||
|
*/
|
||||||
|
@Query("DELETE FROM place")
|
||||||
|
public abstract void deleteAllSynchronous();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all Place objects from the database.
|
||||||
|
*
|
||||||
|
* @return A Completable that completes once the deletion operation is done.
|
||||||
|
*/
|
||||||
|
public Completable deleteAll() {
|
||||||
|
return Completable.fromAction(this::deleteAllSynchronous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
|
@ -36,4 +35,8 @@ public class PlacesLocalDataSource {
|
||||||
public Completable savePlace(Place place) {
|
public Completable savePlace(Place place) {
|
||||||
return placeDao.save(place);
|
return placeDao.save(place);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Completable clearCache() {
|
||||||
|
return placeDao.deleteAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby;
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,4 +39,13 @@ public class PlacesRepository {
|
||||||
return localDataSource.fetchPlace(entityID);
|
return localDataSource.fetchPlace(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the Nearby cache on an IO thread.
|
||||||
|
*
|
||||||
|
* @return A Completable that completes once the cache has been successfully cleared.
|
||||||
|
*/
|
||||||
|
public Completable clearCache() {
|
||||||
|
return localDataSource.clearCache()
|
||||||
|
.subscribeOn(Schedulers.io()); // Ensure it runs on IO thread
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class WikidataFeedback : BaseActivity() {
|
||||||
lat,
|
lat,
|
||||||
lng,
|
lng,
|
||||||
)
|
)
|
||||||
} as Callable<SingleSource<Boolean?>>,
|
},
|
||||||
).subscribeOn(Schedulers.io())
|
).subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({ aBoolean: Boolean? ->
|
.subscribe({ aBoolean: Boolean? ->
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,14 @@ class CommonPlaceClickActions
|
||||||
private val activity: Activity,
|
private val activity: Activity,
|
||||||
private val contributionController: ContributionController,
|
private val contributionController: ContributionController,
|
||||||
) {
|
) {
|
||||||
fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>) -> Unit =
|
fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit =
|
||||||
{ place, launcher ->
|
{ place, launcher, resultLauncher ->
|
||||||
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
||||||
showLoginDialog()
|
showLoginDialog()
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}")
|
Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}")
|
||||||
storeSharedPrefs(place)
|
storeSharedPrefs(place)
|
||||||
contributionController.initiateCameraPick(activity, launcher)
|
contributionController.initiateCameraPick(activity, launcher, resultLauncher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,14 +72,14 @@ class CommonPlaceClickActions
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onGalleryClicked(): (Place) -> Unit =
|
fun onGalleryClicked(): (Place, ActivityResultLauncher<Intent>) -> Unit =
|
||||||
{
|
{place, galleryPickLauncherForResult ->
|
||||||
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
||||||
showLoginDialog()
|
showLoginDialog()
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Gallery button tapped. Image title: ${it.getName()}Image desc: ${it.getLongDescription()}")
|
Timber.d("Gallery button tapped. Image title: ${place.getName()}Image desc: ${place.getLongDescription()}")
|
||||||
storeSharedPrefs(it)
|
storeSharedPrefs(place)
|
||||||
contributionController.initiateGalleryPick(activity, false)
|
contributionController.initiateGalleryPick(activity, galleryPickLauncherForResult, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,18 @@ import android.view.ViewGroup;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
import androidx.activity.result.ActivityResultCallback;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog.Builder;
|
import androidx.appcompat.app.AlertDialog.Builder;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
|
|
@ -105,6 +108,7 @@ import fr.free.nrw.commons.utils.NetworkUtils;
|
||||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||||
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
@ -218,9 +222,36 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
private LatLng updatedLatLng;
|
private LatLng updatedLatLng;
|
||||||
private boolean searchable;
|
private boolean searchable;
|
||||||
|
|
||||||
|
private ConstraintLayout nearbyLegend;
|
||||||
|
|
||||||
private GridLayoutManager gridLayoutManager;
|
private GridLayoutManager gridLayoutManager;
|
||||||
private List<BottomSheetItem> dataList;
|
private List<BottomSheetItem> dataList;
|
||||||
private BottomSheetAdapter bottomSheetAdapter;
|
private BottomSheetAdapter bottomSheetAdapter;
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> customSelectorLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
|
||||||
new RequestMultiplePermissions(),
|
new RequestMultiplePermissions(),
|
||||||
new ActivityResultCallback<Map<String, Boolean>>() {
|
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
|
|
@ -236,7 +267,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
} else {
|
} else {
|
||||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
||||||
inAppCameraLocationPermissionLauncher);
|
inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
} else {
|
} else {
|
||||||
controller.locationPermissionCallback.onLocationPermissionDenied(
|
controller.locationPermissionCallback.onLocationPermissionDenied(
|
||||||
getActivity().getString(
|
getActivity().getString(
|
||||||
|
|
@ -302,6 +333,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setMessage("Saving in progress...");
|
progressDialog.setMessage("Saving in progress...");
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
return view;
|
return view;
|
||||||
|
|
||||||
|
|
@ -311,9 +343,21 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
||||||
@NonNull final MenuInflater inflater) {
|
@NonNull final MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.nearby_fragment_menu, menu);
|
inflater.inflate(R.menu.nearby_fragment_menu, menu);
|
||||||
|
MenuItem refreshButton = menu.findItem(R.id.item_refresh);
|
||||||
MenuItem listMenu = menu.findItem(R.id.list_sheet);
|
MenuItem listMenu = menu.findItem(R.id.list_sheet);
|
||||||
MenuItem saveAsGPXButton = menu.findItem(R.id.list_item_gpx);
|
MenuItem saveAsGPXButton = menu.findItem(R.id.list_item_gpx);
|
||||||
MenuItem saveAsKMLButton = menu.findItem(R.id.list_item_kml);
|
MenuItem saveAsKMLButton = menu.findItem(R.id.list_item_kml);
|
||||||
|
refreshButton.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
try {
|
||||||
|
emptyCache();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
listMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
listMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
|
@ -362,6 +406,16 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
}
|
}
|
||||||
locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager,
|
locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
// Set up the floating activity button to toggle the visibility of the legend
|
||||||
|
binding.fabLegend.setOnClickListener(v -> {
|
||||||
|
if (binding.nearbyLegendLayout.getRoot().getVisibility() == View.VISIBLE) {
|
||||||
|
binding.nearbyLegendLayout.getRoot().setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
binding.nearbyLegendLayout.getRoot().setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
presenter.attachView(this);
|
presenter.attachView(this);
|
||||||
isPermissionDenied = false;
|
isPermissionDenied = false;
|
||||||
recenterToUserLocation = false;
|
recenterToUserLocation = false;
|
||||||
|
|
@ -555,7 +609,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
},
|
},
|
||||||
commonPlaceClickActions,
|
commonPlaceClickActions,
|
||||||
inAppCameraLocationPermissionLauncher
|
inAppCameraLocationPermissionLauncher,
|
||||||
|
galleryPickLauncherForResult,
|
||||||
|
cameraPickLauncherForResult
|
||||||
);
|
);
|
||||||
binding.bottomSheetNearby.rvNearbyList.setAdapter(adapter);
|
binding.bottomSheetNearby.rvNearbyList.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
@ -1115,6 +1171,48 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the Nearby map
|
||||||
|
* Clears all location markers, refreshes them, reinserts them into the map.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void reloadMap() {
|
||||||
|
clearAllMarkers(); // Clear the list of markers
|
||||||
|
binding.map.getController().setZoom(ZOOM_LEVEL); // Reset the zoom level
|
||||||
|
binding.map.getController().setCenter(lastMapFocus); // Recenter the focus
|
||||||
|
if (locationPermissionsHelper.checkLocationPermission(getActivity())) {
|
||||||
|
locationPermissionGranted(); // Reload map with user's location
|
||||||
|
} else {
|
||||||
|
startMapWithoutPermission(); // Reload map without user's location
|
||||||
|
}
|
||||||
|
binding.map.invalidate(); // Invalidate the map
|
||||||
|
presenter.updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED); // Restart the map
|
||||||
|
Timber.d("Reloaded Map Successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the Nearby local cache and then calls for the map to be reloaded
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void emptyCache() {
|
||||||
|
// reload the map once the cache is cleared
|
||||||
|
compositeDisposable.add(
|
||||||
|
placesRepository.clearCache()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.andThen(Completable.fromAction(this::reloadMap))
|
||||||
|
.subscribe(
|
||||||
|
() -> {
|
||||||
|
Timber.d("Nearby Cache cleared successfully.");
|
||||||
|
},
|
||||||
|
throwable -> {
|
||||||
|
Timber.e(throwable, "Failed to clear the Nearby Cache");
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void savePlacesAsKML() {
|
private void savePlacesAsKML() {
|
||||||
final Observable<String> savePlacesObservable = Observable
|
final Observable<String> savePlacesObservable = Observable
|
||||||
.fromCallable(() -> nearbyController
|
.fromCallable(() -> nearbyController
|
||||||
|
|
@ -2186,7 +2284,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
if (binding.fabCamera.isShown()) {
|
if (binding.fabCamera.isShown()) {
|
||||||
Timber.d("Camera button tapped. Place: %s", selectedPlace.toString());
|
Timber.d("Camera button tapped. Place: %s", selectedPlace.toString());
|
||||||
storeSharedPrefs(selectedPlace);
|
storeSharedPrefs(selectedPlace);
|
||||||
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
|
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2195,6 +2293,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString());
|
Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString());
|
||||||
storeSharedPrefs(selectedPlace);
|
storeSharedPrefs(selectedPlace);
|
||||||
controller.initiateGalleryPick(getActivity(),
|
controller.initiateGalleryPick(getActivity(),
|
||||||
|
galleryPickLauncherForResult,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -2203,7 +2302,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
if (binding.fabCustomGallery.isShown()) {
|
if (binding.fabCustomGallery.isShown()) {
|
||||||
Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString());
|
Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString());
|
||||||
storeSharedPrefs(selectedPlace);
|
storeSharedPrefs(selectedPlace);
|
||||||
controller.initiateCustomGalleryPickWithPermission(getActivity());
|
controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby.fragments
|
package fr.free.nrw.commons.nearby.fragments
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
|
@ -12,6 +13,8 @@ class PlaceAdapter(
|
||||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||||
commonPlaceClickActions: CommonPlaceClickActions,
|
commonPlaceClickActions: CommonPlaceClickActions,
|
||||||
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
||||||
|
galleryPickLauncherForResult: ActivityResultLauncher<Intent>,
|
||||||
|
cameraPickLauncherForResult: ActivityResultLauncher<Intent>
|
||||||
) : BaseDelegateAdapter<Place>(
|
) : BaseDelegateAdapter<Place>(
|
||||||
placeAdapterDelegate(
|
placeAdapterDelegate(
|
||||||
bookmarkLocationsDao,
|
bookmarkLocationsDao,
|
||||||
|
|
@ -27,6 +30,8 @@ class PlaceAdapter(
|
||||||
commonPlaceClickActions.onDirectionsClicked(),
|
commonPlaceClickActions.onDirectionsClicked(),
|
||||||
commonPlaceClickActions.onDirectionsLongPressed(),
|
commonPlaceClickActions.onDirectionsLongPressed(),
|
||||||
inAppCameraLocationPermissionLauncher,
|
inAppCameraLocationPermissionLauncher,
|
||||||
|
cameraPickLauncherForResult,
|
||||||
|
galleryPickLauncherForResult
|
||||||
),
|
),
|
||||||
areItemsTheSame = { oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId },
|
areItemsTheSame = { oldItem, newItem -> oldItem.wikiDataEntityId == newItem.wikiDataEntityId },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import fr.free.nrw.commons.databinding.ActivityNotificationBinding;
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
|
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException;
|
||||||
import fr.free.nrw.commons.notification.models.Notification;
|
import fr.free.nrw.commons.notification.models.Notification;
|
||||||
|
import fr.free.nrw.commons.notification.models.NotificationType;
|
||||||
import fr.free.nrw.commons.theme.BaseActivity;
|
import fr.free.nrw.commons.theme.BaseActivity;
|
||||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
|
|
@ -148,7 +149,11 @@ public class NotificationActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
adapter = new NotificatinAdapter(item -> {
|
adapter = new NotificatinAdapter(item -> {
|
||||||
Timber.d("Notification clicked %s", item.getLink());
|
Timber.d("Notification clicked %s", item.getLink());
|
||||||
handleUrl(item.getLink());
|
if (item.getNotificationType() == NotificationType.EMAIL){
|
||||||
|
ViewUtil.showLongSnackbar(binding.container,getString(R.string.check_your_email_inbox));
|
||||||
|
} else {
|
||||||
|
handleUrl(item.getLink());
|
||||||
|
}
|
||||||
removeNotification(item);
|
removeNotification(item);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,23 @@ class NotificationClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun WikimediaNotification.toCommonsNotification() =
|
private fun WikimediaNotification.toCommonsNotification() :
|
||||||
Notification(
|
Notification {
|
||||||
notificationType = NotificationType.UNKNOWN,
|
val notificationText = contents?.compactHeader ?: ""
|
||||||
notificationText = contents?.compactHeader ?: "",
|
val notificationType =
|
||||||
date = DateUtil.getMonthOnlyDateString(timestamp),
|
if (notificationText.contains("Sent you an email", ignoreCase = true)) {
|
||||||
link = contents?.links?.primary?.url ?: "",
|
NotificationType.EMAIL
|
||||||
iconUrl = "",
|
} else {
|
||||||
notificationId = id().toString(),
|
NotificationType.UNKNOWN
|
||||||
)
|
}
|
||||||
|
|
||||||
|
return Notification(
|
||||||
|
notificationType = notificationType,
|
||||||
|
notificationText = notificationText,
|
||||||
|
date = DateUtil.getMonthOnlyDateString(timestamp),
|
||||||
|
link = contents?.links?.primary?.url ?: "",
|
||||||
|
iconUrl = "",
|
||||||
|
notificationId = id().toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ public enum NotificationType {
|
||||||
THANK_YOU_EDIT("thank-you-edit"),
|
THANK_YOU_EDIT("thank-you-edit"),
|
||||||
EDIT_USER_TALK("edit-user-talk"),
|
EDIT_USER_TALK("edit-user-talk"),
|
||||||
MENTION("mention"),
|
MENTION("mention"),
|
||||||
|
EMAIL("email"),
|
||||||
WELCOME("welcome"),
|
WELCOME("welcome"),
|
||||||
UNKNOWN("unknown");
|
UNKNOWN("unknown");
|
||||||
private String type;
|
private String type;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -139,14 +140,14 @@ public class ProfileActivity extends BaseActivity {
|
||||||
leaderboardFragment.setArguments(leaderBoardBundle);
|
leaderboardFragment.setArguments(leaderBoardBundle);
|
||||||
|
|
||||||
fragmentList.add(leaderboardFragment);
|
fragmentList.add(leaderboardFragment);
|
||||||
titleList.add(getResources().getString(R.string.leaderboard_tab_title).toUpperCase());
|
titleList.add(getResources().getString(R.string.leaderboard_tab_title).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
contributionsFragment = new ContributionsFragment();
|
contributionsFragment = new ContributionsFragment();
|
||||||
Bundle contributionsListBundle = new Bundle();
|
Bundle contributionsListBundle = new Bundle();
|
||||||
contributionsListBundle.putString(KEY_USERNAME, userName);
|
contributionsListBundle.putString(KEY_USERNAME, userName);
|
||||||
contributionsFragment.setArguments(contributionsListBundle);
|
contributionsFragment.setArguments(contributionsListBundle);
|
||||||
fragmentList.add(contributionsFragment);
|
fragmentList.add(contributionsFragment);
|
||||||
titleList.add(getString(R.string.contributions_fragment).toUpperCase());
|
titleList.add(getString(R.string.contributions_fragment).toUpperCase(Locale.ROOT));
|
||||||
|
|
||||||
viewPagerAdapter.setTabData(fragmentList, titleList);
|
viewPagerAdapter.setTabData(fragmentList, titleList);
|
||||||
viewPagerAdapter.notifyDataSetChanged();
|
viewPagerAdapter.notifyDataSetChanged();
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import fr.free.nrw.commons.profile.ProfileActivity;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
@ -361,7 +362,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
|
||||||
+ levelInfo.getMaxUniqueImages());
|
+ levelInfo.getMaxUniqueImages());
|
||||||
binding.imageFeatured.setText(String.valueOf(achievements.getFeaturedImages()));
|
binding.imageFeatured.setText(String.valueOf(achievements.getFeaturedImages()));
|
||||||
binding.qualityImages.setText(String.valueOf(achievements.getQualityImages()));
|
binding.qualityImages.setText(String.valueOf(achievements.getQualityImages()));
|
||||||
String levelUpInfoString = getString(R.string.level).toUpperCase();
|
String levelUpInfoString = getString(R.string.level).toUpperCase(Locale.ROOT);
|
||||||
levelUpInfoString += " " + levelInfo.getLevelNumber();
|
levelUpInfoString += " " + levelInfo.getLevelNumber();
|
||||||
binding.achievementLevel.setText(levelUpInfoString);
|
binding.achievementLevel.setText(levelUpInfoString);
|
||||||
binding.achievementBadgeImage.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge,
|
binding.achievementBadgeImage.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.recentlanguages;
|
package fr.free.nrw.commons.recentlanguages;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
@ -117,6 +118,7 @@ public class RecentLanguagesDao {
|
||||||
* @return Language object
|
* @return Language object
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@SuppressLint("Range")
|
||||||
Language fromCursor(final Cursor cursor) {
|
Language fromCursor(final Cursor cursor) {
|
||||||
// Hardcoding column positions!
|
// Hardcoding column positions!
|
||||||
final String languageName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
final String languageName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
import java.util.Locale;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
public class ReviewActivity extends BaseActivity {
|
public class ReviewActivity extends BaseActivity {
|
||||||
|
|
@ -241,7 +242,7 @@ public class ReviewActivity extends BaseActivity {
|
||||||
|
|
||||||
public void showSkipImageInfo(){
|
public void showSkipImageInfo(){
|
||||||
DialogUtil.showAlertDialog(ReviewActivity.this,
|
DialogUtil.showAlertDialog(ReviewActivity.this,
|
||||||
getString(R.string.skip_image).toUpperCase(),
|
getString(R.string.skip_image).toUpperCase(Locale.ROOT),
|
||||||
getString(R.string.skip_image_explanation),
|
getString(R.string.skip_image_explanation),
|
||||||
getString(android.R.string.ok),
|
getString(android.R.string.ok),
|
||||||
"",
|
"",
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import android.widget.TextView;
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
import androidx.activity.result.ActivityResultCallback;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.preference.ListPreference;
|
import androidx.preference.ListPreference;
|
||||||
import androidx.preference.MultiSelectListPreference;
|
import androidx.preference.MultiSelectListPreference;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
@ -88,6 +89,15 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
private View separator;
|
private View separator;
|
||||||
private ListView languageHistoryListView;
|
private ListView languageHistoryListView;
|
||||||
private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content";
|
private static final String GET_CONTENT_PICKER_HELP_URL = "https://commons-app.github.io/docs.html#get-content";
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||||
|
registerForActivityResult(new StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||||
|
contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(Map<String, Boolean> result) {
|
public void onActivityResult(Map<String, Boolean> result) {
|
||||||
|
|
@ -96,7 +106,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
areAllGranted = areAllGranted && b;
|
areAllGranted = areAllGranted && b;
|
||||||
}
|
}
|
||||||
if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
if (!areAllGranted && shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher);
|
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class FailedUploadsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(userName)) {
|
if (StringUtils.isEmpty(userName)) {
|
||||||
userName = sessionManager!!.getUserName()
|
userName = sessionManager.getUserName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,8 +96,8 @@ class FailedUploadsFragment :
|
||||||
fun initRecyclerView() {
|
fun initRecyclerView() {
|
||||||
binding.failedUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
binding.failedUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||||
binding.failedUploadsRecyclerView.adapter = adapter
|
binding.failedUploadsRecyclerView.adapter = adapter
|
||||||
pendingUploadsPresenter!!.getFailedContributions()
|
pendingUploadsPresenter.getFailedContributions()
|
||||||
pendingUploadsPresenter!!.failedContributionList.observe(
|
pendingUploadsPresenter.failedContributionList.observe(
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
) { list: PagedList<Contribution?> ->
|
) { list: PagedList<Contribution?> ->
|
||||||
adapter.submitList(list)
|
adapter.submitList(list)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import java.math.BigInteger;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
@ -139,7 +140,7 @@ public class FileUtils {
|
||||||
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
|
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
|
||||||
.toString());
|
.toString());
|
||||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||||
fileExtension.toLowerCase());
|
fileExtension.toLowerCase(Locale.getDefault()));
|
||||||
}
|
}
|
||||||
return mimeType;
|
return mimeType;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ class PendingUploadsFragment :
|
||||||
fun initRecyclerView() {
|
fun initRecyclerView() {
|
||||||
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||||
binding.pendingUploadsRecyclerView.adapter = adapter
|
binding.pendingUploadsRecyclerView.adapter = adapter
|
||||||
pendingUploadsPresenter!!.setup()
|
pendingUploadsPresenter.setup()
|
||||||
pendingUploadsPresenter!!.totalContributionList.observe(
|
pendingUploadsPresenter.totalContributionList.observe(
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
) { list: PagedList<Contribution?> ->
|
) { list: PagedList<Contribution?> ->
|
||||||
contributionsSize = list.size
|
contributionsSize = list.size
|
||||||
|
|
|
||||||
|
|
@ -320,6 +320,14 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* go to the uploadProgress activity to check the status of uploading
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void goToUploadProgressActivity() {
|
||||||
|
startActivity(new Intent(this, UploadProgressActivity.class));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show/Hide the progress dialog
|
* Show/Hide the progress dialog
|
||||||
*/
|
*/
|
||||||
|
|
@ -433,14 +441,6 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (requestCode == CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS) {
|
|
||||||
//TODO: Confirm if handling manual permission enabled is required
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the flag indicating whether the upload is of a specific place.
|
* Sets the flag indicating whether the upload is of a specific place.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ public interface UploadContract {
|
||||||
|
|
||||||
void returnToMainActivity();
|
void returnToMainActivity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When submission successful, go to the loadProgressActivity to hint the user this
|
||||||
|
* submission is valid. And the user will see the upload progress in this activity;
|
||||||
|
* Fixes: <a href="https://github.com/commons-app/apps-android-commons/issues/5846">Issue</a>
|
||||||
|
*/
|
||||||
|
void goToUploadProgressActivity();
|
||||||
|
|
||||||
void askUserToLogIn();
|
void askUserToLogIn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
@ -57,27 +58,29 @@ public class UploadMediaDetailAdapter extends
|
||||||
private int currentPosition;
|
private int currentPosition;
|
||||||
private Fragment fragment;
|
private Fragment fragment;
|
||||||
private Activity activity;
|
private Activity activity;
|
||||||
|
private final ActivityResultLauncher<Intent> voiceInputResultLauncher;
|
||||||
private SelectedVoiceIcon selectedVoiceIcon;
|
private SelectedVoiceIcon selectedVoiceIcon;
|
||||||
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
|
||||||
|
|
||||||
private RowItemDescriptionBinding binding;
|
private RowItemDescriptionBinding binding;
|
||||||
|
|
||||||
public UploadMediaDetailAdapter(Fragment fragment, String savedLanguageValue,
|
public UploadMediaDetailAdapter(Fragment fragment, String savedLanguageValue,
|
||||||
RecentLanguagesDao recentLanguagesDao) {
|
RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher<Intent> voiceInputResultLauncher) {
|
||||||
uploadMediaDetails = new ArrayList<>();
|
uploadMediaDetails = new ArrayList<>();
|
||||||
selectedLanguages = new HashMap<>();
|
selectedLanguages = new HashMap<>();
|
||||||
this.savedLanguageValue = savedLanguageValue;
|
this.savedLanguageValue = savedLanguageValue;
|
||||||
this.recentLanguagesDao = recentLanguagesDao;
|
this.recentLanguagesDao = recentLanguagesDao;
|
||||||
this.fragment = fragment;
|
this.fragment = fragment;
|
||||||
|
this.voiceInputResultLauncher = voiceInputResultLauncher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UploadMediaDetailAdapter(Activity activity, final String savedLanguageValue,
|
public UploadMediaDetailAdapter(Activity activity, final String savedLanguageValue,
|
||||||
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) {
|
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher<Intent> voiceInputResultLauncher) {
|
||||||
this.uploadMediaDetails = uploadMediaDetails;
|
this.uploadMediaDetails = uploadMediaDetails;
|
||||||
selectedLanguages = new HashMap<>();
|
selectedLanguages = new HashMap<>();
|
||||||
this.savedLanguageValue = savedLanguageValue;
|
this.savedLanguageValue = savedLanguageValue;
|
||||||
this.recentLanguagesDao = recentLanguagesDao;
|
this.recentLanguagesDao = recentLanguagesDao;
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
|
this.voiceInputResultLauncher = voiceInputResultLauncher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCallback(Callback callback) {
|
public void setCallback(Callback callback) {
|
||||||
|
|
@ -150,11 +153,7 @@ public class UploadMediaDetailAdapter extends
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (activity == null) {
|
voiceInputResultLauncher.launch(intent);
|
||||||
fragment.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
|
||||||
} else {
|
|
||||||
activity.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Timber.e(e.getMessage());
|
Timber.e(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
@ -407,7 +406,7 @@ public class UploadMediaDetailAdapter extends
|
||||||
recentLanguagesDao
|
recentLanguagesDao
|
||||||
.addRecentLanguage(new Language(languageName, languageCode));
|
.addRecentLanguage(new Language(languageName, languageCode));
|
||||||
|
|
||||||
selectedLanguages.remove(position);
|
selectedLanguages.clear();
|
||||||
selectedLanguages.put(position, languageCode);
|
selectedLanguages.put(position, languageCode);
|
||||||
((LanguagesAdapter) adapterView
|
((LanguagesAdapter) adapterView
|
||||||
.getAdapter()).setSelectedLangCode(languageCode);
|
.getAdapter()).setSelectedLangCode(languageCode);
|
||||||
|
|
@ -497,7 +496,7 @@ public class UploadMediaDetailAdapter extends
|
||||||
}
|
}
|
||||||
recentLanguagesDao.addRecentLanguage(new Language(languageName, languageCode));
|
recentLanguagesDao.addRecentLanguage(new Language(languageName, languageCode));
|
||||||
|
|
||||||
selectedLanguages.remove(position);
|
selectedLanguages.clear();
|
||||||
selectedLanguages.put(position, languageCode);
|
selectedLanguages.put(position, languageCode);
|
||||||
((RecentLanguagesAdapter) adapterView
|
((RecentLanguagesAdapter) adapterView
|
||||||
.getAdapter()).setSelectedLangCode(languageCode);
|
.getAdapter()).setSelectedLangCode(languageCode);
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,9 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
||||||
view.returnToMainActivity();
|
view.returnToMainActivity();
|
||||||
compositeDisposable.clear();
|
compositeDisposable.clear();
|
||||||
Timber.e("failed to upload: " + e.getMessage());
|
Timber.e("failed to upload: " + e.getMessage());
|
||||||
|
|
||||||
|
//is submission error, not need to go to the uploadActivity
|
||||||
|
//not start the uploading progress
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -131,6 +134,10 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
||||||
repository.cleanup();
|
repository.cleanup();
|
||||||
view.returnToMainActivity();
|
view.returnToMainActivity();
|
||||||
compositeDisposable.clear();
|
compositeDisposable.clear();
|
||||||
|
|
||||||
|
//after finish the uploadActivity, if successful,
|
||||||
|
//directly go to the upload progress activity
|
||||||
|
view.goToUploadProgressActivity();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,13 @@ abstract class BaseDelegateAdapter<T>(
|
||||||
areContentsTheSame: (T, T) -> Boolean = { old, new -> old == new },
|
areContentsTheSame: (T, T) -> Boolean = { old, new -> old == new },
|
||||||
) : AsyncListDifferDelegationAdapter<T>(
|
) : AsyncListDifferDelegationAdapter<T>(
|
||||||
object : DiffUtil.ItemCallback<T>() {
|
object : DiffUtil.ItemCallback<T>() {
|
||||||
override fun areItemsTheSame(
|
override fun areItemsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
|
||||||
oldItem: T,
|
return areItemsTheSame(oldItem, newItem)
|
||||||
newItem: T,
|
}
|
||||||
) = areItemsTheSame(oldItem, newItem)
|
|
||||||
|
|
||||||
override fun areContentsTheSame(
|
override fun areContentsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
|
||||||
oldItem: T,
|
return areContentsTheSame(oldItem, newItem)
|
||||||
newItem: T,
|
}
|
||||||
) = areContentsTheSame(oldItem, newItem)
|
|
||||||
},
|
},
|
||||||
*delegates,
|
*delegates,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
Objects.requireNonNull(getView()).setFocusableInTouchMode(true);
|
requireView().setFocusableInTouchMode(true);
|
||||||
getView().requestFocus();
|
getView().requestFocus();
|
||||||
getView().setOnKeyListener((v, keyCode, event) -> {
|
getView().setOnKeyListener((v, keyCode, event) -> {
|
||||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
|
@ -387,7 +387,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
||||||
});
|
});
|
||||||
|
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||||
.hide();
|
.hide();
|
||||||
|
|
||||||
if (getParentFragment().getParentFragment().getParentFragment()
|
if (getParentFragment().getParentFragment().getParentFragment()
|
||||||
|
|
@ -407,7 +407,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
||||||
super.onStop();
|
super.onStop();
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ abstract class DepictsDao {
|
||||||
/**
|
/**
|
||||||
* Gets all Depicts objects from the database, ordered by lastUsed in descending order.
|
* Gets all Depicts objects from the database, ordered by lastUsed in descending order.
|
||||||
*
|
*
|
||||||
* @return A list of Depicts objects.
|
* @return Deferred list of Depicts objects.
|
||||||
*/
|
*/
|
||||||
fun depictsList(): Deferred<List<Depicts>> =
|
fun depictsList(): Deferred<List<Depicts>> =
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
CoroutineScope(Dispatchers.IO).async {
|
||||||
|
|
@ -48,7 +48,7 @@ abstract class DepictsDao {
|
||||||
*
|
*
|
||||||
* @param depictedItem The Depicts object to insert.
|
* @param depictedItem The Depicts object to insert.
|
||||||
*/
|
*/
|
||||||
private fun insertDepict(depictedItem: Depicts) =
|
fun insertDepict(depictedItem: Depicts) =
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
insert(depictedItem)
|
insert(depictedItem)
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ abstract class DepictsDao {
|
||||||
* @param n The number of depicts to delete.
|
* @param n The number of depicts to delete.
|
||||||
* @return A list of Depicts objects to delete.
|
* @return A list of Depicts objects to delete.
|
||||||
*/
|
*/
|
||||||
private suspend fun depictsForDeletion(n: Int): Deferred<List<Depicts>> =
|
fun depictsForDeletion(n: Int): Deferred<List<Depicts>> =
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
CoroutineScope(Dispatchers.IO).async {
|
||||||
getDepictsForDeletion(n)
|
getDepictsForDeletion(n)
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,7 @@ abstract class DepictsDao {
|
||||||
*
|
*
|
||||||
* @param depicts The Depicts object to delete.
|
* @param depicts The Depicts object to delete.
|
||||||
*/
|
*/
|
||||||
private suspend fun deleteDepicts(depicts: Depicts) =
|
fun deleteDepicts(depicts: Depicts) =
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
delete(depicts)
|
delete(depicts)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
Objects.requireNonNull(getView()).setFocusableInTouchMode(true);
|
requireView().setFocusableInTouchMode(true);
|
||||||
getView().requestFocus();
|
getView().requestFocus();
|
||||||
getView().setOnKeyListener((v, keyCode, event) -> {
|
getView().setOnKeyListener((v, keyCode, event) -> {
|
||||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
|
@ -411,7 +411,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
||||||
});
|
});
|
||||||
|
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||||
.hide();
|
.hide();
|
||||||
|
|
||||||
if (getParentFragment().getParentFragment().getParentFragment()
|
if (getParentFragment().getParentFragment().getParentFragment()
|
||||||
|
|
@ -431,7 +431,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
||||||
super.onStop();
|
super.onStop();
|
||||||
if (media != null) {
|
if (media != null) {
|
||||||
Objects.requireNonNull(
|
Objects.requireNonNull(
|
||||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ import android.view.ViewGroup;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.exifinterface.media.ExifInterface;
|
import androidx.exifinterface.media.ExifInterface;
|
||||||
|
|
@ -58,9 +61,24 @@ import timber.log.Timber;
|
||||||
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
||||||
|
|
||||||
private static final int REQUEST_CODE = 1211;
|
private UploadMediaDetailAdapter uploadMediaDetailAdapter;
|
||||||
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
|
||||||
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
private final ActivityResultLauncher<Intent> startForResult = registerForActivityResult(
|
||||||
|
new StartActivityForResult(), result -> {
|
||||||
|
onCameraPosition(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> startForEditActivityResult = registerForActivityResult(
|
||||||
|
new StartActivityForResult(), result -> {
|
||||||
|
onEditActivityResult(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<Intent> voiceInputResultLauncher = registerForActivityResult(
|
||||||
|
new StartActivityForResult(), result -> {
|
||||||
|
onVoiceInput(result);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
public static Activity activity ;
|
public static Activity activity ;
|
||||||
|
|
||||||
|
|
@ -84,8 +102,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
private boolean hasUserRemovedLocation;
|
private boolean hasUserRemovedLocation;
|
||||||
|
|
||||||
|
|
||||||
private UploadMediaDetailAdapter uploadMediaDetailAdapter;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UploadMediaDetailsContract.UserActionListener presenter;
|
UploadMediaDetailsContract.UserActionListener presenter;
|
||||||
|
|
||||||
|
|
@ -279,7 +295,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
*/
|
*/
|
||||||
private void initRecyclerView() {
|
private void initRecyclerView() {
|
||||||
uploadMediaDetailAdapter = new UploadMediaDetailAdapter(this,
|
uploadMediaDetailAdapter = new UploadMediaDetailAdapter(this,
|
||||||
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao);
|
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao, voiceInputResultLauncher);
|
||||||
uploadMediaDetailAdapter.setCallback(this::showInfoAlert);
|
uploadMediaDetailAdapter.setCallback(this::showInfoAlert);
|
||||||
uploadMediaDetailAdapter.setEventListener(this);
|
uploadMediaDetailAdapter.setEventListener(this);
|
||||||
binding.rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext()));
|
binding.rvDescriptions.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
|
@ -593,14 +609,14 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
* This method is called to start the image editing activity for a specific UploadItem.
|
* This method is called to start the image editing activity for a specific UploadItem.
|
||||||
* It sets the UploadItem as the currently editable item, creates an intent to launch the
|
* It sets the UploadItem as the currently editable item, creates an intent to launch the
|
||||||
* EditActivity, and passes the image file path as an extra in the intent. The activity
|
* EditActivity, and passes the image file path as an extra in the intent. The activity
|
||||||
* is started with a request code, allowing the result to be handled in onActivityResult.
|
* is started using resultLauncher that handles the result in respective callback.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void showEditActivity(UploadItem uploadItem) {
|
public void showEditActivity(UploadItem uploadItem) {
|
||||||
editableUploadItem = uploadItem;
|
editableUploadItem = uploadItem;
|
||||||
Intent intent = new Intent(getContext(), EditActivity.class);
|
Intent intent = new Intent(getContext(), EditActivity.class);
|
||||||
intent.putExtra("image", uploadableFile.getFilePath().toString());
|
intent.putExtra("image", uploadableFile.getFilePath().toString());
|
||||||
startActivityForResult(intent, REQUEST_CODE_FOR_EDIT_ACTIVITY);
|
startForEditActivityResult.launch(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -615,6 +631,8 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
double defaultLongitude = -122.431297;
|
double defaultLongitude = -122.431297;
|
||||||
double defaultZoom = 16.0;
|
double defaultZoom = 16.0;
|
||||||
|
|
||||||
|
final Intent locationPickerIntent;
|
||||||
|
|
||||||
/* Retrieve image location from EXIF if present or
|
/* Retrieve image location from EXIF if present or
|
||||||
check if user has provided location while using the in-app camera.
|
check if user has provided location while using the in-app camera.
|
||||||
Use location of last UploadItem if none of them is available */
|
Use location of last UploadItem if none of them is available */
|
||||||
|
|
@ -624,10 +642,11 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
.getDecLatitude();
|
.getDecLatitude();
|
||||||
defaultLongitude = uploadItem.getGpsCoords().getDecLongitude();
|
defaultLongitude = uploadItem.getGpsCoords().getDecLongitude();
|
||||||
defaultZoom = uploadItem.getGpsCoords().getZoomLevel();
|
defaultZoom = uploadItem.getGpsCoords().getZoomLevel();
|
||||||
startActivityForResult(new LocationPicker.IntentBuilder()
|
|
||||||
|
locationPickerIntent = new LocationPicker.IntentBuilder()
|
||||||
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
||||||
.activityKey("UploadActivity")
|
.activityKey("UploadActivity")
|
||||||
.build(getActivity()), REQUEST_CODE);
|
.build(getActivity());
|
||||||
} else {
|
} else {
|
||||||
if (defaultKvStore.getString(LAST_LOCATION) != null) {
|
if (defaultKvStore.getString(LAST_LOCATION) != null) {
|
||||||
final String[] locationLatLng
|
final String[] locationLatLng
|
||||||
|
|
@ -638,27 +657,20 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
if (defaultKvStore.getString(LAST_ZOOM) != null) {
|
if (defaultKvStore.getString(LAST_ZOOM) != null) {
|
||||||
defaultZoom = Double.parseDouble(defaultKvStore.getString(LAST_ZOOM));
|
defaultZoom = Double.parseDouble(defaultKvStore.getString(LAST_ZOOM));
|
||||||
}
|
}
|
||||||
startActivityForResult(new LocationPicker.IntentBuilder()
|
|
||||||
|
locationPickerIntent = new LocationPicker.IntentBuilder()
|
||||||
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
||||||
.activityKey("NoLocationUploadActivity")
|
.activityKey("NoLocationUploadActivity")
|
||||||
.build(getActivity()), REQUEST_CODE);
|
.build(getActivity());
|
||||||
}
|
}
|
||||||
|
startForResult.launch(locationPickerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void onCameraPosition(ActivityResult result){
|
||||||
* Get the coordinates and update the existing coordinates.
|
if (result.getResultCode() == RESULT_OK) {
|
||||||
* @param requestCode code of request
|
|
||||||
* @param resultCode code of result
|
|
||||||
* @param data intent
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(final int requestCode, final int resultCode,
|
|
||||||
@Nullable final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
|
|
||||||
|
|
||||||
assert data != null;
|
assert result.getData() != null;
|
||||||
final CameraPosition cameraPosition = LocationPicker.getCameraPosition(data);
|
final CameraPosition cameraPosition = LocationPicker.getCameraPosition(result.getData());
|
||||||
|
|
||||||
if (cameraPosition != null) {
|
if (cameraPosition != null) {
|
||||||
|
|
||||||
|
|
@ -678,8 +690,21 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
removeLocation();
|
removeLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (requestCode == REQUEST_CODE_FOR_EDIT_ACTIVITY && resultCode == RESULT_OK) {
|
}
|
||||||
String result = data.getStringExtra("editedImageFilePath");
|
|
||||||
|
private void onVoiceInput(ActivityResult result) {
|
||||||
|
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
|
||||||
|
ArrayList<String> resultData = result.getData().getStringArrayListExtra(
|
||||||
|
RecognizerIntent.EXTRA_RESULTS);
|
||||||
|
uploadMediaDetailAdapter.handleSpeechResult(resultData.get(0));
|
||||||
|
}else {
|
||||||
|
Timber.e("Error %s", result.getResultCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onEditActivityResult(ActivityResult result){
|
||||||
|
if (result.getResultCode() == RESULT_OK) {
|
||||||
|
String path = result.getData().getStringExtra("editedImageFilePath");
|
||||||
|
|
||||||
if (Objects.equals(result, "Error")) {
|
if (Objects.equals(result, "Error")) {
|
||||||
Timber.e("Error in rotating image");
|
Timber.e("Error in rotating image");
|
||||||
|
|
@ -687,24 +712,15 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (binding != null){
|
if (binding != null){
|
||||||
binding.backgroundImage.setImageURI(Uri.fromFile(new File(result)));
|
binding.backgroundImage.setImageURI(Uri.fromFile(new File(path)));
|
||||||
}
|
}
|
||||||
editableUploadItem.setContentUri(Uri.fromFile(new File(result)));
|
editableUploadItem.setContentUri(Uri.fromFile(new File(path)));
|
||||||
callback.changeThumbnail(indexOfFragment,
|
callback.changeThumbnail(indexOfFragment,
|
||||||
result);
|
path);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Timber.e(e);
|
Timber.e(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (requestCode == REQUEST_CODE_FOR_VOICE_INPUT) {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
ArrayList<String> result = data.getStringArrayListExtra(
|
|
||||||
RecognizerIntent.EXTRA_RESULTS);
|
|
||||||
uploadMediaDetailAdapter.handleSpeechResult(result.get(0));
|
|
||||||
}else {
|
|
||||||
Timber.e("Error %s", resultCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -809,7 +825,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
@Override
|
@Override
|
||||||
public void displayAddLocationDialog(final Runnable onSkipClicked) {
|
public void displayAddLocationDialog(final Runnable onSkipClicked) {
|
||||||
isMissingLocationDialog = true;
|
isMissingLocationDialog = true;
|
||||||
DialogUtil.showAlertDialog(Objects.requireNonNull(getActivity()),
|
DialogUtil.showAlertDialog(requireActivity(),
|
||||||
getString(R.string.no_location_found_title),
|
getString(R.string.no_location_found_title),
|
||||||
getString(R.string.no_location_found_message),
|
getString(R.string.no_location_found_message),
|
||||||
getString(R.string.add_location),
|
getString(R.string.add_location),
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,9 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
||||||
if (place.location != null) {
|
if (place.location != null) {
|
||||||
final String countryCode = reverseGeoCode(place.location);
|
final String countryCode = reverseGeoCode(place.location);
|
||||||
if (countryCode != null && WLM_SUPPORTED_COUNTRIES
|
if (countryCode != null && WLM_SUPPORTED_COUNTRIES
|
||||||
.contains(countryCode.toLowerCase())) {
|
.contains(countryCode.toLowerCase(Locale.ROOT))) {
|
||||||
uploadItem.setWLMUpload(true);
|
uploadItem.setWLMUpload(true);
|
||||||
uploadItem.setCountryCode(countryCode.toLowerCase());
|
uploadItem.setCountryCode(countryCode.toLowerCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import androidx.work.Data
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
import fr.free.nrw.commons.BuildConfig.HOME_URL
|
||||||
import fr.free.nrw.commons.CommonsApplication
|
import fr.free.nrw.commons.CommonsApplication
|
||||||
import fr.free.nrw.commons.Media
|
import fr.free.nrw.commons.Media
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
|
|
@ -30,6 +31,7 @@ import fr.free.nrw.commons.customselector.database.UploadedStatus
|
||||||
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection
|
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||||
import fr.free.nrw.commons.media.MediaClient
|
import fr.free.nrw.commons.media.MediaClient
|
||||||
|
import fr.free.nrw.commons.nearby.PlacesRepository
|
||||||
import fr.free.nrw.commons.theme.BaseActivity
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
||||||
import fr.free.nrw.commons.upload.StashUploadResult
|
import fr.free.nrw.commons.upload.StashUploadResult
|
||||||
|
|
@ -38,8 +40,9 @@ import fr.free.nrw.commons.upload.UploadClient
|
||||||
import fr.free.nrw.commons.upload.UploadProgressActivity
|
import fr.free.nrw.commons.upload.UploadProgressActivity
|
||||||
import fr.free.nrw.commons.upload.UploadResult
|
import fr.free.nrw.commons.upload.UploadResult
|
||||||
import fr.free.nrw.commons.wikidata.WikidataEditService
|
import fr.free.nrw.commons.wikidata.WikidataEditService
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.MainScope
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -74,6 +77,9 @@ class UploadWorker(
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var fileUtilsWrapper: FileUtilsWrapper
|
lateinit var fileUtilsWrapper: FileUtilsWrapper
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var placesRepository: PlacesRepository
|
||||||
|
|
||||||
private val processingUploadsNotificationTag = BuildConfig.APPLICATION_ID + " : upload_tag"
|
private val processingUploadsNotificationTag = BuildConfig.APPLICATION_ID + " : upload_tag"
|
||||||
|
|
||||||
private val processingUploadsNotificationId = 101
|
private val processingUploadsNotificationId = 101
|
||||||
|
|
@ -379,7 +385,7 @@ class UploadWorker(
|
||||||
saveCompletedContribution(contribution, uploadResult)
|
saveCompletedContribution(contribution, uploadResult)
|
||||||
} else {
|
} else {
|
||||||
Timber.d(
|
Timber.d(
|
||||||
"WikiDataEdit not required, making wikidata edit",
|
"WikiDataEdit required, making wikidata edit",
|
||||||
)
|
)
|
||||||
makeWikiDataEdit(uploadResult, contribution)
|
makeWikiDataEdit(uploadResult, contribution)
|
||||||
}
|
}
|
||||||
|
|
@ -432,7 +438,7 @@ class UploadWorker(
|
||||||
username,
|
username,
|
||||||
)
|
)
|
||||||
CommonsApplication
|
CommonsApplication
|
||||||
.getInstance()
|
.instance!!
|
||||||
.clearApplicationData(appContext, logoutListener)
|
.clearApplicationData(appContext, logoutListener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -471,6 +477,16 @@ class UploadWorker(
|
||||||
contribution.media.captions,
|
contribution.media.captions,
|
||||||
)
|
)
|
||||||
if (null != revisionID) {
|
if (null != revisionID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val place = placesRepository.fetchPlace(wikiDataPlace.id);
|
||||||
|
place.name = wikiDataPlace.name;
|
||||||
|
place.pic = HOME_URL + uploadResult.createCanonicalFileName()
|
||||||
|
placesRepository
|
||||||
|
.save(place)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.blockingAwait()
|
||||||
|
Timber.d("Updated WikiItem place ${place.name} with image ${place.pic}")
|
||||||
|
}
|
||||||
showSuccessNotification(contribution)
|
showSuccessNotification(contribution)
|
||||||
}
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -518,7 +534,7 @@ class UploadWorker(
|
||||||
contribution.contentUri?.let {
|
contribution.contentUri?.let {
|
||||||
val imageSha1 = contribution.imageSHA1.toString()
|
val imageSha1 = contribution.imageSHA1.toString()
|
||||||
val modifiedSha1 = fileUtilsWrapper.getSHA1(fileUtilsWrapper.getFileInputStream(contribution.localUri?.path))
|
val modifiedSha1 = fileUtilsWrapper.getSHA1(fileUtilsWrapper.getFileInputStream(contribution.localUri?.path))
|
||||||
MainScope().launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
uploadedStatusDao.insertUploaded(
|
uploadedStatusDao.insertUploaded(
|
||||||
UploadedStatus(
|
UploadedStatus(
|
||||||
imageSha1,
|
imageSha1,
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,7 @@ public class PermissionUtils {
|
||||||
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
final Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
final Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
||||||
intent.setData(uri);
|
intent.setData(uri);
|
||||||
activity.startActivityForResult(intent,
|
activity.startActivity(intent);
|
||||||
CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
18
app/src/main/res/drawable/ic_refresh_24dp_nearby.xml
Normal file
18
app/src/main/res/drawable/ic_refresh_24dp_nearby.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="@dimen/half_standard_height"
|
||||||
|
android:height="@dimen/half_standard_height"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:scaleX="1.0"
|
||||||
|
android:scaleY="1.0"
|
||||||
|
android:translateX="-0.0"
|
||||||
|
android:translateY="-0.0">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/menu_item_tint"
|
||||||
|
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
|
|
@ -36,11 +36,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:contentDescription="@string/exit_location_picker"
|
android:contentDescription="@string/exit_location_picker"
|
||||||
android:tint="@color/white"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_arrow_back_white" />
|
app:srcCompat="@drawable/ic_arrow_back_white"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
android:id="@+id/btn_edit_submit"
|
android:id="@+id/btn_edit_submit"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:text="@string/submit"
|
android:text="@string/submit"
|
||||||
android:textColor="@android:color/white" />
|
android:textColor="@android:color/white" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:layout_marginRight="50dp"
|
android:layout_marginEnd="50dp"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
/>
|
/>
|
||||||
|
|
@ -58,6 +58,7 @@
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
android:padding="@dimen/standard_gap"
|
android:padding="@dimen/standard_gap"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
|
|
@ -69,8 +70,7 @@
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:duplicateParentState="true"
|
android:duplicateParentState="true"
|
||||||
app:srcCompat="@drawable/ic_directions_black_24dp"
|
app:srcCompat="@drawable/ic_directions_black_24dp"
|
||||||
android:tint="?attr/rowButtonColor"
|
app:tint="?attr/rowButtonColor" />
|
||||||
/>
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
@ -89,6 +89,7 @@
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
android:padding="@dimen/standard_gap"
|
android:padding="@dimen/standard_gap"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
|
|
@ -118,6 +119,7 @@
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
android:padding="@dimen/standard_gap"
|
android:padding="@dimen/standard_gap"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
|
|
@ -153,8 +155,8 @@
|
||||||
android:id="@+id/description"
|
android:id="@+id/description"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/large_height"
|
android:layout_marginStart="@dimen/large_height"
|
||||||
android:layout_marginRight="@dimen/standard_gap"
|
android:layout_marginEnd="@dimen/standard_gap"
|
||||||
android:layout_marginBottom="@dimen/standard_gap"
|
android:layout_marginBottom="@dimen/standard_gap"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/bookmarkButton"
|
android:id="@+id/bookmarkButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_columnWeight="1"
|
android:layout_columnWeight="1"
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/standard_gap">
|
android:padding="@dimen/standard_gap">
|
||||||
|
|
||||||
|
|
@ -14,7 +16,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:tint="?attr/rowButtonColor" />
|
app:tint="?attr/rowButtonColor" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/buttonText"
|
android:id="@+id/buttonText"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/toolbar"
|
|
||||||
android:background="?attr/achievementBackground"
|
android:background="?attr/achievementBackground"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
|
@ -36,7 +35,6 @@
|
||||||
style="?android:textAppearanceLarge"
|
style="?android:textAppearanceLarge"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:text="@string/level"
|
android:text="@string/level"
|
||||||
|
|
@ -48,13 +46,11 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/black"
|
android:layout_marginVertical="@dimen/activity_margin_vertical"
|
||||||
android:layout_marginVertical="@dimen/activity_margin_vertical" />
|
app:tint="@color/black" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/badge_layout"
|
android:id="@+id/badge_layout"
|
||||||
|
|
@ -108,7 +104,6 @@
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:id="@+id/images_upload_text_param"
|
android:id="@+id/images_upload_text_param"
|
||||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||||
|
|
@ -120,12 +115,10 @@
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
android:layout_toRightOf="@+id/images_upload_text_param"
|
|
||||||
android:layout_toEndOf="@+id/images_upload_text_param"
|
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor"
|
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
@ -189,7 +182,6 @@
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:id="@+id/images_reverted_text"
|
android:id="@+id/images_reverted_text"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:text="@string/image_reverts" />
|
android:text="@string/image_reverts" />
|
||||||
|
|
@ -200,24 +192,19 @@
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
android:layout_toRightOf="@+id/images_reverted_text"
|
|
||||||
android:layout_toEndOf="@+id/images_reverted_text"
|
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor"
|
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
android:layout_marginStart="@dimen/activity_margin_horizontal" app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/achievements_revert_limit_message"
|
android:text="@string/achievements_revert_limit_message"
|
||||||
android:textSize="@dimen/small_text"
|
android:textSize="@dimen/small_text"
|
||||||
android:id="@+id/images_revert_limit_text"
|
android:id="@+id/images_revert_limit_text"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_below="@id/images_reverted_info"/>
|
android:layout_below="@id/images_reverted_info"/>
|
||||||
|
|
||||||
|
|
@ -278,7 +265,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/images_used_by_wiki_text"
|
android:id="@+id/images_used_by_wiki_text"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||||
android:text="@string/images_used_by_wiki" />
|
android:text="@string/images_used_by_wiki" />
|
||||||
|
|
@ -289,12 +275,10 @@
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
android:layout_toRightOf="@+id/images_used_by_wiki_text"
|
|
||||||
android:layout_toEndOf="@+id/images_used_by_wiki_text"
|
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor"
|
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"/>
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
@ -353,7 +337,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/statistics"
|
android:text="@string/statistics"
|
||||||
style="?android:textAppearanceLarge"
|
style="?android:textAppearanceLarge"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||||
android:textAllCaps="true"/>
|
android:textAllCaps="true"/>
|
||||||
|
|
@ -373,9 +356,7 @@
|
||||||
android:id="@+id/images_nearby_info"
|
android:id="@+id/images_nearby_info"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toStartOf="@+id/wikidata_edits"
|
android:layout_toStartOf="@+id/wikidata_edits"
|
||||||
android:layout_toLeftOf="@+id/wikidata_edits"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
|
@ -407,14 +388,13 @@
|
||||||
android:layout_height="@dimen/medium_height"
|
android:layout_height="@dimen/medium_height"
|
||||||
android:id="@+id/images_nearby_info_icon"
|
android:id="@+id/images_nearby_info_icon"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
app:layout_constraintLeft_toRightOf="@id/images_nearby_data"
|
app:layout_constraintLeft_toRightOf="@id/images_nearby_data"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor" />
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -423,16 +403,14 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/half_standard_height"
|
android:layout_marginEnd="@dimen/half_standard_height"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
tools:text="2"
|
tools:text="2"
|
||||||
android:id="@+id/wikidata_edits"
|
android:id="@+id/wikidata_edits"
|
||||||
android:layout_marginRight="@dimen/half_standard_height" />
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
@ -451,9 +429,7 @@
|
||||||
android:id="@+id/images_featured_info"
|
android:id="@+id/images_featured_info"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toStartOf="@+id/image_featured"
|
android:layout_toStartOf="@+id/image_featured"
|
||||||
android:layout_toLeftOf="@+id/image_featured"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
|
@ -486,14 +462,13 @@
|
||||||
android:layout_height="@dimen/medium_height"
|
android:layout_height="@dimen/medium_height"
|
||||||
android:id="@+id/images_featured_info_icon"
|
android:id="@+id/images_featured_info_icon"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
app:layout_constraintLeft_toRightOf="@id/images_featured_data"
|
app:layout_constraintLeft_toRightOf="@id/images_featured_data"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor" />
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -501,16 +476,14 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
tools:text="2"
|
tools:text="2"
|
||||||
android:id="@+id/image_featured"
|
android:id="@+id/image_featured"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/half_standard_height"
|
android:layout_marginEnd="@dimen/half_standard_height"
|
||||||
android:layout_marginRight="@dimen/half_standard_height" />
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
@ -529,9 +502,7 @@
|
||||||
android:id="@+id/quality_images_info"
|
android:id="@+id/quality_images_info"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toStartOf="@+id/quality_images"
|
android:layout_toStartOf="@+id/quality_images"
|
||||||
android:layout_toLeftOf="@+id/quality_images"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
|
@ -564,14 +535,13 @@
|
||||||
android:layout_height="@dimen/medium_height"
|
android:layout_height="@dimen/medium_height"
|
||||||
android:id="@+id/quality_images_info_icon"
|
android:id="@+id/quality_images_info_icon"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
app:layout_constraintLeft_toRightOf="@id/quality_images_data"
|
app:layout_constraintLeft_toRightOf="@id/quality_images_data"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor" />
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -579,7 +549,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
|
|
@ -587,9 +556,8 @@
|
||||||
tools:text="2"
|
tools:text="2"
|
||||||
android:text="0"
|
android:text="0"
|
||||||
android:id="@+id/quality_images"
|
android:id="@+id/quality_images"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/half_standard_height"
|
android:layout_marginEnd="@dimen/half_standard_height"
|
||||||
android:layout_marginRight="@dimen/half_standard_height" />
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
@ -608,9 +576,7 @@
|
||||||
android:id="@+id/thanks_received_info"
|
android:id="@+id/thanks_received_info"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_alignParentStart="true"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toStartOf="@+id/thanks_received"
|
android:layout_toStartOf="@+id/thanks_received"
|
||||||
android:layout_toLeftOf="@+id/thanks_received"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
|
@ -643,14 +609,13 @@
|
||||||
android:layout_height="@dimen/medium_height"
|
android:layout_height="@dimen/medium_height"
|
||||||
android:id="@+id/thanks_received_info_icon"
|
android:id="@+id/thanks_received_info_icon"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||||
app:layout_constraintLeft_toRightOf="@id/thanks_received_data"
|
app:layout_constraintLeft_toRightOf="@id/thanks_received_data"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
android:tint="@color/primaryLightColor" />
|
app:tint="@color/primaryLightColor" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -658,16 +623,14 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="?android:textAppearanceMedium"
|
style="?android:textAppearanceMedium"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
tools:text="2"
|
tools:text="2"
|
||||||
android:id="@+id/thanks_received"
|
android:id="@+id/thanks_received"
|
||||||
android:layout_marginEnd="@dimen/half_standard_height"
|
android:layout_marginEnd="@dimen/half_standard_height"
|
||||||
android:layout_marginRight="@dimen/half_standard_height" />
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,33 @@
|
||||||
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
||||||
app:useCompatPadding="true" />
|
app:useCompatPadding="true" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab_legend"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/fab_recenter"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:clickable="true"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:backgroundTint="@color/main_background_light"
|
||||||
|
app:elevation="@dimen/dimen_6"
|
||||||
|
app:fabSize="normal"
|
||||||
|
app:layout_anchorGravity="top|right|end"
|
||||||
|
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||||
|
app:useCompatPadding="true" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/nearby_legend_layout"
|
||||||
|
layout="@layout/nearby_legend"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/rl_container_wlm_month_message"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="@dimen/standard_gap"
|
android:layout_margin="@dimen/standard_gap"
|
||||||
android:tint="?attr/rowButtonColor"
|
app:srcCompat="@drawable/ic_round_star_border_24px"
|
||||||
app:srcCompat="@drawable/ic_round_star_border_24px" />
|
app:tint="?attr/rowButtonColor" />
|
||||||
|
|
||||||
<com.facebook.drawee.view.SimpleDraweeView
|
<com.facebook.drawee.view.SimpleDraweeView
|
||||||
android:id="@+id/icon"
|
android:id="@+id/icon"
|
||||||
|
|
@ -30,7 +30,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
android:layout_marginLeft="@dimen/standard_gap"
|
||||||
android:layout_marginRight="@dimen/standard_gap"
|
android:layout_marginRight="@dimen/standard_gap"
|
||||||
android:layout_marginTop="@dimen/standard_gap"
|
android:layout_marginTop="@dimen/standard_gap"
|
||||||
|
|
@ -43,8 +42,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_marginEnd="@dimen/standard_gap"
|
||||||
android:layout_marginRight="@dimen/standard_gap"
|
|
||||||
android:layout_marginTop="@dimen/large_gap"
|
android:layout_marginTop="@dimen/large_gap"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
@ -54,11 +52,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignTop="@id/distance"
|
android:layout_alignTop="@id/distance"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
|
||||||
android:layout_marginStart="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:layout_toEndOf="@id/icon"
|
android:layout_toEndOf="@id/icon"
|
||||||
android:layout_toLeftOf="@id/distance"
|
|
||||||
android:layout_toRightOf="@id/icon"
|
|
||||||
android:layout_toStartOf="@id/distance"
|
android:layout_toStartOf="@id/distance"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
|
|
@ -71,8 +66,6 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignEnd="@id/distance"
|
android:layout_alignEnd="@id/distance"
|
||||||
android:layout_alignLeft="@id/tvName"
|
|
||||||
android:layout_alignRight="@id/distance"
|
|
||||||
android:layout_alignStart="@id/tvName"
|
android:layout_alignStart="@id/tvName"
|
||||||
android:layout_below="@id/tvName"
|
android:layout_below="@id/tvName"
|
||||||
android:layout_marginBottom="@dimen/standard_gap"
|
android:layout_marginBottom="@dimen/standard_gap"
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,14 @@
|
||||||
android:id="@+id/iv_campaign"
|
android:id="@+id/iv_campaign"
|
||||||
android:layout_width="@dimen/dimen_40"
|
android:layout_width="@dimen/dimen_40"
|
||||||
android:layout_height="@dimen/dimen_40"
|
android:layout_height="@dimen/dimen_40"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
|
||||||
android:layout_marginStart="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_campaign"
|
app:srcCompat="@drawable/ic_campaign"
|
||||||
android:tint="?attr/card_item_color"
|
app:tint="?attr/card_item_color" />
|
||||||
/>
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:weightSum="4">
|
android:weightSum="4">
|
||||||
|
|
@ -37,15 +34,13 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:layout_marginRight="@dimen/tiny_margin"
|
android:layout_marginEnd="@dimen/tiny_margin">
|
||||||
android:layout_centerInParent="true"
|
|
||||||
>
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_title"
|
android:id="@+id/tv_title"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:textColor="?attr/card_item_color"
|
android:textColor="?attr/card_item_color"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
tools:text="Campaign Title"
|
tools:text="Campaign Title"
|
||||||
|
|
@ -55,7 +50,7 @@
|
||||||
android:id="@+id/tv_description"
|
android:id="@+id/tv_description"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:paddingTop="@dimen/miniscule_margin"
|
android:paddingTop="@dimen/miniscule_margin"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
|
|
@ -69,7 +64,7 @@
|
||||||
android:id="@+id/tv_dates"
|
android:id="@+id/tv_dates"
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingTop="@dimen/miniscule_margin"
|
android:paddingTop="@dimen/miniscule_margin"
|
||||||
android:text="@string/ends_on"
|
android:text="@string/ends_on"
|
||||||
|
|
|
||||||
|
|
@ -113,9 +113,9 @@
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:padding="@dimen/activity_margin_horizontal"
|
android:padding="@dimen/activity_margin_horizontal"
|
||||||
android:src="@drawable/ic_wikipedia"
|
android:src="@drawable/ic_wikipedia"
|
||||||
android:tint="?attr/contributionsListTextSecondary"
|
|
||||||
android:text="@string/menu_cancel_upload"
|
android:text="@string/menu_cancel_upload"
|
||||||
android:visibility="visible" />
|
android:visibility="visible"
|
||||||
|
app:tint="?attr/contributionsListTextSecondary" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||||
|
|
@ -30,34 +29,28 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/content_layout"
|
android:id="@+id/content_layout"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar" />
|
||||||
android:layout_centerInParent="true"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/nearby_icon"
|
android:id="@+id/nearby_icon"
|
||||||
android:layout_width="@dimen/dimen_40"
|
android:layout_width="@dimen/dimen_40"
|
||||||
android:layout_height="@dimen/dimen_40"
|
android:layout_height="@dimen/dimen_40"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
|
||||||
android:layout_marginStart="@dimen/standard_gap"
|
android:layout_marginStart="@dimen/standard_gap"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_location_white_24dp"
|
app:srcCompat="@drawable/ic_location_white_24dp"
|
||||||
android:tint="?attr/card_item_color"
|
app:tint="?attr/card_item_color" />
|
||||||
/>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:orientation="horizontal"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:weightSum="4"
|
android:weightSum="4"
|
||||||
|
|
@ -68,8 +61,7 @@
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="3"
|
android:layout_weight="3"
|
||||||
android:layout_centerInParent="true"
|
android:layout_marginLeft="@dimen/standard_gap"
|
||||||
android:layout_marginLeft="@dimen/standard_gap"
|
|
||||||
android:layout_marginRight="@dimen/standard_gap"
|
android:layout_marginRight="@dimen/standard_gap"
|
||||||
tools:text="test distance"
|
tools:text="test distance"
|
||||||
android:textColor="?attr/card_item_color"
|
android:textColor="?attr/card_item_color"
|
||||||
|
|
|
||||||
74
app/src/main/res/layout/nearby_legend.xml
Normal file
74
app/src/main/res/layout/nearby_legend.xml
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#BFFFFFFF"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageRed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/imageGreen"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/imageGreen"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/imageGreen"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker_red" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textRed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:text="@string/red_pin"
|
||||||
|
android:textColor="#F74D4D"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/imageRed"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageRed"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/imageRed" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageGreen"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/imageGrey"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/imageGrey"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/imageGrey"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker_green" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textGreen"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:text="@string/green_pin"
|
||||||
|
android:textColor="#1F7123"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/imageGreen"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageGreen"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/imageGreen" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageGrey"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_custom_map_marker_grey" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textGrey"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/grey_pin"
|
||||||
|
android:textColor="#454547"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/imageGrey"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/imageGrey"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/imageGrey" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/standard_gap">
|
android:padding="@dimen/standard_gap">
|
||||||
|
|
||||||
|
|
@ -24,8 +25,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:tint="?attr/bookmarkButtonColor"
|
app:srcCompat="@drawable/ic_photo_camera_white_24dp"
|
||||||
app:srcCompat="@drawable/ic_photo_camera_white_24dp" />
|
app:tint="?attr/bookmarkButtonColor" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/cameraButtonText"
|
android:id="@+id/cameraButtonText"
|
||||||
|
|
@ -45,6 +46,7 @@
|
||||||
android:background="@drawable/button_background_selector"
|
android:background="@drawable/button_background_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:contentDescription="@string/nearby_row_image"
|
android:contentDescription="@string/nearby_row_image"
|
||||||
|
android:focusable="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/standard_gap">
|
android:padding="@dimen/standard_gap">
|
||||||
|
|
||||||
|
|
@ -53,8 +55,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:duplicateParentState="true"
|
android:duplicateParentState="true"
|
||||||
android:tint="?attr/bookmarkButtonColor"
|
app:srcCompat="@drawable/ic_photo_white_24dp"
|
||||||
app:srcCompat="@drawable/ic_photo_white_24dp" />
|
app:tint="?attr/bookmarkButtonColor" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/galleryButtonText"
|
android:id="@+id/galleryButtonText"
|
||||||
|
|
@ -72,6 +74,7 @@
|
||||||
android:layout_width="@dimen/dimen_0"
|
android:layout_width="@dimen/dimen_0"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
android:padding="@dimen/standard_gap"
|
android:padding="@dimen/standard_gap"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
|
@ -82,8 +85,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
app:srcCompat="@drawable/ic_directions_black_24dp"
|
app:srcCompat="@drawable/ic_directions_black_24dp"
|
||||||
android:tint="?attr/bookmarkButtonColor"
|
android:duplicateParentState="true"
|
||||||
android:duplicateParentState="true"/>
|
app:tint="?attr/bookmarkButtonColor" />
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
@ -102,6 +105,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="@dimen/standard_gap">
|
android:padding="@dimen/standard_gap">
|
||||||
|
|
||||||
|
|
@ -110,8 +114,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:duplicateParentState="true"
|
android:duplicateParentState="true"
|
||||||
android:tint="?attr/bookmarkButtonColor"
|
app:srcCompat="@drawable/ic_overflow"
|
||||||
app:srcCompat="@drawable/ic_overflow" />
|
app:tint="?attr/bookmarkButtonColor" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/iconOverflowText"
|
android:id="@+id/iconOverflowText"
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:contentDescription="@string/exit_location_picker"
|
android:contentDescription="@string/exit_location_picker"
|
||||||
android:tint="@color/white"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_arrow_back_white"/>
|
app:srcCompat="@drawable/ic_arrow_back_white"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -1,17 +1,25 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item android:id="@+id/item_refresh"
|
||||||
|
android:title="Refresh"
|
||||||
|
app:showAsAction="ifRoom"
|
||||||
|
android:icon="@drawable/ic_refresh_24dp_nearby" />
|
||||||
|
|
||||||
<item android:id="@+id/list_sheet"
|
<item android:id="@+id/list_sheet"
|
||||||
android:title="@string/list_sheet"
|
android:title="@string/list_sheet"
|
||||||
app:showAsAction="ifRoom|withText"
|
app:showAsAction="ifRoom|withText"
|
||||||
android:icon="@drawable/ic_list_white_24dp"
|
android:icon="@drawable/ic_list_white_24dp"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<item android:id="@+id/list_item_gpx"
|
<item android:id="@+id/list_item_gpx"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:title="Save as GPX file" />
|
android:title="Save as GPX file" />
|
||||||
|
|
||||||
<item android:id="@+id/list_item_kml"
|
<item android:id="@+id/list_item_kml"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:title="Save as KML file" />
|
android:title="Save as KML file" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,7 @@
|
||||||
<string name="no_notification">ليس لديك أي إشعارات غير مقروءة</string>
|
<string name="no_notification">ليس لديك أي إشعارات غير مقروءة</string>
|
||||||
<string name="no_read_notification">ليس لديك أي إشعاراتٍ غير مقروءة</string>
|
<string name="no_read_notification">ليس لديك أي إشعاراتٍ غير مقروءة</string>
|
||||||
<string name="share_logs_using">مشاركة السجلات باستخدام</string>
|
<string name="share_logs_using">مشاركة السجلات باستخدام</string>
|
||||||
|
<string name="check_your_email_inbox">تحقق من صندوق بريدك الإلكتروني</string>
|
||||||
<string name="menu_option_read">عرض المقروءة</string>
|
<string name="menu_option_read">عرض المقروءة</string>
|
||||||
<string name="menu_option_unread">عرض غير المقروءة</string>
|
<string name="menu_option_unread">عرض غير المقروءة</string>
|
||||||
<string name="error_occurred_in_picking_images">حدث خطأ أثناء التقاط الصور</string>
|
<string name="error_occurred_in_picking_images">حدث خطأ أثناء التقاط الصور</string>
|
||||||
|
|
@ -690,6 +691,7 @@
|
||||||
<string name="leaderboard_nearby">مجاور</string>
|
<string name="leaderboard_nearby">مجاور</string>
|
||||||
<string name="leaderboard_used">مستخدَم</string>
|
<string name="leaderboard_used">مستخدَم</string>
|
||||||
<string name="leaderboard_my_rank_button_text">ترتيبي</string>
|
<string name="leaderboard_my_rank_button_text">ترتيبي</string>
|
||||||
|
<string name="map_attribution">&#169; <a href=\"https://www.openstreetmap.org/copyright\">خريطة الشارع المفتوحة</a></string>
|
||||||
<string name="limited_connection_enabled">وضع الاتصال المحدود مُمَكَّن!</string>
|
<string name="limited_connection_enabled">وضع الاتصال المحدود مُمَكَّن!</string>
|
||||||
<string name="limited_connection_disabled">وضع الاتصال المحدود مُعطل. سيجري استئناف التحميلات المعلقة الآن.</string>
|
<string name="limited_connection_disabled">وضع الاتصال المحدود مُعطل. سيجري استئناف التحميلات المعلقة الآن.</string>
|
||||||
<string name="limited_connection_mode">وضع الاتصال المحدود</string>
|
<string name="limited_connection_mode">وضع الاتصال المحدود</string>
|
||||||
|
|
@ -739,6 +741,7 @@
|
||||||
<string name="custom_selector_dismiss_limit_warning_button_text">رفض</string>
|
<string name="custom_selector_dismiss_limit_warning_button_text">رفض</string>
|
||||||
<string name="custom_selector_button_limit_text">الحد الأقصى: %1$d</string>
|
<string name="custom_selector_button_limit_text">الحد الأقصى: %1$d</string>
|
||||||
<string name="custom_selector_limit_error_desc">خطأ: تجاوز حد التحميل</string>
|
<string name="custom_selector_limit_error_desc">خطأ: تجاوز حد التحميل</string>
|
||||||
|
<string name="place_state_wlm">دبليو إل إم</string>
|
||||||
<string name="wlm_upload_info">سيتم إدخال هذه الصورة في مسابقة Wiki Loves Monuments</string>
|
<string name="wlm_upload_info">سيتم إدخال هذه الصورة في مسابقة Wiki Loves Monuments</string>
|
||||||
<string name="display_monuments">عرض الآثار</string>
|
<string name="display_monuments">عرض الآثار</string>
|
||||||
<string name="wlm_month_message">إنه شهر Wiki Loves Monuments!</string>
|
<string name="wlm_month_message">إنه شهر Wiki Loves Monuments!</string>
|
||||||
|
|
@ -788,16 +791,66 @@
|
||||||
<string name="image_selected">تم تحديد الصورة</string>
|
<string name="image_selected">تم تحديد الصورة</string>
|
||||||
<string name="image_marked_as_not_for_upload">تم وضع علامة على الصورة على أنها ليست للتحميل</string>
|
<string name="image_marked_as_not_for_upload">تم وضع علامة على الصورة على أنها ليست للتحميل</string>
|
||||||
<string name="menu_view_report">تقرير</string>
|
<string name="menu_view_report">تقرير</string>
|
||||||
|
<string name="menu_view_set_white_background">تعيين الخلفية البيضاء</string>
|
||||||
|
<string name="menu_view_set_black_background">تعيين خلفية سوداء</string>
|
||||||
<string name="report_violation">تبليغ عن عنف</string>
|
<string name="report_violation">تبليغ عن عنف</string>
|
||||||
<string name="report_user">أخطر عن هذا المستخدم</string>
|
<string name="report_user">أخطر عن هذا المستخدم</string>
|
||||||
<string name="report_content">الإبلاغ عن هذا المحتوى</string>
|
<string name="report_content">الإبلاغ عن هذا المحتوى</string>
|
||||||
<string name="request_user_block">طلب منع هذا المستخدم</string>
|
<string name="request_user_block">طلب منع هذا المستخدم</string>
|
||||||
<string name="welcome_to_full_screen_mode_text">مرحبًا بك في وضع التحديد بملء الشاشة</string>
|
<string name="welcome_to_full_screen_mode_text">مرحبًا بك في وضع التحديد بملء الشاشة</string>
|
||||||
<string name="full_screen_mode_zoom_info">استخدم إصبعين للتكبير والتصغير.</string>
|
<string name="full_screen_mode_zoom_info">استخدم إصبعين للتكبير والتصغير.</string>
|
||||||
<string name="full_screen_mode_features_info" fuzzy="true">مرر سريعًا وطويلًا لتنفيذ هذه الإجراءات:! N! - يسار / يمين: انتقل إلى السابق / التالي! N! - لأعلى: حدد! N! - أسفل: وضع علامة على أنه ليس للتحميل.</string>
|
<string name="full_screen_mode_features_info">مرر سريعًا وطويلًا لأداء هذه الإجراءات: \n- يسار/يمين: الانتقال إلى السابق/التالي \n- أعلى: تحديد\n- أسفل: وضع علامة على عدم التحميل.</string>
|
||||||
|
<string name="set_up_avatar_toast_string">لإعداد صورتك الرمزية في قائمة المتصدرين، اضغط على \"تعيين كصورة رمزية\" في قائمة النقاط الثلاث لأي صورة.</string>
|
||||||
|
<string name="similar_coordinate_description_auto_set">الإحداثيات ليست إحداثيات دقيقة، لكن الشخص الذي قام بتحميل هذه الصورة يعتقد أنها قريبة بما فيه الكفاية.</string>
|
||||||
<string name="storage_permissions_denied">رُفض إذن التخزين</string>
|
<string name="storage_permissions_denied">رُفض إذن التخزين</string>
|
||||||
<string name="unable_to_share_upload_item">تعذر مشاركة هذا العنصر</string>
|
<string name="unable_to_share_upload_item">تعذر مشاركة هذا العنصر</string>
|
||||||
<string name="permissions_are_required_for_functionality">الإذن مطلوب لهذه الوظيفة</string>
|
<string name="permissions_are_required_for_functionality">الإذن مطلوب لهذه الوظيفة</string>
|
||||||
|
<string name="learn_how_to_write_a_useful_description">تعلم كيفية كتابة وصف مفيد</string>
|
||||||
|
<string name="learn_how_to_write_a_useful_caption">تعلم كيفية كتابة تعليق مفيد</string>
|
||||||
|
<string name="see_your_achievements">شاهد إنجازاتك</string>
|
||||||
|
<string name="edit_image">تعديل الصورة</string>
|
||||||
|
<string name="edit_location">تعديل الموقع</string>
|
||||||
|
<string name="location_updated">تم تحديث الموقع!</string>
|
||||||
|
<string name="remove_location">إزالة الموقع</string>
|
||||||
|
<string name="remove_location_warning_title">إزالة تحذير الموقع</string>
|
||||||
|
<string name="remove_location_warning_desc">يجعل تحديد الموقع الصور أكثر فائدة وسهولة في العثور عليها. هل ترغب حقًا في إزالة تحديد الموقع من هذه الصورة؟</string>
|
||||||
|
<string name="location_removed">تمت إزالة الموقع!</string>
|
||||||
<string name="send_thanks_to_author">اشكر المؤلف</string>
|
<string name="send_thanks_to_author">اشكر المؤلف</string>
|
||||||
<string name="error_sending_thanks">حدث خطأ أثناء إرسال الشكر للمؤلف.</string>
|
<string name="error_sending_thanks">حدث خطأ أثناء إرسال الشكر للمؤلف.</string>
|
||||||
|
<string name="invalid_login_message">لقد انتهت صلاحية تسجيل الدخول الخاص بك. يرجى تسجيل الدخول مرة أخرى.</string>
|
||||||
|
<string name="no_application_available_to_open_gpx_files">لا يوجد تطبيق متاح لفتح ملفات GPX</string>
|
||||||
|
<string name="file_saved_successfully">تم حفظ الملف بنجاح</string>
|
||||||
|
<string name="do_you_want_to_open_gpx_file">هل تريد فتح ملف GPX؟</string>
|
||||||
|
<string name="do_you_want_to_open_kml_file">هل تريد فتح ملف KML؟</string>
|
||||||
|
<string name="failed_to_save_kml_file">فشل في حفظ ملف KML.</string>
|
||||||
|
<string name="failed_to_save_gpx_file">فشل في حفظ ملف GPX.</string>
|
||||||
|
<string name="saving_kml_file">حفظ ملف KML</string>
|
||||||
|
<string name="saving_gpx_file">حفظ ملف GPX</string>
|
||||||
|
<plurals name="custom_picker_images_selected_title_appendix">
|
||||||
|
<item quantity="zero">لا صور تم اختيارها</item>
|
||||||
|
<item quantity="one">%d صورة تم اختيارها</item>
|
||||||
|
<item quantity="two">صورتان تم اختيارهما</item>
|
||||||
|
<item quantity="few">صور قليلة تم اختيارها</item>
|
||||||
|
<item quantity="many">صور كثيرة تم اختيارها</item>
|
||||||
|
<item quantity="other">%d صور تم اختيارها</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="multiple_files_depiction">يرجى تذكر أن جميع الصور في التحميل المتعدد تحصل على نفس الفئات والأوصاف. إذا لم تتشارك الصور في الأوصاف والفئات، فيرجى إجراء عدة عمليات تحميل منفصلة.</string>
|
||||||
|
<string name="multiple_files_depiction_header">ملاحظة حول التحميلات المتعددة</string>
|
||||||
|
<string name="nearby_wikitalk">الإبلاغ عن مشكلة حول هذا العنصر إلى Wikidata</string>
|
||||||
|
<string name="please_enter_some_comments">الرجاء إدخال بعض التعليقات</string>
|
||||||
|
<string name="talk">نقاش</string>
|
||||||
|
<string name="write_something_about_the_item">اكتب شيئًا عن العنصر \'%1$s\'. سيكون مرئيًا للعامة.</string>
|
||||||
|
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\'%1$s\' لم يعد موجودًا، ولا يمكن التقاط صورة له أبدًا.</string>
|
||||||
|
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' موجود في مكان مختلف. يرجى تحديد المكان الصحيح أدناه، وإذا أمكن، اكتب خط العرض وخط الطول الصحيحين.</string>
|
||||||
|
<string name="other_problem_or_information_please_explain_below">مشكلة أو معلومات أخرى (يرجى التوضيح أدناه).</string>
|
||||||
|
<string name="feedback_destination_note">سيتم نشر تعليقاتك على صفحة الويكي التالية: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a></string>
|
||||||
|
<string name="are_you_sure_that_you_want_cancel_all_the_uploads">هل أنت متأكد أنك تريد إلغاء كافة التحميلات؟</string>
|
||||||
|
<string name="cancelling_all_the_uploads">إلغاء كافة التحميلات...</string>
|
||||||
|
<string name="uploads">المرفوعات</string>
|
||||||
|
<string name="pending">قيد الانتظار</string>
|
||||||
|
<string name="failed">فشل</string>
|
||||||
|
<string name="could_not_load_place_data">تعذر تحميل بيانات المكان</string>
|
||||||
|
<string name="red_pin">هذا المكان ليس له صورة بعد، اذهب والتقط واحدة!</string>
|
||||||
|
<string name="green_pin">هذا المكان لديه صورة بالفعل.</string>
|
||||||
|
<string name="grey_pin">الآن التحقق ما إذا كان هذا المكان لديه صورة.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
<!-- Authors:
|
<!-- Authors:
|
||||||
* Dağlı95
|
* Dağlı95
|
||||||
* Khan27
|
* Khan27
|
||||||
|
* Nemoralis
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<string name="crash_dialog_title">Nasazlıq</string>
|
<string name="crash_dialog_title">Nasazlıq</string>
|
||||||
<string name="crash_dialog_text">Uups. Nəsə düzgün çalışmır!</string>
|
<string name="crash_dialog_text">Uups. Nəsə düzgün çalışmır!</string>
|
||||||
<string name="crash_dialog_comment_prompt">Nə etdiyinizi dəqiqləşdirib, bizə bildirin və sonra e-poçtla bizə göndərin. Bu problemi həll etməyə bizə kömək edin.</string>
|
<string name="crash_dialog_comment_prompt">Nə etdiyinizi bizə deyin, sonra e-poçt vasitəsilə bizimlə paylaşın. Bu, bizə bunu düzəltməyə kömək edəcək!</string>
|
||||||
<string name="crash_dialog_ok_toast">Təşəkkür!</string>
|
<string name="crash_dialog_ok_toast">Təşəkkürlər!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -12,34 +12,60 @@
|
||||||
* Şeyx Şamil
|
* Şeyx Şamil
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="commons_facebook">Commons Facebook səhifəsi</string>
|
||||||
|
<string name="commons_github">Commons Github Mənbə Kodu</string>
|
||||||
|
<string name="commons_logo">Commons Loqotipi</string>
|
||||||
|
<string name="commons_website">Commons Veb-saytı</string>
|
||||||
|
<string name="exit_location_picker">Məkan seçicidən çıxın</string>
|
||||||
|
<string name="submit">Göndər</string>
|
||||||
|
<string name="add_another_description">Başqa təsvir əlavə et</string>
|
||||||
|
<string name="add_new_contribution">Yeni töhfə</string>
|
||||||
|
<string name="add_contribution_from_camera">Kamera ilə töhfə ver</string>
|
||||||
|
<string name="add_contribution_from_photos">Fotolar ilə töhfə ver</string>
|
||||||
|
<string name="add_contribution_from_contributions_gallery">Əvvəlki töhfələr qalereyasından töhfə əlavə et</string>
|
||||||
|
<string name="show_captions">Başlıqlar</string>
|
||||||
|
<string name="row_item_language_description">Dil təsviri</string>
|
||||||
|
<string name="row_item_caption">Başlıq</string>
|
||||||
|
<string name="show_captions_description">Təsvir</string>
|
||||||
|
<string name="nearby_row_image">Şəkil</string>
|
||||||
|
<string name="nearby_all">Hamısı</string>
|
||||||
|
<string name="nearby_filter_toggle">Aç/Bağla</string>
|
||||||
|
<string name="nearby_filter_search">Axtarış Görünüşü</string>
|
||||||
|
<string name="nearby_filter_state">Məkanın Vəziyyəti</string>
|
||||||
|
<string name="appwidget_img">Günün Şəkli</string>
|
||||||
<plurals name="uploads_pending_notification_indicator">
|
<plurals name="uploads_pending_notification_indicator">
|
||||||
<item quantity="one">%1$d fayl yüklənir</item>
|
<item quantity="one">%1$d fayl yüklənir</item>
|
||||||
<item quantity="other">%1$d fayllar yüklənir</item>
|
<item quantity="other">%1$d fayllar yüklənir</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<plurals name="contributions_subtitle">
|
||||||
|
<item quantity="one">(%1$d)</item>
|
||||||
|
<item quantity="other">(%1$d)</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="starting_uploads">Yükləmələrə Başlanılır</string>
|
||||||
<string name="preference_category_general">Ümumi</string>
|
<string name="preference_category_general">Ümumi</string>
|
||||||
<string name="preference_category_privacy">Məxfilik</string>
|
<string name="preference_category_privacy">Məxfilik</string>
|
||||||
<string name="app_name">Vikimedia Commons</string>
|
<string name="app_name">Vikianbar</string>
|
||||||
<string name="menu_settings">Tənzimləmələr</string>
|
<string name="menu_settings">Tənzimləmələr</string>
|
||||||
<string name="username">Ləqəb</string>
|
<string name="username">İstifadəçi adı</string>
|
||||||
<string name="password">Parol</string>
|
<string name="password">Parol</string>
|
||||||
<string name="login">Daxil ol</string>
|
<string name="login">Daxil ol</string>
|
||||||
<string name="signup">Qeydiyyatdan keç</string>
|
<string name="signup">Qeydiyyatdan keç</string>
|
||||||
<string name="logging_in_title">Giriş edilir</string>
|
<string name="logging_in_title">Giriş edilir</string>
|
||||||
<string name="logging_in_message">Lütfən gözləyin…</string>
|
<string name="logging_in_message">Zəhmət olmasa, gözləyin…</string>
|
||||||
<string name="login_success" fuzzy="true">Daxil oldunuz!</string>
|
<string name="login_success" fuzzy="true">Daxil oldunuz!</string>
|
||||||
<string name="login_failed">Giriş baş tutmadı!</string>
|
<string name="login_failed">Giriş baş tutmadı!</string>
|
||||||
<string name="upload_failed">Fayl tapılmadı. Xahiş edirik başqa bir fayl üzərində cəhd edin.</string>
|
<string name="upload_failed">Fayl tapılmadı. Xahiş edirik başqa bir fayl üzərində cəhd edin.</string>
|
||||||
<string name="authentication_failed" fuzzy="true">Doğrulama alınmadı, xahiş edirəm yenidən daxil olun</string>
|
<string name="authentication_failed" fuzzy="true">Doğrulama alınmadı, xahiş edirəm yenidən daxil olun</string>
|
||||||
<string name="uploading_started">Yükləmə başladı!</string>
|
<string name="uploading_started">Yükləmə başladı!</string>
|
||||||
<string name="upload_completed_notification_title">%1$s yükləndi!</string>
|
<string name="upload_completed_notification_title">%1$s yükləndi!</string>
|
||||||
<string name="upload_completed_notification_text">Yüklədiyini izlə</string>
|
<string name="upload_completed_notification_text">Yükləmənizə baxmaq üçün toxunun</string>
|
||||||
<string name="upload_progress_notification_title_start" fuzzy="true">%1$s yüklənməsi başlanır</string>
|
<string name="upload_progress_notification_title_start" fuzzy="true">%1$s yüklənməsi başlanır</string>
|
||||||
<string name="upload_progress_notification_title_in_progress">%1$s yüklənir</string>
|
<string name="upload_progress_notification_title_in_progress">%1$s yüklənir</string>
|
||||||
<string name="upload_progress_notification_title_finishing">%1$s yüklənməsi başa çatdı</string>
|
<string name="upload_progress_notification_title_finishing">%1$s yüklənməsi başa çatdı</string>
|
||||||
<string name="upload_failed_notification_title" fuzzy="true">%1$s faylının yüklənməsi alınmadı</string>
|
<string name="upload_failed_notification_title" fuzzy="true">%1$s faylının yüklənməsi alınmadı</string>
|
||||||
<string name="upload_failed_notification_subtitle">Baxmaq üçün toxunun</string>
|
<string name="upload_failed_notification_subtitle">Baxmaq üçün toxun</string>
|
||||||
<string name="title_activity_contributions">Yükləmələrim</string>
|
<string name="title_activity_contributions">Son Yükləmələrim</string>
|
||||||
<string name="contribution_state_queued">Sırada</string>
|
<string name="contribution_state_queued">Növbəyə alındı</string>
|
||||||
<string name="contribution_state_failed">Uğursuz</string>
|
<string name="contribution_state_failed">Uğursuz</string>
|
||||||
<string name="contribution_state_in_progress">%1$d%% tamamlandı</string>
|
<string name="contribution_state_in_progress">%1$d%% tamamlandı</string>
|
||||||
<string name="contribution_state_starting">Yüklənir</string>
|
<string name="contribution_state_starting">Yüklənir</string>
|
||||||
|
|
@ -52,15 +78,15 @@
|
||||||
<string name="share_description_hint">Açıqlama</string>
|
<string name="share_description_hint">Açıqlama</string>
|
||||||
<string name="login_failed_network" fuzzy="true">Daxil olmaq olmur — şəbəkə xətası</string>
|
<string name="login_failed_network" fuzzy="true">Daxil olmaq olmur — şəbəkə xətası</string>
|
||||||
<string name="login_failed_throttled">Çox sayda uğursuz daxil olma. Xahiş edirik bir neçə dəqiqə sonra yenidən cəhd edin.</string>
|
<string name="login_failed_throttled">Çox sayda uğursuz daxil olma. Xahiş edirik bir neçə dəqiqə sonra yenidən cəhd edin.</string>
|
||||||
<string name="login_failed_blocked">Bağışlayın, bu istifadəçi Commons-da bloklanmışdır.</string>
|
<string name="login_failed_blocked">Bağışlayın, bu istifadəçi Vikianbardan bloklanıb</string>
|
||||||
<string name="login_failed_2fa_needed">İki faktorlu giriş doğrulama kodunu verməlisiniz.</string>
|
<string name="login_failed_2fa_needed">Siz iki faktorlu autentifikasiya kodunuzu təqdim etməlisiniz.</string>
|
||||||
<string name="login_failed_generic" fuzzy="true">Daxil olma uğursuz oldu</string>
|
<string name="login_failed_generic" fuzzy="true">Daxil olma uğursuz oldu</string>
|
||||||
<string name="share_upload_button">Yüklə</string>
|
<string name="share_upload_button">Yüklə</string>
|
||||||
<string name="multiple_share_base_title">Bu dəsti adlandırın</string>
|
<string name="multiple_share_base_title">Bu dəsti adlandırın</string>
|
||||||
<string name="provider_modifications">Bildirişlər</string>
|
<string name="provider_modifications">Dəyişikliklər</string>
|
||||||
<string name="menu_upload_single">Yüklə</string>
|
<string name="menu_upload_single">Yüklə</string>
|
||||||
<string name="categories_search_text_hint">Kateqoriyaları axtar</string>
|
<string name="categories_search_text_hint">Kateqoriyalarda axtar</string>
|
||||||
<string name="menu_save_categories">Qeyd et</string>
|
<string name="menu_save_categories">Yadda saxla</string>
|
||||||
<string name="refresh_button">Yenilə</string>
|
<string name="refresh_button">Yenilə</string>
|
||||||
<string name="display_list_button">Siyahı</string>
|
<string name="display_list_button">Siyahı</string>
|
||||||
<string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string>
|
<string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string>
|
||||||
|
|
|
||||||
|
|
@ -307,4 +307,5 @@
|
||||||
<string name="please_wait">Моля, изчакайте...</string>
|
<string name="please_wait">Моля, изчакайте...</string>
|
||||||
<string name="delete_helper_ask_spam_blurry">напълно размазано</string>
|
<string name="delete_helper_ask_spam_blurry">напълно размазано</string>
|
||||||
<string name="leaderboard_nearby">Наблизо</string>
|
<string name="leaderboard_nearby">Наблизо</string>
|
||||||
|
<string name="read_help_link">Прочетете повече</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -242,8 +242,8 @@
|
||||||
<string name="nominated_for_deletion">Meneget eo bet ar skeudenn evit lemel.</string>
|
<string name="nominated_for_deletion">Meneget eo bet ar skeudenn evit lemel.</string>
|
||||||
<string name="skip_login">Lezel a-gostez</string>
|
<string name="skip_login">Lezel a-gostez</string>
|
||||||
<string name="navigation_item_login">Kevreañ</string>
|
<string name="navigation_item_login">Kevreañ</string>
|
||||||
<string name="skip_login_title" fuzzy="true">Ha c\'hoant ho peus, evit gwir, da gevreañ ?</string>
|
<string name="skip_login_title">Ha n\'ho peus ket c\'hoant, evit gwir, da gevreañ ?</string>
|
||||||
<string name="skip_login_message" fuzzy="true">Da gevreañ ho po en amzer-da-zont evit pellgargañ skeudennoù.</string>
|
<string name="skip_login_message">Ret e vo deoc\'h kevreañ en amzer-da-zont evit pellgargañ skeudennoù.</string>
|
||||||
<string name="login_alert_message">Kevreit, mar plij, evit implijout an arc\'hwel-mañ</string>
|
<string name="login_alert_message">Kevreit, mar plij, evit implijout an arc\'hwel-mañ</string>
|
||||||
<string name="copy_wikicode">Eilañ an destenn wiki er golver</string>
|
<string name="copy_wikicode">Eilañ an destenn wiki er golver</string>
|
||||||
<string name="wikicode_copied">Testenn wiki eilet er golver</string>
|
<string name="wikicode_copied">Testenn wiki eilet er golver</string>
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@
|
||||||
<string name="menu_view_file_page">Хьажа файлан агӀоне</string>
|
<string name="menu_view_file_page">Хьажа файлан агӀоне</string>
|
||||||
<string name="share_title_hint">Куьг йазор (ТIедилина ду)</string>
|
<string name="share_title_hint">Куьг йазор (ТIедилина ду)</string>
|
||||||
<string name="add_caption_toast">Дехар ду, хӀокху файлан цIе гайта</string>
|
<string name="add_caption_toast">Дехар ду, хӀокху файлан цIе гайта</string>
|
||||||
<string name="share_description_hint">Цунах лаьцна</string>
|
<string name="share_description_hint">Цуьнах лаьцна</string>
|
||||||
<string name="share_caption_hint">Куьг</string>
|
<string name="share_caption_hint">Куьг</string>
|
||||||
<string name="login_failed_network">Чувала(йала) тара цало — сетан гӀалат</string>
|
<string name="login_failed_network">Чувала(йала) тара цало — сетан гӀалат</string>
|
||||||
<string name="login_failed_throttled">ТӀех дукха кхиаме боцу гӀертарш. Дехар ду масех минот йаьлча йуха а хьажа.</string>
|
<string name="login_failed_throttled">ТӀех дукха кхиаме боцу гӀертарш. Дехар ду масех минот йаьлча йуха а хьажа.</string>
|
||||||
|
|
|
||||||
|
|
@ -481,6 +481,7 @@
|
||||||
<string name="no_notification">Du har ingen ulæste notifikationer</string>
|
<string name="no_notification">Du har ingen ulæste notifikationer</string>
|
||||||
<string name="no_read_notification">Du har ingen læste notifikationer</string>
|
<string name="no_read_notification">Du har ingen læste notifikationer</string>
|
||||||
<string name="share_logs_using">Del logs ved hjælp af</string>
|
<string name="share_logs_using">Del logs ved hjælp af</string>
|
||||||
|
<string name="check_your_email_inbox">Tjek din e-mail-indbakke</string>
|
||||||
<string name="menu_option_read">Vis læste</string>
|
<string name="menu_option_read">Vis læste</string>
|
||||||
<string name="menu_option_unread">Vis ulæste</string>
|
<string name="menu_option_unread">Vis ulæste</string>
|
||||||
<string name="error_occurred_in_picking_images">Der opstod en fejl under udvælgelse af billeder</string>
|
<string name="error_occurred_in_picking_images">Der opstod en fejl under udvælgelse af billeder</string>
|
||||||
|
|
@ -788,4 +789,7 @@
|
||||||
<string name="pending">Afventer</string>
|
<string name="pending">Afventer</string>
|
||||||
<string name="failed">Mislykkedes</string>
|
<string name="failed">Mislykkedes</string>
|
||||||
<string name="could_not_load_place_data">Kunne ikke indlæse steddata</string>
|
<string name="could_not_load_place_data">Kunne ikke indlæse steddata</string>
|
||||||
|
<string name="red_pin">Dette sted har endnu ikke noget billede, så gå hen og tag et!</string>
|
||||||
|
<string name="green_pin">Dette sted har allerede et billede.</string>
|
||||||
|
<string name="grey_pin">Tjekker nu, om dette sted har et billede.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
* Sujan
|
* Sujan
|
||||||
* Sushi
|
* Sushi
|
||||||
* Tacsipacsi
|
* Tacsipacsi
|
||||||
|
* TheRabbit22
|
||||||
* ThisCarthing
|
* ThisCarthing
|
||||||
* Tobi 406
|
* Tobi 406
|
||||||
* TomatoCake
|
* TomatoCake
|
||||||
|
|
@ -802,4 +803,17 @@
|
||||||
<string name="multiple_files_depiction">Bitte beachte, dass bei einem Multiupload alle Bilder die gleichen Kategorien und Bezeichnungen erhalten. Sollten die Bilder keine gemeinsamen Bezeichnungen und Kategorien haben, führe bitte mehrere separate Uploads durch.</string>
|
<string name="multiple_files_depiction">Bitte beachte, dass bei einem Multiupload alle Bilder die gleichen Kategorien und Bezeichnungen erhalten. Sollten die Bilder keine gemeinsamen Bezeichnungen und Kategorien haben, führe bitte mehrere separate Uploads durch.</string>
|
||||||
<string name="multiple_files_depiction_header">Hinweis zu Mehrfach-Uploads</string>
|
<string name="multiple_files_depiction_header">Hinweis zu Mehrfach-Uploads</string>
|
||||||
<string name="nearby_wikitalk">Melde ein Problem mit diesem Datenobjekt an Wikidata</string>
|
<string name="nearby_wikitalk">Melde ein Problem mit diesem Datenobjekt an Wikidata</string>
|
||||||
|
<string name="please_enter_some_comments">Bitte gib einige Kommentare ein</string>
|
||||||
|
<string name="talk">Diskussion</string>
|
||||||
|
<string name="write_something_about_the_item">Schreibe etwas über das Objekt ‚%1$s‘. Deine Beschreibung wird öffentlich sichtbar sein.</string>
|
||||||
|
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">‚%1$s‘ existiert nicht mehr, es kann kein Foto mehr davon gemacht werden.</string>
|
||||||
|
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">‚%1$s‘ ist jetzt an einem anderen Ort. Bitte gib den richtigen Ort und, wenn möglich, den Breiten- und Längengrad an.</string>
|
||||||
|
<string name="other_problem_or_information_please_explain_below">Sonstiges Problem oder Information (bitte unten erläutern).</string>
|
||||||
|
<string name="feedback_destination_note">Dein Feedback wird auf der folgenden Wiki-Seite veröffentlicht werden: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a></string>
|
||||||
|
<string name="are_you_sure_that_you_want_cancel_all_the_uploads">Möchtest du wirklich alle Uploads abbrechen?</string>
|
||||||
|
<string name="cancelling_all_the_uploads">Alle Uploads werden abgebrochen…</string>
|
||||||
|
<string name="uploads">Hochgeladene Dateien</string>
|
||||||
|
<string name="pending">Ausstehend</string>
|
||||||
|
<string name="failed">Fehlgeschlagen</string>
|
||||||
|
<string name="could_not_load_place_data">Ortsdaten konnten nicht geladen werden</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
* JenyxGym
|
* JenyxGym
|
||||||
* KATRINE1992
|
* KATRINE1992
|
||||||
* Koreller
|
* Koreller
|
||||||
|
* Mahabarata
|
||||||
* McDutchie
|
* McDutchie
|
||||||
* Melissadeba95
|
* Melissadeba95
|
||||||
* Metroitendo
|
* Metroitendo
|
||||||
|
|
@ -516,6 +517,7 @@
|
||||||
<string name="no_notification">Vous n’avez aucune notification non lue</string>
|
<string name="no_notification">Vous n’avez aucune notification non lue</string>
|
||||||
<string name="no_read_notification">Vous n’avez aucune notification lue</string>
|
<string name="no_read_notification">Vous n’avez aucune notification lue</string>
|
||||||
<string name="share_logs_using">Partager les journaux en utilisant</string>
|
<string name="share_logs_using">Partager les journaux en utilisant</string>
|
||||||
|
<string name="check_your_email_inbox">Vérifiez votre boîte de réception</string>
|
||||||
<string name="menu_option_read">Afficher les lus</string>
|
<string name="menu_option_read">Afficher les lus</string>
|
||||||
<string name="menu_option_unread">Afficher les non lus</string>
|
<string name="menu_option_unread">Afficher les non lus</string>
|
||||||
<string name="error_occurred_in_picking_images">Une erreur est survenue lors de la sélection des images</string>
|
<string name="error_occurred_in_picking_images">Une erreur est survenue lors de la sélection des images</string>
|
||||||
|
|
@ -814,7 +816,7 @@
|
||||||
<string name="nearby_wikitalk">Signaler un problème concernant cet élément à Wikidata</string>
|
<string name="nearby_wikitalk">Signaler un problème concernant cet élément à Wikidata</string>
|
||||||
<string name="please_enter_some_comments">Merci de saisir vos commentaires</string>
|
<string name="please_enter_some_comments">Merci de saisir vos commentaires</string>
|
||||||
<string name="talk">Discussion</string>
|
<string name="talk">Discussion</string>
|
||||||
<string name="write_something_about_the_item">Ecrivez quelque chose sur l\'article \"%1$s\". Il sera visible par le public\nAjouter une définition terminologique pour ce terme</string>
|
<string name="write_something_about_the_item">Écrivez quelque chose à propos de l’élément « %1$s ». Il sera visible publiquement.</string>
|
||||||
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\'%1$s\' n\'existe plus, aucune photo ne pourra jamais en être prise.</string>
|
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\'%1$s\' n\'existe plus, aucune photo ne pourra jamais en être prise.</string>
|
||||||
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' se trouve à un endroit différent. Veuillez indiquer l\'endroit correct ci-dessous et, si possible, indiquez la latitude et la longitude correctes.</string>
|
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' se trouve à un endroit différent. Veuillez indiquer l\'endroit correct ci-dessous et, si possible, indiquez la latitude et la longitude correctes.</string>
|
||||||
<string name="other_problem_or_information_please_explain_below">Autre problème ou information (merci d\'expliquer ci-dessous).</string>
|
<string name="other_problem_or_information_please_explain_below">Autre problème ou information (merci d\'expliquer ci-dessous).</string>
|
||||||
|
|
@ -824,5 +826,8 @@
|
||||||
<string name="uploads">Téléversements</string>
|
<string name="uploads">Téléversements</string>
|
||||||
<string name="pending">En attente</string>
|
<string name="pending">En attente</string>
|
||||||
<string name="failed">Échec</string>
|
<string name="failed">Échec</string>
|
||||||
<string name="could_not_load_place_data">Ne peut pas supporter les données</string>
|
<string name="could_not_load_place_data">Les données du lieu n\'ont pas pu être chargées</string>
|
||||||
|
<string name="red_pin">Cet endroit n\'a pas encore de photo, allez en prendre une !</string>
|
||||||
|
<string name="green_pin">Cet endroit a déjà une photo.</string>
|
||||||
|
<string name="grey_pin">Je vérifie maintenant si cet endroit a une photo.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -374,7 +374,7 @@
|
||||||
<string name="unable_to_display_nearest_place">A helymeghatározás nélkül nem használható ez a funkció.</string>
|
<string name="unable_to_display_nearest_place">A helymeghatározás nélkül nem használható ez a funkció.</string>
|
||||||
<string name="never_ask_again">Ne kérdezd meg többször</string>
|
<string name="never_ask_again">Ne kérdezd meg többször</string>
|
||||||
<string name="display_location_permission_title">Helymeghatározási engedély</string>
|
<string name="display_location_permission_title">Helymeghatározási engedély</string>
|
||||||
<string name="achievements_fetch_failed" fuzzy="true">Valami hiba történt, nem sikerült az eredményeid betöltése</string>
|
<string name="achievements_fetch_failed">Valami hiba történt, nem sikerült az eredményeid betöltése</string>
|
||||||
<string name="display_campaigns">Kampányok megjelenítése</string>
|
<string name="display_campaigns">Kampányok megjelenítése</string>
|
||||||
<string name="display_campaigns_explanation">Folyamatban lévő kampányok megjelenítése</string>
|
<string name="display_campaigns_explanation">Folyamatban lévő kampányok megjelenítése</string>
|
||||||
<string name="in_app_camera_location_access_explanation">Engedélyezd az alkalmazás számára a helyszín lekérését, ha a kamera nem rögzíti azt! Egyes eszközök kamerái nem rögzítik a helyszínt. Közreműködésed hasznosabb, ha ilyen esetekben hagyod, hogy az alkalmazás lekérje és hozzárendelje a helyszínt. Ezt bármikor módosíthatod a Beállításokban</string>
|
<string name="in_app_camera_location_access_explanation">Engedélyezd az alkalmazás számára a helyszín lekérését, ha a kamera nem rögzíti azt! Egyes eszközök kamerái nem rögzítik a helyszínt. Közreműködésed hasznosabb, ha ilyen esetekben hagyod, hogy az alkalmazás lekérje és hozzárendelje a helyszínt. Ezt bármikor módosíthatod a Beállításokban</string>
|
||||||
|
|
@ -385,7 +385,7 @@
|
||||||
<string name="in_app_camera_location_permission_denied">Az alkalmazás helymeghatározási engedély hiányában nem rögzíti a helyszínt a felvételekkel együtt</string>
|
<string name="in_app_camera_location_permission_denied">Az alkalmazás helymeghatározási engedély hiányában nem rögzíti a helyszínt a felvételekkel együtt</string>
|
||||||
<string name="in_app_camera_location_unavailable">Az alkalmazás nem rögzít helyszínt a felvételekkel együtt, mivel a GPS ki van kapcsolva</string>
|
<string name="in_app_camera_location_unavailable">Az alkalmazás nem rögzít helyszínt a felvételekkel együtt, mivel a GPS ki van kapcsolva</string>
|
||||||
<string name="nearby_campaign_dismiss_message">Többé nem lesznek láthatók a kampányok. Ha akarod, visszakapcsolható a Beállításoknál.</string>
|
<string name="nearby_campaign_dismiss_message">Többé nem lesznek láthatók a kampányok. Ha akarod, visszakapcsolható a Beállításoknál.</string>
|
||||||
<string name="this_function_needs_network_connection" fuzzy="true">Ehhez a funkcióhoz hálózati kapcsolat szükséges, kérlek ellenőrizd az internetbeállításaidat.</string>
|
<string name="this_function_needs_network_connection">Ehhez a funkcióhoz hálózati kapcsolat szükséges. Kérlek ellenőrizd az internetbeállításaidat!</string>
|
||||||
<string name="error_processing_image">Hiba történt a kép feltöltése során. Próbáld meg újra!</string>
|
<string name="error_processing_image">Hiba történt a kép feltöltése során. Próbáld meg újra!</string>
|
||||||
<string name="getting_edit_token">Szerkesztő token beszerzése</string>
|
<string name="getting_edit_token">Szerkesztő token beszerzése</string>
|
||||||
<string name="check_category_adding_template">Kategóriaellenőrző sablon felhelyezése</string>
|
<string name="check_category_adding_template">Kategóriaellenőrző sablon felhelyezése</string>
|
||||||
|
|
@ -454,9 +454,9 @@
|
||||||
<string name="delete_helper_show_deletion_message_if">Törlésre jelölve: %1$s.</string>
|
<string name="delete_helper_show_deletion_message_if">Törlésre jelölve: %1$s.</string>
|
||||||
<string name="delete_helper_show_deletion_title_failed">Sikertelen</string>
|
<string name="delete_helper_show_deletion_title_failed">Sikertelen</string>
|
||||||
<string name="delete_helper_show_deletion_message_else">Nem sikerült a törlés kérése.</string>
|
<string name="delete_helper_show_deletion_message_else">Nem sikerült a törlés kérése.</string>
|
||||||
<string name="delete_helper_ask_spam_selfie" fuzzy="true">Egy szelfi</string>
|
<string name="delete_helper_ask_spam_selfie">egy szelfi, amely egyetlen cikkben sem szerepel</string>
|
||||||
<string name="delete_helper_ask_spam_blurry" fuzzy="true">Homályos</string>
|
<string name="delete_helper_ask_spam_blurry">teljesen homályos</string>
|
||||||
<string name="delete_helper_ask_spam_nonsense" fuzzy="true">Nonszensz</string>
|
<string name="delete_helper_ask_spam_nonsense">nonszensz, abszolút használhatatlan bármely cikkben is</string>
|
||||||
<string name="delete_helper_ask_reason_copyright_press_photo">Sajtófotó</string>
|
<string name="delete_helper_ask_reason_copyright_press_photo">Sajtófotó</string>
|
||||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Random fénykép az Internetről</string>
|
<string name="delete_helper_ask_reason_copyright_internet_photo">Random fénykép az Internetről</string>
|
||||||
<string name="delete_helper_ask_reason_copyright_logo">Logó</string>
|
<string name="delete_helper_ask_reason_copyright_logo">Logó</string>
|
||||||
|
|
@ -472,7 +472,7 @@
|
||||||
<string name="place_state_needs_photo">Fénykép szükséges</string>
|
<string name="place_state_needs_photo">Fénykép szükséges</string>
|
||||||
<string name="place_type">Hely típusa:</string>
|
<string name="place_type">Hely típusa:</string>
|
||||||
<string name="nearby_search_hint">Híd, múzeum, szálloda, stb.</string>
|
<string name="nearby_search_hint">Híd, múzeum, szálloda, stb.</string>
|
||||||
<string name="you_must_reset_your_passsword" fuzzy="true">A belépés nem sikerült, kérj új jelszót.</string>
|
<string name="you_must_reset_your_passsword">A belépés nem sikerült. Kérj új jelszót!</string>
|
||||||
<string name="setting_wallpaper_dialog_title">Beállítás háttérképnek</string>
|
<string name="setting_wallpaper_dialog_title">Beállítás háttérképnek</string>
|
||||||
<string name="setting_wallpaper_dialog_message">Beállítás háttérképnek. Kérem várjon...</string>
|
<string name="setting_wallpaper_dialog_message">Beállítás háttérképnek. Kérem várjon...</string>
|
||||||
<string name="theme_default_name">Rendszerbeállítás követése</string>
|
<string name="theme_default_name">Rendszerbeállítás követése</string>
|
||||||
|
|
|
||||||
|
|
@ -765,8 +765,15 @@
|
||||||
<string name="nearby_wikitalk">Signalar a Wikidata un problema sur iste elemento</string>
|
<string name="nearby_wikitalk">Signalar a Wikidata un problema sur iste elemento</string>
|
||||||
<string name="please_enter_some_comments">Per favor insere alcun commentos</string>
|
<string name="please_enter_some_comments">Per favor insere alcun commentos</string>
|
||||||
<string name="talk">Discussion</string>
|
<string name="talk">Discussion</string>
|
||||||
|
<string name="write_something_about_the_item">Scribe qualcosa sur le elemento ‘%1$s’. Isto essera visibile publicamente.</string>
|
||||||
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">‘%1$s’ non existe plus, necun imagine pote jammais esser prendite de illo.</string>
|
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">‘%1$s’ non existe plus, necun imagine pote jammais esser prendite de illo.</string>
|
||||||
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">‘%1$s’ es in un altere loco. Per favor specifica le loco correcte hic infra, e si possibile, indica le latitude e longitude correcte.</string>
|
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">‘%1$s’ es in un altere loco. Per favor specifica le loco correcte hic infra, e si possibile, indica le latitude e longitude correcte.</string>
|
||||||
<string name="other_problem_or_information_please_explain_below">Altere problema o information (per favor explica hic infra).</string>
|
<string name="other_problem_or_information_please_explain_below">Altere problema o information (per favor explica hic infra).</string>
|
||||||
<string name="feedback_destination_note">Tu retroaction apparera sur le sequente pagina wiki: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a></string>
|
<string name="feedback_destination_note">Tu retroaction apparera sur le sequente pagina wiki: <a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\">Commons:Mobile app/Feedback</a></string>
|
||||||
|
<string name="are_you_sure_that_you_want_cancel_all_the_uploads">Es tu secur de voler cancellar tote le incargamentos?</string>
|
||||||
|
<string name="cancelling_all_the_uploads">Cancella tote le incargamentos…</string>
|
||||||
|
<string name="uploads">Incargamentos</string>
|
||||||
|
<string name="pending">Pendente</string>
|
||||||
|
<string name="failed">Fallite</string>
|
||||||
|
<string name="could_not_load_place_data">Non poteva cargar le datos del loco</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -760,4 +760,7 @@
|
||||||
<item quantity="one">%d immagine selezionata</item>
|
<item quantity="one">%d immagine selezionata</item>
|
||||||
<item quantity="other">%d immagini selezionate</item>
|
<item quantity="other">%d immagini selezionate</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
<string name="red_pin">Questo posto non ha ancora una foto, scattane una!</string>
|
||||||
|
<string name="green_pin">Questo posto ha già una foto.</string>
|
||||||
|
<string name="grey_pin">Ora controlliamo se questo posto ha una foto.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue