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"
|
||||
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
|
||||
implementation ("org.osmdroid:osmdroid-android:$OSMDROID_VERSION")
|
||||
|
|
@ -226,7 +226,7 @@ android {
|
|||
excludes += ['META-INF/androidx.*']
|
||||
}
|
||||
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
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion '1.3.2'
|
||||
kotlinCompilerExtensionVersion '1.5.8'
|
||||
}
|
||||
namespace 'fr.free.nrw.commons'
|
||||
lint {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class AboutActivityTest {
|
|||
fun testLaunchTranslate() {
|
||||
Espresso.onView(ViewMatchers.withId(R.id.about_translate)).perform(ViewActions.click())
|
||||
Espresso.onView(ViewMatchers.withId(android.R.id.button1)).perform(ViewActions.click())
|
||||
val langCode = CommonsApplication.getInstance().languageLookUpTable.codes[0]
|
||||
val langCode = CommonsApplication.instance.languageLookUpTable!!.codes[0]
|
||||
Intents.intended(
|
||||
CoreMatchers.allOf(
|
||||
IntentMatchers.hasAction(Intent.ACTION_VIEW),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import org.junit.Before
|
|||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
|
|
@ -59,7 +61,7 @@ class WelcomeActivityTest {
|
|||
.perform(ViewActions.click())
|
||||
onView(withId(R.id.finishTutorialButton))
|
||||
.perform(ViewActions.click())
|
||||
assert(activityRule.activity.isDestroyed)
|
||||
assertThat(activityRule.activity.isDestroyed, equalTo(true))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,10 +71,10 @@ class WelcomeActivityTest {
|
|||
.perform(ViewActions.click())
|
||||
onView(withId(R.id.welcomePager))
|
||||
.perform(ViewActions.swipeLeft())
|
||||
assert(true)
|
||||
assertThat(true, equalTo(true))
|
||||
onView(withId(R.id.welcomePager))
|
||||
.perform(ViewActions.swipeRight())
|
||||
assert(true)
|
||||
assertThat(true, equalTo(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -84,13 +86,13 @@ class WelcomeActivityTest {
|
|||
.perform(ViewActions.swipeLeft())
|
||||
.perform(ViewActions.swipeLeft())
|
||||
.perform(ViewActions.swipeLeft())
|
||||
assert(true)
|
||||
assertThat(true, equalTo(true))
|
||||
onView(withId(R.id.welcomePager))
|
||||
.perform(ViewActions.swipeRight())
|
||||
.perform(ViewActions.swipeRight())
|
||||
.perform(ViewActions.swipeRight())
|
||||
.perform(ViewActions.swipeRight())
|
||||
assert(true)
|
||||
assertThat(true, equalTo(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -101,10 +103,10 @@ class WelcomeActivityTest {
|
|||
if (viewPager.currentItem == 3) {
|
||||
onView(withId(R.id.welcomePager))
|
||||
.perform(ViewActions.swipeLeft())
|
||||
assert(true)
|
||||
assertThat(true, equalTo(true))
|
||||
onView(withId(R.id.welcomePager))
|
||||
.perform(ViewActions.swipeRight())
|
||||
assert(false)
|
||||
assertThat(true, equalTo(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -119,7 +121,7 @@ class WelcomeActivityTest {
|
|||
.perform(ViewActions.click())
|
||||
onView(withId(R.id.finishTutorialButton))
|
||||
.perform(ViewActions.click())
|
||||
assert(activityRule.activity.isDestroyed)
|
||||
assertThat(activityRule.activity.isDestroyed, equalTo(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
android:maxSdkVersion="29"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<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.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
|
@ -97,7 +99,6 @@
|
|||
android:exported="true"
|
||||
android:hardwareAccelerated="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter android:label="@string/intent_share_upload_label">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
|
@ -120,7 +121,7 @@
|
|||
android:name=".contributions.MainActivity"
|
||||
android:configChanges="screenSize|keyboard|orientation"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name" />
|
||||
/>
|
||||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:label="@string/title_activity_settings" />
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class BaseMarker {
|
|||
val drawable: Drawable = context.resources.getDrawable(drawableResId)
|
||||
icon =
|
||||
if (drawable is BitmapDrawable) {
|
||||
(drawable as BitmapDrawable).bitmap
|
||||
drawable.bitmap
|
||||
} else {
|
||||
val bitmap =
|
||||
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 static org.acra.ReportField.ANDROID_VERSION;
|
||||
import static org.acra.ReportField.APP_VERSION_CODE;
|
||||
import static org.acra.ReportField.APP_VERSION_NAME;
|
||||
import static org.acra.ReportField.PHONE_MODEL;
|
||||
import static org.acra.ReportField.STACK_TRACE;
|
||||
import static org.acra.ReportField.USER_COMMENT;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao.Table;
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao;
|
||||
import fr.free.nrw.commons.category.CategoryDao;
|
||||
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler;
|
||||
import fr.free.nrw.commons.concurrency.ThreadPoolService;
|
||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.language.AppLanguageLookUpTable;
|
||||
import fr.free.nrw.commons.logging.FileLoggingTree;
|
||||
import fr.free.nrw.commons.logging.LogUtils;
|
||||
import fr.free.nrw.commons.media.CustomOkHttpNetworkFetcher;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.internal.functions.Functions;
|
||||
import io.reactivex.plugins.RxJavaPlugins;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.File;
|
||||
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;
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.sqlite.SQLiteException
|
||||
import android.os.Build
|
||||
import android.os.Process
|
||||
import android.util.Log
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
||||
import fr.free.nrw.commons.auth.LoginActivity
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao
|
||||
import fr.free.nrw.commons.category.CategoryDao
|
||||
import fr.free.nrw.commons.concurrency.BackgroundPoolExceptionHandler
|
||||
import fr.free.nrw.commons.concurrency.ThreadPoolService
|
||||
import fr.free.nrw.commons.contributions.ContributionDao
|
||||
import fr.free.nrw.commons.data.DBOpenHelper
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.language.AppLanguageLookUpTable
|
||||
import fr.free.nrw.commons.logging.FileLoggingTree
|
||||
import fr.free.nrw.commons.logging.LogUtils
|
||||
import fr.free.nrw.commons.media.CustomOkHttpNetworkFetcher
|
||||
import fr.free.nrw.commons.settings.Prefs
|
||||
import fr.free.nrw.commons.upload.FileUtils
|
||||
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
|
||||
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
|
||||
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.internal.functions.Functions
|
||||
import io.reactivex.plugins.RxJavaPlugins
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.acra.ACRA.init
|
||||
import org.acra.ReportField
|
||||
import org.acra.annotation.AcraCore
|
||||
import org.acra.annotation.AcraDialog
|
||||
import org.acra.annotation.AcraMailSender
|
||||
import org.acra.data.StringFormat
|
||||
import timber.log.Timber
|
||||
import timber.log.Timber.DebugTree
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
@AcraCore(
|
||||
buildConfigClass = BuildConfig.class,
|
||||
buildConfigClass = BuildConfig::class,
|
||||
resReportSendSuccessToast = R.string.crash_dialog_ok_toast,
|
||||
reportFormat = StringFormat.KEY_VALUE_LIST,
|
||||
reportContent = {USER_COMMENT, APP_VERSION_CODE, APP_VERSION_NAME, ANDROID_VERSION, PHONE_MODEL,
|
||||
STACK_TRACE}
|
||||
reportContent = [ReportField.USER_COMMENT, ReportField.APP_VERSION_CODE, ReportField.APP_VERSION_NAME, ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, ReportField.STACK_TRACE]
|
||||
)
|
||||
|
||||
@AcraMailSender(
|
||||
mailTo = "commons-app-android-private@googlegroups.com",
|
||||
reportAsFile = false
|
||||
)
|
||||
@AcraMailSender(mailTo = "commons-app-android-private@googlegroups.com", reportAsFile = false)
|
||||
|
||||
@AcraDialog(
|
||||
resTheme = R.style.Theme_AppCompat_Dialog,
|
||||
|
|
@ -83,137 +67,100 @@ import timber.log.Timber;
|
|||
resCommentPrompt = R.string.crash_dialog_comment_prompt
|
||||
)
|
||||
|
||||
public class CommonsApplication extends 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;
|
||||
class CommonsApplication : MultiDexApplication() {
|
||||
|
||||
@Inject
|
||||
@Named("default_preferences")
|
||||
JsonKvStore defaultPrefs;
|
||||
lateinit var sessionManager: SessionManager
|
||||
|
||||
@Inject
|
||||
CommonsCookieJar cookieJar;
|
||||
lateinit var dbOpenHelper: DBOpenHelper
|
||||
|
||||
@Inject
|
||||
CustomOkHttpNetworkFetcher customOkHttpNetworkFetcher;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@field:Named("default_preferences")
|
||||
lateinit var defaultPrefs: JsonKvStore
|
||||
|
||||
@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
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
INSTANCE = this;
|
||||
ACRA.init(this);
|
||||
instance = this
|
||||
init(this)
|
||||
|
||||
ApplicationlessInjection
|
||||
.getInstance(this)
|
||||
.getCommonsApplicationComponent()
|
||||
.inject(this);
|
||||
.commonsApplicationComponent
|
||||
.inject(this)
|
||||
|
||||
initTimber();
|
||||
initTimber()
|
||||
|
||||
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) {
|
||||
defaultExifTagsSet = new HashSet<>();
|
||||
defaultExifTagsSet = HashSet()
|
||||
}
|
||||
defaultExifTagsSet.add(getString(R.string.exif_tag_location));
|
||||
defaultPrefs.putStringSet(Prefs.MANAGED_EXIF_TAGS, defaultExifTagsSet);
|
||||
defaultExifTagsSet.add(getString(R.string.exif_tag_location))
|
||||
defaultPrefs.putStringSet(Prefs.MANAGED_EXIF_TAGS, defaultExifTagsSet)
|
||||
}
|
||||
|
||||
// Set DownsampleEnabled to True to downsample the image in case it's heavy
|
||||
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
|
||||
// Set DownsampleEnabled to True to downsample the image in case it's heavy
|
||||
val config = ImagePipelineConfig.newBuilder(this)
|
||||
.setNetworkFetcher(customOkHttpNetworkFetcher)
|
||||
.setDownsampleEnabled(true)
|
||||
.build();
|
||||
.build()
|
||||
try {
|
||||
Fresco.initialize(this, config);
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
Fresco.initialize(this, config)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
// 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,
|
||||
// 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
|
||||
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.
|
||||
*/
|
||||
private void initTimber() {
|
||||
boolean isBeta = ConfigUtils.isBetaFlavour();
|
||||
String logFileName =
|
||||
isBeta ? "CommonsBetaAppLogs" : "CommonsAppLogs";
|
||||
String logDirectory = LogUtils.getLogDirectory();
|
||||
private fun initTimber() {
|
||||
val isBeta = isBetaFlavour
|
||||
val logFileName =
|
||||
if (isBeta) "CommonsBetaAppLogs" else "CommonsAppLogs"
|
||||
val logDirectory = LogUtils.getLogDirectory()
|
||||
//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,
|
||||
logFileName,
|
||||
logDirectory,
|
||||
1000,
|
||||
getFileLoggingThreadPool());
|
||||
fileLoggingThreadPool
|
||||
)
|
||||
|
||||
Timber.plant(tree);
|
||||
Timber.plant(new Timber.DebugTree());
|
||||
Timber.plant(tree)
|
||||
Timber.plant(DebugTree())
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -223,48 +170,27 @@ public class CommonsApplication extends MultiDexApplication {
|
|||
* @param logFileName
|
||||
* @param logDirectory
|
||||
*/
|
||||
private void deleteStaleLogs(String logFileName, String logDirectory) {
|
||||
private fun deleteStaleLogs(logFileName: String, logDirectory: String) {
|
||||
try {
|
||||
File file = new File(logDirectory + "/zip/" + logFileName + ".zip");
|
||||
if (file.exists() && file.getTotalSpace() > 1000000) {// In Kbs
|
||||
file.delete();
|
||||
val file = File("$logDirectory/zip/$logFileName.zip")
|
||||
if (file.exists() && file.totalSpace > 1000000) { // In Kbs
|
||||
file.delete()
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRoboUnitTest() {
|
||||
return "robolectric".equals(Build.FINGERPRINT);
|
||||
}
|
||||
|
||||
private ThreadPoolService getFileLoggingThreadPool() {
|
||||
return new ThreadPoolService.Builder("file-logging-thread")
|
||||
private val fileLoggingThreadPool: ThreadPoolService
|
||||
get() = ThreadPoolService.Builder("file-logging-thread")
|
||||
.setPriority(Process.THREAD_PRIORITY_LOWEST)
|
||||
.setPoolSize(1)
|
||||
.setExceptionHandler(new BackgroundPoolExceptionHandler())
|
||||
.build();
|
||||
}
|
||||
.setExceptionHandler(BackgroundPoolExceptionHandler())
|
||||
.build()
|
||||
|
||||
public static void createNotificationChannel(@NonNull Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationManager manager = (NotificationManager) context
|
||||
.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;
|
||||
}
|
||||
val userAgent: String
|
||||
get() = ("Commons/" + this.getVersionNameWithSha()
|
||||
+ " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE)
|
||||
|
||||
/**
|
||||
* clears data of current application
|
||||
|
|
@ -273,88 +199,88 @@ public class CommonsApplication extends MultiDexApplication {
|
|||
* @param logoutListener Implementation of interface LogoutListener
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
public void clearApplicationData(Context context, LogoutListener logoutListener) {
|
||||
File cacheDirectory = context.getCacheDir();
|
||||
File applicationDirectory = new File(cacheDirectory.getParent());
|
||||
fun clearApplicationData(context: Context, logoutListener: LogoutListener) {
|
||||
val cacheDirectory = context.cacheDir
|
||||
val applicationDirectory = File(cacheDirectory.parent)
|
||||
if (applicationDirectory.exists()) {
|
||||
String[] fileNames = applicationDirectory.list();
|
||||
for (String fileName : fileNames) {
|
||||
if (!fileName.equals("lib")) {
|
||||
FileUtils.deleteFile(new File(applicationDirectory, fileName));
|
||||
val fileNames = applicationDirectory.list()
|
||||
for (fileName in fileNames) {
|
||||
if (fileName != "lib") {
|
||||
FileUtils.deleteFile(File(applicationDirectory, fileName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionManager.logout()
|
||||
.andThen(Completable.fromAction(() -> cookieJar.clear()))
|
||||
.andThen(Completable.fromAction(() -> {
|
||||
Timber.d("All accounts have been removed");
|
||||
clearImageCache();
|
||||
//TODO: fix preference manager
|
||||
defaultPrefs.clearAll();
|
||||
defaultPrefs.putBoolean("firstrun", false);
|
||||
updateAllDatabases();
|
||||
}
|
||||
))
|
||||
.andThen(Completable.fromAction { cookieJar.clear() })
|
||||
.andThen(Completable.fromAction {
|
||||
Timber.d("All accounts have been removed")
|
||||
clearImageCache()
|
||||
//TODO: fix preference manager
|
||||
defaultPrefs.clearAll()
|
||||
defaultPrefs.putBoolean("firstrun", false)
|
||||
updateAllDatabases()
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(logoutListener::onLogoutComplete, Timber::e);
|
||||
.subscribe({ logoutListener.onLogoutComplete() }, { t: Throwable? -> Timber.e(t) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all images cache held by Fresco
|
||||
*/
|
||||
private void clearImageCache() {
|
||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
imagePipeline.clearCaches();
|
||||
private fun clearImageCache() {
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
imagePipeline.clearCaches()
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all tables and re-creates them.
|
||||
*/
|
||||
private void updateAllDatabases() {
|
||||
dbOpenHelper.getReadableDatabase().close();
|
||||
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
||||
private fun updateAllDatabases() {
|
||||
dbOpenHelper.readableDatabase.close()
|
||||
val db = dbOpenHelper.writableDatabase
|
||||
|
||||
CategoryDao.Table.onDelete(db);
|
||||
dbOpenHelper.deleteTable(db,
|
||||
CONTRIBUTIONS_TABLE);//Delete the contributions table in the existing db on older versions
|
||||
CategoryDao.Table.onDelete(db)
|
||||
dbOpenHelper.deleteTable(
|
||||
db,
|
||||
DBOpenHelper.CONTRIBUTIONS_TABLE
|
||||
) //Delete the contributions table in the existing db on older versions
|
||||
|
||||
try {
|
||||
contributionDao.deleteAll();
|
||||
} catch (SQLiteException e) {
|
||||
Timber.e(e);
|
||||
contributionDao.deleteAll()
|
||||
} catch (e: SQLiteException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
BookmarkPicturesDao.Table.onDelete(db);
|
||||
BookmarkLocationsDao.Table.onDelete(db);
|
||||
Table.onDelete(db);
|
||||
BookmarkPicturesDao.Table.onDelete(db)
|
||||
BookmarkLocationsDao.Table.onDelete(db)
|
||||
BookmarkItemsDao.Table.onDelete(db)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface used to get log-out events
|
||||
*/
|
||||
public interface LogoutListener {
|
||||
|
||||
void onLogoutComplete();
|
||||
interface LogoutListener {
|
||||
fun onLogoutComplete()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static class BaseLogoutListener implements CommonsApplication.LogoutListener {
|
||||
|
||||
Context ctx;
|
||||
String loginMessage, userName;
|
||||
open class BaseLogoutListener : LogoutListener {
|
||||
var ctx: Context
|
||||
var loginMessage: String? = null
|
||||
var userName: String? = null
|
||||
|
||||
/**
|
||||
* Constructor for BaseLogoutListener.
|
||||
*
|
||||
* @param ctx Application context
|
||||
*/
|
||||
public BaseLogoutListener(final Context ctx) {
|
||||
this.ctx = ctx;
|
||||
constructor(ctx: Context) {
|
||||
this.ctx = ctx
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -364,28 +290,29 @@ public class CommonsApplication extends MultiDexApplication {
|
|||
* @param loginMessage Message to be displayed on the login page
|
||||
* @param loginUsername Username to be pre-filled on the login page
|
||||
*/
|
||||
public BaseLogoutListener(final Context ctx, final String loginMessage,
|
||||
final String loginUsername) {
|
||||
this.ctx = ctx;
|
||||
this.loginMessage = loginMessage;
|
||||
this.userName = loginUsername;
|
||||
constructor(
|
||||
ctx: Context, loginMessage: String?,
|
||||
loginUsername: String?
|
||||
) {
|
||||
this.ctx = ctx
|
||||
this.loginMessage = loginMessage
|
||||
this.userName = loginUsername
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutComplete() {
|
||||
Timber.d("Logout complete callback received.");
|
||||
final Intent loginIntent = new Intent(ctx, LoginActivity.class);
|
||||
override fun onLogoutComplete() {
|
||||
Timber.d("Logout complete callback received.")
|
||||
val loginIntent = Intent(ctx, LoginActivity::class.java)
|
||||
loginIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
if (loginMessage != null) {
|
||||
loginIntent.putExtra(loginMessageIntentKey, loginMessage);
|
||||
loginIntent.putExtra(LOGIN_MESSAGE_INTENT_KEY, loginMessage)
|
||||
}
|
||||
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
|
||||
* 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 {
|
||||
|
||||
Activity activity;
|
||||
class ActivityLogoutListener : BaseLogoutListener {
|
||||
var 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 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) {
|
||||
super(ctx);
|
||||
this.activity = activity;
|
||||
constructor(activity: Activity, ctx: Context) : super(ctx) {
|
||||
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 loginUsername Username to be pre-filled on the login page after logout.
|
||||
*/
|
||||
public ActivityLogoutListener(final Activity activity, final Context ctx,
|
||||
final String loginMessage, final String loginUsername) {
|
||||
super(activity, loginMessage, loginUsername);
|
||||
this.activity = activity;
|
||||
constructor(
|
||||
activity: Activity, ctx: Context?,
|
||||
loginMessage: String?, loginUsername: String?
|
||||
) : super(activity, loginMessage, loginUsername) {
|
||||
this.activity = activity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutComplete() {
|
||||
super.onLogoutComplete();
|
||||
activity.finish();
|
||||
override fun onLogoutComplete() {
|
||||
super.onLogoutComplete()
|
||||
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.schedulers.Schedulers;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
|
||||
|
|
@ -301,7 +302,8 @@ public class LocationPickerActivity extends BaseActivity implements
|
|||
modifyLocationButton = findViewById(R.id.modify_location);
|
||||
removeLocationButton = findViewById(R.id.remove_location);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package fr.free.nrw.commons
|
|||
import android.os.Parcelable
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.wikidata.model.page.PageTitle
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
|
@ -124,6 +125,7 @@ class Media constructor(
|
|||
* Gets the categories the file falls under.
|
||||
* @return file categories as an ArrayList of Strings
|
||||
*/
|
||||
@IgnoredOnParcel
|
||||
var addedCategories: List<String>? = null
|
||||
// TODO added categories should be removed. It is added for a short fix. On category update,
|
||||
// categories should be re-fetched instead
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class ThanksClient
|
|||
revisionId.toString(), // Rev
|
||||
null, // Log
|
||||
csrfTokenClient.getTokenBlocking(), // Token
|
||||
CommonsApplication.getInstance().userAgent, // Source
|
||||
CommonsApplication.instance.userAgent, // Source
|
||||
).map { mwThankPostResponse ->
|
||||
mwThankPostResponse.result?.success == 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ import timber.log.Timber;
|
|||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||
import static fr.free.nrw.commons.CommonsApplication.loginMessageIntentKey;
|
||||
import static fr.free.nrw.commons.CommonsApplication.loginUsernameIntentKey;
|
||||
import static fr.free.nrw.commons.CommonsApplication.LOGIN_MESSAGE_INTENT_KEY;
|
||||
import static fr.free.nrw.commons.CommonsApplication.LOGIN_USERNAME_INTENT_KEY;
|
||||
|
||||
public class LoginActivity extends AccountAuthenticatorActivity {
|
||||
|
||||
|
|
@ -94,8 +94,8 @@ public class LoginActivity extends AccountAuthenticatorActivity {
|
|||
binding = ActivityLoginBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
String message = getIntent().getStringExtra(loginMessageIntentKey);
|
||||
String username = getIntent().getStringExtra(loginUsernameIntentKey);
|
||||
String message = getIntent().getStringExtra(LOGIN_MESSAGE_INTENT_KEY);
|
||||
String username = getIntent().getStringExtra(LOGIN_USERNAME_INTENT_KEY);
|
||||
|
||||
binding.loginUsername.addTextChangedListener(textWatcher);
|
||||
binding.loginPassword.addTextChangedListener(textWatcher);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.bookmarks.items;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -134,6 +135,7 @@ public class BookmarkItemsDao {
|
|||
* @param cursor : Object for storing database data
|
||||
* @return DepictedItem
|
||||
*/
|
||||
@SuppressLint("Range")
|
||||
DepictedItem fromCursor(final Cursor cursor) {
|
||||
final String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME));
|
||||
final String description
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.bookmarks.locations;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -146,6 +147,7 @@ public class BookmarkLocationsDao {
|
|||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
@NonNull
|
||||
Place fromCursor(final Cursor cursor) {
|
||||
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.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
|
@ -33,6 +34,23 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
|||
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
||||
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
||||
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>>() {
|
||||
@Override
|
||||
public void onActivityResult(Map<String, Boolean> result) {
|
||||
|
|
@ -45,7 +63,7 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
|||
contributionController.locationPermissionCallback.onLocationPermissionGranted();
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher);
|
||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
} else {
|
||||
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;
|
||||
},
|
||||
commonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult
|
||||
);
|
||||
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
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.bookmarks.pictures;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -150,6 +151,7 @@ public class BookmarkPicturesDao {
|
|||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
@NonNull
|
||||
Bookmark fromCursor(Cursor cursor) {
|
||||
String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_NAME));
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class CategoryClient
|
|||
}.map {
|
||||
it
|
||||
.filter { page ->
|
||||
page.categoryInfo() == null || !page.categoryInfo().isHidden
|
||||
!page.categoryInfo().isHidden
|
||||
}.map {
|
||||
CategoryItem(
|
||||
it.title().replace(CATEGORY_PREFIX, ""),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.category;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -111,6 +112,7 @@ public class CategoryDao {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@SuppressLint("Range")
|
||||
Category fromCursor(Cursor cursor) {
|
||||
// Hardcoding column positions!
|
||||
return new Category(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.app.Activity;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
|
@ -64,10 +65,11 @@ public class ContributionController {
|
|||
* Check for permissions and initiate camera click
|
||||
*/
|
||||
public void initiateCameraPick(Activity activity,
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||
ActivityResultLauncher<Intent> resultLauncher) {
|
||||
boolean useExtStorage = defaultKvStore.getBoolean("useExternalStorage", true);
|
||||
if (!useExtStorage) {
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -75,12 +77,12 @@ public class ContributionController {
|
|||
() -> {
|
||||
if (defaultKvStore.getBoolean("inAppCameraFirstRun")) {
|
||||
defaultKvStore.putBoolean("inAppCameraFirstRun", false);
|
||||
askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher);
|
||||
askUserToAllowLocationAccess(activity, inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||
} else if (defaultKvStore.getBoolean("inAppCameraLocationPref")) {
|
||||
createDialogsAndHandleLocationPermissions(activity,
|
||||
inAppCameraLocationPermissionLauncher);
|
||||
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||
} else {
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
}
|
||||
},
|
||||
R.string.storage_permission_title,
|
||||
|
|
@ -94,7 +96,8 @@ public class ContributionController {
|
|||
* @param activity
|
||||
*/
|
||||
private void createDialogsAndHandleLocationPermissions(Activity activity,
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||
ActivityResultLauncher<Intent> resultLauncher) {
|
||||
locationPermissionCallback = new LocationPermissionCallback() {
|
||||
@Override
|
||||
public void onLocationPermissionDenied(String toastMessage) {
|
||||
|
|
@ -103,16 +106,16 @@ public class ContributionController {
|
|||
toastMessage,
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationPermissionGranted() {
|
||||
if (!locationPermissionsHelper.isLocationAccessToAppsTurnedOn()) {
|
||||
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 {
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -135,9 +138,10 @@ public class ContributionController {
|
|||
* @param activity Activity reference
|
||||
* @param dialogTextResource Resource id of text to be shown in dialog
|
||||
* @param toastTextResource Resource id of text to be shown in toast
|
||||
* @param resultLauncher
|
||||
*/
|
||||
private void showLocationOffDialog(Activity activity, int dialogTextResource,
|
||||
int toastTextResource) {
|
||||
int toastTextResource, ActivityResultLauncher<Intent> resultLauncher) {
|
||||
DialogUtil
|
||||
.showAlertDialog(activity,
|
||||
activity.getString(R.string.ask_to_turn_location_on),
|
||||
|
|
@ -148,20 +152,21 @@ public class ContributionController {
|
|||
() -> {
|
||||
Toast.makeText(activity, activity.getString(toastTextResource),
|
||||
Toast.LENGTH_LONG).show();
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void handleShowRationaleFlowCameraLocation(Activity activity,
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||
ActivityResultLauncher<Intent> resultLauncher) {
|
||||
DialogUtil.showAlertDialog(activity, activity.getString(R.string.location_permission_title),
|
||||
activity.getString(R.string.in_app_camera_location_permission_rationale),
|
||||
activity.getString(android.R.string.ok),
|
||||
activity.getString(android.R.string.cancel),
|
||||
() -> {
|
||||
createDialogsAndHandleLocationPermissions(activity,
|
||||
inAppCameraLocationPermissionLauncher);
|
||||
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||
},
|
||||
() -> locationPermissionCallback.onLocationPermissionDenied(
|
||||
activity.getString(R.string.in_app_camera_location_permission_denied)),
|
||||
|
|
@ -181,7 +186,8 @@ public class ContributionController {
|
|||
* @param activity
|
||||
*/
|
||||
private void askUserToAllowLocationAccess(Activity activity,
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher) {
|
||||
ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher,
|
||||
ActivityResultLauncher<Intent> resultLauncher) {
|
||||
DialogUtil.showAlertDialog(activity,
|
||||
activity.getString(R.string.in_app_camera_location_permission_title),
|
||||
activity.getString(R.string.in_app_camera_location_access_explanation),
|
||||
|
|
@ -190,12 +196,12 @@ public class ContributionController {
|
|||
() -> {
|
||||
defaultKvStore.putBoolean("inAppCameraLocationPref", true);
|
||||
createDialogsAndHandleLocationPermissions(activity,
|
||||
inAppCameraLocationPermissionLauncher);
|
||||
inAppCameraLocationPermissionLauncher, resultLauncher);
|
||||
},
|
||||
() -> {
|
||||
ViewUtil.showLongToast(activity, R.string.in_app_camera_location_permission_denied);
|
||||
defaultKvStore.putBoolean("inAppCameraLocationPref", false);
|
||||
initiateCameraUpload(activity);
|
||||
initiateCameraUpload(activity, resultLauncher);
|
||||
},
|
||||
null,
|
||||
true);
|
||||
|
|
@ -204,18 +210,18 @@ public class ContributionController {
|
|||
/**
|
||||
* Initiate gallery picker
|
||||
*/
|
||||
public void initiateGalleryPick(final Activity activity, final boolean allowMultipleUploads) {
|
||||
initiateGalleryUpload(activity, allowMultipleUploads);
|
||||
public void initiateGalleryPick(final Activity activity, ActivityResultLauncher<Intent> resultLauncher, final boolean allowMultipleUploads) {
|
||||
initiateGalleryUpload(activity, resultLauncher, allowMultipleUploads);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate gallery picker with permission
|
||||
*/
|
||||
public void initiateCustomGalleryPickWithPermission(final Activity activity) {
|
||||
public void initiateCustomGalleryPickWithPermission(final Activity activity, ActivityResultLauncher<Intent> resultLauncher) {
|
||||
setPickerConfiguration(activity, true);
|
||||
|
||||
PermissionUtils.checkPermissionsAndPerformAction(activity,
|
||||
() -> FilePicker.openCustomSelector(activity, 0),
|
||||
() -> FilePicker.openCustomSelector(activity, resultLauncher, 0),
|
||||
R.string.storage_permission_title,
|
||||
R.string.write_storage_permission_rationale,
|
||||
PermissionUtils.PERMISSIONS_STORAGE);
|
||||
|
|
@ -225,12 +231,10 @@ public class ContributionController {
|
|||
/**
|
||||
* Open chooser for gallery uploads
|
||||
*/
|
||||
private void initiateGalleryUpload(final Activity activity,
|
||||
private void initiateGalleryUpload(final Activity activity, ActivityResultLauncher<Intent> resultLauncher,
|
||||
final boolean allowMultipleUploads) {
|
||||
setPickerConfiguration(activity, allowMultipleUploads);
|
||||
boolean openDocumentIntentPreferred = defaultKvStore.getBoolean(
|
||||
"openDocumentPhotoPickerPref", true);
|
||||
FilePicker.openGallery(activity, 0, openDocumentIntentPreferred);
|
||||
FilePicker.openGallery(activity, resultLauncher, 0, isDocumentPhotoPickerPreferred());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,22 +251,43 @@ public class ContributionController {
|
|||
/**
|
||||
* Initiate camera upload by opening camera
|
||||
*/
|
||||
private void initiateCameraUpload(Activity activity) {
|
||||
private void initiateCameraUpload(Activity activity, ActivityResultLauncher<Intent> resultLauncher) {
|
||||
setPickerConfiguration(activity, false);
|
||||
if (defaultKvStore.getBoolean("inAppCameraLocationPref", false)) {
|
||||
locationBeforeImageCapture = locationManager.getLastLocation();
|
||||
}
|
||||
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.
|
||||
*/
|
||||
public void handleActivityResult(Activity activity, int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
FilePicker.handleActivityResult(requestCode, resultCode, data, activity,
|
||||
new DefaultCallback() {
|
||||
public void handleActivityResultWithCallback(Activity activity, FilePicker.HandleActivityResult handleActivityResult) {
|
||||
|
||||
handleActivityResult.onHandleActivityResult(new DefaultCallback() {
|
||||
|
||||
@Override
|
||||
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.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -20,6 +21,7 @@ import android.widget.LinearLayout;
|
|||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
|
@ -96,6 +98,30 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
private int contributionsSize;
|
||||
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(
|
||||
new RequestMultiplePermissions(),
|
||||
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||
|
|
@ -111,7 +137,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
||||
inAppCameraLocationPermissionLauncher);
|
||||
inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
} else {
|
||||
controller.locationPermissionCallback.onLocationPermissionDenied(
|
||||
getActivity().getString(
|
||||
|
|
@ -322,7 +348,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
private void setListeners() {
|
||||
binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
||||
binding.fabCamera.setOnClickListener(view -> {
|
||||
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher);
|
||||
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
animateFAB(isFabOpen);
|
||||
});
|
||||
binding.fabCamera.setOnLongClickListener(view -> {
|
||||
|
|
@ -330,7 +356,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
return true;
|
||||
});
|
||||
binding.fabGallery.setOnClickListener(view -> {
|
||||
controller.initiateGalleryPick(getActivity(), true);
|
||||
controller.initiateGalleryPick(getActivity(), galleryPickLauncherForResult, true);
|
||||
animateFAB(isFabOpen);
|
||||
});
|
||||
binding.fabGallery.setOnLongClickListener(view -> {
|
||||
|
|
@ -343,7 +369,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
* Launch Custom Selector.
|
||||
*/
|
||||
protected void launchCustomSelector() {
|
||||
controller.initiateCustomGalleryPickWithPermission(getActivity());
|
||||
controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult);
|
||||
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
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class WikipediaInstructionsDialogFragment : DialogFragment() {
|
|||
) = DialogAddToWikipediaInstructionsBinding
|
||||
.inflate(inflater, container, false)
|
||||
.apply {
|
||||
val contribution: Contribution? = arguments!!.getParcelable(ARG_CONTRIBUTION)
|
||||
val contribution: Contribution? = requireArguments().getParcelable(ARG_CONTRIBUTION)
|
||||
tvWikicode.setText(contribution?.media?.wikiCode)
|
||||
instructionsCancel.setOnClickListener { dismiss() }
|
||||
instructionsConfirm.setOnClickListener {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package fr.free.nrw.commons.customselector.helper
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.media.MediaScannerConnection
|
||||
|
|
@ -8,9 +7,10 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.IntentSenderRequest
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.filepicker.Constants
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
|
|
@ -22,15 +22,20 @@ object FolderDeletionHelper {
|
|||
* @param context The context used to show the confirmation dialog and manage deletion.
|
||||
* @param folder The folder to be deleted.
|
||||
* @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.
|
||||
*/
|
||||
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 folderPath = folder.absolutePath
|
||||
|
||||
//don't show this dialog on API 30+, it's handled automatically using MediaStore
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
val success = deleteFolderMain(context, folder)
|
||||
val success = deleteFolderMain(context, folder, trashFolderLauncher)
|
||||
onDeletionComplete(success)
|
||||
|
||||
} else {
|
||||
|
|
@ -40,7 +45,7 @@ object FolderDeletionHelper {
|
|||
.setPositiveButton(context.getString(R.string.custom_selector_delete)) { _, _ ->
|
||||
|
||||
//proceed with deletion if user confirms
|
||||
val success = deleteFolderMain(context, folder)
|
||||
val success = deleteFolderMain(context, folder, trashFolderLauncher)
|
||||
onDeletionComplete(success)
|
||||
}
|
||||
.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 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.
|
||||
*/
|
||||
private fun deleteFolderMain(context: Context, folder: File): Boolean {
|
||||
private fun deleteFolderMain(
|
||||
context: Context,
|
||||
folder: File,
|
||||
trashFolderLauncher: ActivityResultLauncher<IntentSenderRequest>): Boolean
|
||||
{
|
||||
return when {
|
||||
//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)
|
||||
// and below use file system
|
||||
|
|
@ -75,9 +85,14 @@ object FolderDeletionHelper {
|
|||
*
|
||||
* @param context The context used to access the content resolver.
|
||||
* @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.
|
||||
*/
|
||||
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
|
||||
|
||||
val contentResolver = context.contentResolver
|
||||
|
|
@ -111,11 +126,8 @@ object FolderDeletionHelper {
|
|||
if (urisToTrash.isNotEmpty()) {
|
||||
try {
|
||||
val trashRequest = MediaStore.createTrashRequest(contentResolver, urisToTrash, true)
|
||||
(context as? Activity)?.startIntentSenderForResult(
|
||||
trashRequest.intentSender,
|
||||
Constants.RequestCodes.DELETE_FOLDER_REQUEST_CODE,
|
||||
null, 0, 0, 0
|
||||
)
|
||||
val intentSenderRequest = IntentSenderRequest.Builder(trashRequest.intentSender).build()
|
||||
trashFolderLauncher.launch(intentSenderRequest)
|
||||
return true
|
||||
} catch (e: SecurityException) {
|
||||
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.PopupMenu
|
||||
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.layout.Row
|
||||
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.NotForUploadStatusDao
|
||||
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.listeners.FolderClickListener
|
||||
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.CustomSelectorBottomLayoutBinding
|
||||
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.theme.BaseActivity
|
||||
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
||||
|
|
@ -65,7 +66,6 @@ import java.io.File
|
|||
import java.lang.Integer.max
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* Custom Selector Activity.
|
||||
*/
|
||||
|
|
@ -155,7 +155,16 @@ class CustomSelectorActivity :
|
|||
*/
|
||||
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
|
||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
Modifier
|
||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
val view = binding.root
|
||||
|
|
@ -215,7 +224,6 @@ class CustomSelectorActivity :
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
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
|
||||
*/
|
||||
override fun onActivityResult(
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?,
|
||||
) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constants.RequestCodes.RECEIVE_DATA_FROM_FULL_SCREEN_MODE &&
|
||||
resultCode == Activity.RESULT_OK
|
||||
) {
|
||||
private fun onFullScreenDataReceived(result: ActivityResult){
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val selectedImages: ArrayList<Image> =
|
||||
data!!
|
||||
result.data!!
|
||||
.getParcelableArrayListExtra(CustomSelectorConstants.NEW_SELECTED_IMAGES)!!
|
||||
val shouldRefresh = data.getBooleanExtra(SHOULD_REFRESH, false)
|
||||
imageFragment?.passSelectedImages(selectedImages, shouldRefresh)
|
||||
viewModel?.selectedImages?.value = selectedImages
|
||||
}
|
||||
}
|
||||
|
||||
if (requestCode == Constants.RequestCodes.DELETE_FOLDER_REQUEST_CODE &&
|
||||
resultCode == Activity.RESULT_OK) {
|
||||
|
||||
private fun onDeleteFolderResultReceived(result: ActivityResult){
|
||||
if (result.resultCode == Activity.RESULT_OK){
|
||||
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
||||
navigateToCustomSelector()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
val back: ImageButton = findViewById(R.id.back)
|
||||
|
|
@ -489,9 +486,9 @@ class CustomSelectorActivity :
|
|||
return
|
||||
}
|
||||
|
||||
FolderDeletionHelper.confirmAndDeleteFolder(this, folder) { success ->
|
||||
FolderDeletionHelper.confirmAndDeleteFolder(this, folder, startForFolderDeletionResult) { 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) {
|
||||
FolderDeletionHelper.showSuccess(this, "Folder deleted successfully", bucketName)
|
||||
navigateToCustomSelector()
|
||||
|
|
@ -542,9 +539,8 @@ class CustomSelectorActivity :
|
|||
override fun onFolderClick(
|
||||
folderId: Long,
|
||||
folderName: String,
|
||||
lastItemId: Long
|
||||
lastItemId: Long,
|
||||
) {
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.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.
|
||||
*/
|
||||
|
|
@ -629,7 +624,7 @@ class CustomSelectorActivity :
|
|||
selectedImages,
|
||||
)
|
||||
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(
|
||||
modifier = modifier,
|
||||
colors =
|
||||
CardDefaults.cardColors(
|
||||
containerColor = colorResource(R.color.primarySuperLightColor),
|
||||
),
|
||||
CardDefaults.cardColors(
|
||||
containerColor = colorResource(R.color.primarySuperLightColor),
|
||||
),
|
||||
border = BorderStroke(0.5.dp, color = colorResource(R.color.primaryColor)),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
) {
|
||||
Row(modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth()) {
|
||||
Row(modifier = Modifier.padding(16.dp).fillMaxWidth()) {
|
||||
Text(
|
||||
text = "You've given access to a select number of photos",
|
||||
modifier = Modifier.weight(1f),
|
||||
|
|
@ -755,9 +748,9 @@ fun partialStorageAccessIndicator(
|
|||
onClick = onManage,
|
||||
modifier = Modifier.align(Alignment.Bottom),
|
||||
colors =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = colorResource(R.color.primaryColor),
|
||||
),
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = colorResource(R.color.primaryColor),
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
) {
|
||||
Text(
|
||||
|
|
@ -779,9 +772,9 @@ fun partialStorageAccessIndicatorPreview() {
|
|||
isVisible = true,
|
||||
onManage = {},
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
Modifier
|
||||
.padding(vertical = 8.dp, horizontal = 4.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -279,11 +279,17 @@ class ImageFragment :
|
|||
filteredImages = ImageHelper.filterImages(images, bucketId)
|
||||
allImages = ArrayList(filteredImages)
|
||||
imageAdapter.init(filteredImages, allImages, TreeMap(), uploadingContributions)
|
||||
viewModel?.selectedImages?.value?.let { selectedImages ->
|
||||
imageAdapter.setSelectedImages(selectedImages)
|
||||
}
|
||||
imageAdapter.notifyDataSetChanged()
|
||||
selectorRV?.let {
|
||||
it.visibility = View.VISIBLE
|
||||
lastItemId?.let { pos ->
|
||||
(it.layoutManager as GridLayoutManager)
|
||||
.scrollToPosition(ImageHelper.getIndexFromId(filteredImages, pos))
|
||||
if (switch?.isChecked == false) {
|
||||
lastItemId?.let { pos ->
|
||||
(it.layoutManager as GridLayoutManager)
|
||||
.scrollToPosition(ImageHelper.getIndexFromId(filteredImages, pos))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -382,14 +388,6 @@ class ImageFragment :
|
|||
selectedImages: ArrayList<Image>,
|
||||
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 kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Calendar
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.speech.RecognizerIntent
|
||||
import android.view.View
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
|
|
@ -70,10 +72,14 @@ class DescriptionEditActivity :
|
|||
|
||||
private lateinit var binding: ActivityDescriptionEditBinding
|
||||
|
||||
private val requestCodeForVoiceInput = 1213
|
||||
|
||||
private var descriptionAndCaptions: ArrayList<UploadMediaDetail>? = null
|
||||
|
||||
private val voiceInputResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result: ActivityResult ->
|
||||
onVoiceInput(result)
|
||||
}
|
||||
|
||||
@Inject lateinit var descriptionEditHelper: DescriptionEditHelper
|
||||
|
||||
@Inject lateinit var sessionManager: SessionManager
|
||||
|
|
@ -115,6 +121,7 @@ class DescriptionEditActivity :
|
|||
savedLanguageValue,
|
||||
descriptionAndCaptions,
|
||||
recentLanguagesDao,
|
||||
voiceInputResultLauncher
|
||||
)
|
||||
uploadMediaDetailAdapter.setCallback { titleStringID: Int, messageStringId: Int ->
|
||||
showInfoAlert(
|
||||
|
|
@ -149,6 +156,15 @@ class DescriptionEditActivity :
|
|||
|
||||
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
|
||||
*/
|
||||
|
|
@ -221,7 +237,7 @@ class DescriptionEditActivity :
|
|||
) {
|
||||
try {
|
||||
descriptionEditHelper
|
||||
?.addDescription(
|
||||
.addDescription(
|
||||
applicationContext,
|
||||
media,
|
||||
updatedWikiText,
|
||||
|
|
@ -234,7 +250,7 @@ class DescriptionEditActivity :
|
|||
)
|
||||
}
|
||||
} catch (e: InvalidLoginTokenException) {
|
||||
val username: String? = sessionManager?.userName
|
||||
val username: String? = sessionManager.userName
|
||||
val logoutListener =
|
||||
CommonsApplication.BaseLogoutListener(
|
||||
this,
|
||||
|
|
@ -242,7 +258,7 @@ class DescriptionEditActivity :
|
|||
username,
|
||||
)
|
||||
|
||||
val commonsApplication = CommonsApplication.getInstance()
|
||||
val commonsApplication = CommonsApplication.instance
|
||||
if (commonsApplication != null) {
|
||||
commonsApplication.clearApplicationData(this, logoutListener)
|
||||
}
|
||||
|
|
@ -252,7 +268,7 @@ class DescriptionEditActivity :
|
|||
for (mediaDetail in uploadMediaDetails) {
|
||||
try {
|
||||
compositeDisposable.add(
|
||||
descriptionEditHelper!!
|
||||
descriptionEditHelper
|
||||
.addCaption(
|
||||
applicationContext,
|
||||
media,
|
||||
|
|
@ -275,7 +291,7 @@ class DescriptionEditActivity :
|
|||
username,
|
||||
)
|
||||
|
||||
val commonsApplication = CommonsApplication.getInstance()
|
||||
val commonsApplication = CommonsApplication.instance
|
||||
if (commonsApplication != null) {
|
||||
commonsApplication.clearApplicationData(this, logoutListener)
|
||||
}
|
||||
|
|
@ -292,22 +308,6 @@ class DescriptionEditActivity :
|
|||
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) {
|
||||
super.onSaveInstanceState(outState)
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ class TransformImageImpl : TransformImage {
|
|||
} catch (e: LLJTranException) {
|
||||
Timber.tag("Error").d(e)
|
||||
return null
|
||||
false
|
||||
}
|
||||
|
||||
if (rotated) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import fr.free.nrw.commons.theme.BaseActivity;
|
|||
import fr.free.nrw.commons.utils.ActivityUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
|
|
@ -112,13 +113,13 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
|
|||
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
|
||||
mapRootFragment = new ExploreMapRootFragment(mapArguments);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
|
@ -95,11 +96,11 @@ public class SearchActivity extends BaseActivity
|
|||
searchDepictionsFragment = new SearchDepictionsFragment();
|
||||
searchCategoryFragment= new SearchCategoryFragment();
|
||||
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);
|
||||
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);
|
||||
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.notifyDataSetChanged();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,6 @@ class CategoriesMediaFragment : PageableMediaFragment() {
|
|||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
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?,
|
||||
) {
|
||||
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?,
|
||||
) {
|
||||
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
|
||||
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(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
||||
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,6 @@ class DepictedImagesFragment : PageableMediaFragment() {
|
|||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
||||
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ class ParentDepictionsFragment : PageableDepictionsFragment() {
|
|||
override val injectedPresenter
|
||||
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(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
onQueryUpdated(arguments!!.getString("entityId")!!)
|
||||
onQueryUpdated(requireArguments().getString("entityId")!!)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class MediaConverter
|
|||
metadata.licenseShortName(),
|
||||
metadata.prefixedLicenseUrl,
|
||||
getAuthor(metadata),
|
||||
imageInfo.user,
|
||||
getAuthor(metadata),
|
||||
MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories),
|
||||
metadata.latLng,
|
||||
entity.labels().mapValues { it.value.value() },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.explore.recentsearches;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -178,6 +179,7 @@ public class RecentSearchesDao {
|
|||
* @return RecentSearch object
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressLint("Range")
|
||||
RecentSearch fromCursor(Cursor cursor) {
|
||||
// Hardcoding column positions!
|
||||
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.explore.SearchActivity;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
|
|
@ -90,7 +91,7 @@ public class RecentSearchesFragment extends CommonsDaggerSupportFragment {
|
|||
private void showDeleteAlertDialog(@NonNull final Context context, final int position) {
|
||||
new AlertDialog.Builder(context)
|
||||
.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)))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
|
|
|
|||
|
|
@ -4,23 +4,12 @@ public interface Constants {
|
|||
String DEFAULT_FOLDER_NAME = "CommonsContributions";
|
||||
|
||||
/**
|
||||
* Provides the request codes utilised by the FilePicker
|
||||
* Provides the request codes for permission handling
|
||||
*/
|
||||
interface RequestCodes {
|
||||
int LOCATION = 1;
|
||||
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.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
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
|
||||
*/
|
||||
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);
|
||||
activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_GALLERY);
|
||||
resultLauncher.launch(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
activity.startActivityForResult(intent, RequestCodes.PICK_PICTURE_FROM_CUSTOM_SELECTOR);
|
||||
resultLauncher.launch(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
activity.startActivityForResult(intent, RequestCodes.TAKE_PICTURE);
|
||||
resultLauncher.launch(intent);
|
||||
}
|
||||
|
||||
@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) {
|
||||
try {
|
||||
return getFilesFromGalleryPictures(data, activity);
|
||||
|
|
@ -241,18 +202,22 @@ public class FilePicker implements Constants {
|
|||
return intent;
|
||||
}
|
||||
|
||||
private static void onPictureReturnedFromDocuments(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
try {
|
||||
Uri photoPath = data.getData();
|
||||
UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath);
|
||||
callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||
public static void onPictureReturnedFromDocuments(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){
|
||||
try {
|
||||
Uri photoPath = result.getData().getData();
|
||||
UploadableFile photoFile = PickedFiles.pickedExistingPicture(activity, photoPath);
|
||||
callbacks.onImagesPicked(singleFileList(photoFile), FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||
|
||||
if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) {
|
||||
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
||||
if (configuration(activity).shouldCopyPickedImagesToPublicGalleryAppFolder()) {
|
||||
PickedFiles.copyFilesInSeparateThread(activity, singleFileList(photoFile));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||
} else {
|
||||
callbacks.onCanceled(FilePicker.ImageSource.DOCUMENTS, restoreType(activity));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,14 +225,18 @@ public class FilePicker implements Constants {
|
|||
* onPictureReturnedFromCustomSelector.
|
||||
* Retrieve and forward the images to upload wizard through callback.
|
||||
*/
|
||||
private static void onPictureReturnedFromCustomSelector(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
try {
|
||||
List<UploadableFile> files = getFilesFromCustomSelector(data, activity);
|
||||
callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
callbacks.onImagePickerError(e, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||
}
|
||||
public static void onPictureReturnedFromCustomSelector(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
if(result.getResultCode() == Activity.RESULT_OK){
|
||||
try {
|
||||
List<UploadableFile> files = getFilesFromCustomSelector(result.getData(), activity);
|
||||
callbacks.onImagesPicked(files, ImageSource.CUSTOM_SELECTOR, restoreType(activity));
|
||||
} catch (Exception e) {
|
||||
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;
|
||||
}
|
||||
|
||||
private static void onPictureReturnedFromGallery(Intent data, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
try {
|
||||
List<UploadableFile> files = getFilesFromGalleryPictures(data, activity);
|
||||
callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||
public static void onPictureReturnedFromGallery(ActivityResult result, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
if(result.getResultCode() == Activity.RESULT_OK && !isPhoto(result.getData())){
|
||||
try {
|
||||
List<UploadableFile> files = getFilesFromGalleryPictures(result.getData(), activity);
|
||||
callbacks.onImagesPicked(files, FilePicker.ImageSource.GALLERY, restoreType(activity));
|
||||
} catch (Exception e) {
|
||||
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;
|
||||
}
|
||||
|
||||
private static void onPictureReturnedFromCamera(Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
try {
|
||||
String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null);
|
||||
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));
|
||||
public static void onPictureReturnedFromCamera(ActivityResult activityResult, Activity activity, @NonNull FilePicker.Callbacks callbacks) {
|
||||
if(activityResult.getResultCode() == Activity.RESULT_OK){
|
||||
try {
|
||||
String lastImageUri = PreferenceManager.getDefaultSharedPreferences(activity).getString(KEY_PHOTO_URI, null);
|
||||
if (!TextUtils.isEmpty(lastImageUri)) {
|
||||
revokeWritePermission(activity, Uri.parse(lastImageUri));
|
||||
}
|
||||
|
||||
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()
|
||||
.remove(KEY_LAST_CAMERA_PHOTO)
|
||||
.remove(KEY_PHOTO_URI)
|
||||
.apply();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
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));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
callbacks.onImagePickerError(e, FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||
}
|
||||
|
||||
UploadableFile photoFile = FilePicker.takenCameraVideo(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));
|
||||
} else {
|
||||
callbacks.onCanceled(FilePicker.ImageSource.CAMERA_IMAGE, restoreType(activity));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -404,4 +348,8 @@ public class FilePicker implements Constants {
|
|||
|
||||
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;
|
||||
|
||||
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.VISIBLE;
|
||||
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.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.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION;
|
||||
import static fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources;
|
||||
|
|
@ -112,8 +109,6 @@ import timber.log.Timber;
|
|||
public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
||||
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";
|
||||
static final int DEFAULT_IMAGE_BACKGROUND_COLOR = 0;
|
||||
|
||||
|
|
@ -277,6 +272,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
|
||||
if (!sessionManager.isUserLoggedIn()) {
|
||||
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")){
|
||||
|
|
@ -405,7 +406,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
}
|
||||
);
|
||||
binding.progressBarEdit.setVisibility(GONE);
|
||||
binding.descriptionEdit.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -605,8 +605,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
// Check if the presented category is about need of category
|
||||
if (categoriesPresent) {
|
||||
for (String category : media.getCategories()) {
|
||||
if (category.toLowerCase().contains(CATEGORY_NEEDING_CATEGORIES) ||
|
||||
category.toLowerCase().contains(CATEGORY_UNCATEGORISED)) {
|
||||
if (category.toLowerCase(Locale.ROOT).contains(CATEGORY_NEEDING_CATEGORIES) ||
|
||||
category.toLowerCase(Locale.ROOT).contains(CATEGORY_UNCATEGORISED)) {
|
||||
categoriesPresent = false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -683,7 +683,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
// Stick in a filler element.
|
||||
allCategories.add(getString(R.string.detail_panel_cats_none));
|
||||
}
|
||||
binding.categoryEditButton.setVisibility(VISIBLE);
|
||||
if(sessionManager.isUserLoggedIn()) {
|
||||
binding.categoryEditButton.setVisibility(VISIBLE);
|
||||
}
|
||||
rebuildCatList(allCategories);
|
||||
}
|
||||
|
||||
|
|
@ -1065,81 +1067,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
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
|
||||
* @param mediaDetail UploadMediaDetail
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
onSwipe()
|
||||
}
|
||||
}
|
||||
binding.zoomProgressBar?.let {
|
||||
binding.zoomProgressBar.let {
|
||||
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)
|
||||
|
||||
if (!images.isNullOrEmpty()) {
|
||||
binding.zoomable!!.setOnTouchListener(
|
||||
binding.zoomable.setOnTouchListener(
|
||||
object : OnSwipeTouchListener(this) {
|
||||
// Swipe left to view next image in the folder. (if available)
|
||||
override fun onSwipeLeft() {
|
||||
|
|
@ -271,7 +271,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
* Handles down swipe action
|
||||
*/
|
||||
private fun onDownSwiped() {
|
||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
||||
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +341,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
* Handles up swipe action
|
||||
*/
|
||||
private fun onUpSwiped() {
|
||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
||||
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
* Handles right swipe action
|
||||
*/
|
||||
private fun onRightSwiped(showAlreadyActionedImages: Boolean) {
|
||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
||||
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -451,7 +451,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
* Handles left swipe action
|
||||
*/
|
||||
private fun onLeftSwiped(showAlreadyActionedImages: Boolean) {
|
||||
if (binding.zoomable?.zoomableController?.isIdentity == false) {
|
||||
if (binding.zoomable.zoomableController?.isIdentity == false) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -646,7 +646,7 @@ class ZoomableActivity : BaseActivity() {
|
|||
.setProgressBarImage(ProgressBarDrawable())
|
||||
.setProgressBarImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||
.build()
|
||||
with(binding.zoomable!!) {
|
||||
with(binding.zoomable) {
|
||||
setHierarchy(hierarchy)
|
||||
setAllowTouchInterceptionWhileZoomed(true)
|
||||
setIsLongpressEnabled(false)
|
||||
|
|
@ -658,10 +658,10 @@ class ZoomableActivity : BaseActivity() {
|
|||
.setUri(imageUri)
|
||||
.setControllerListener(loadingListener)
|
||||
.build()
|
||||
binding.zoomable!!.controller = controller
|
||||
binding.zoomable.controller = controller
|
||||
|
||||
if (photoBackgroundColor != null) {
|
||||
binding.zoomable!!.setBackgroundColor(photoBackgroundColor!!)
|
||||
binding.zoomable.setBackgroundColor(photoBackgroundColor!!)
|
||||
}
|
||||
|
||||
if (!images.isNullOrEmpty()) {
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ public class OkHttpJsonApiClient {
|
|||
throws Exception {
|
||||
|
||||
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;
|
||||
if (customQuery != null) {
|
||||
wikidataQuery = customQuery;
|
||||
|
|
@ -344,7 +344,7 @@ public class OkHttpJsonApiClient {
|
|||
final boolean shouldQueryForMonuments, final String customQuery)
|
||||
throws Exception {
|
||||
|
||||
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
|
||||
Timber.d("CUSTOM_SPARQL: %s", String.valueOf(customQuery != null));
|
||||
|
||||
final String wikidataQuery;
|
||||
if (customQuery != null) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import java.util.Locale;
|
||||
|
||||
public class NearbyFilterSearchRecyclerViewAdapter
|
||||
extends RecyclerView.Adapter<NearbyFilterSearchRecyclerViewAdapter.RecyclerViewHolder>
|
||||
|
|
@ -121,11 +122,11 @@ public class NearbyFilterSearchRecyclerViewAdapter
|
|||
results.count = labels.size();
|
||||
results.values = labels;
|
||||
} else {
|
||||
constraint = constraint.toString().toLowerCase();
|
||||
constraint = constraint.toString().toLowerCase(Locale.ROOT);
|
||||
|
||||
for (Label label : labels) {
|
||||
String data = label.toString();
|
||||
if (data.toLowerCase().startsWith(constraint.toString())) {
|
||||
if (data.toLowerCase(Locale.ROOT).startsWith(constraint.toString())) {
|
||||
filteredArrayList.add(Label.fromText(label.getText()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
|
|
@ -17,9 +18,9 @@ import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
|||
fun placeAdapterDelegate(
|
||||
bookmarkLocationDao: BookmarkLocationsDao,
|
||||
onItemClick: ((Place) -> Unit)? = null,
|
||||
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>) -> Unit,
|
||||
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
|
||||
onCameraLongPressed: () -> Boolean,
|
||||
onGalleryClicked: (Place) -> Unit,
|
||||
onGalleryClicked: (Place, ActivityResultLauncher<Intent>) -> Unit,
|
||||
onGalleryLongPressed: () -> Boolean,
|
||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||
onBookmarkLongPressed: () -> Boolean,
|
||||
|
|
@ -28,6 +29,8 @@ fun placeAdapterDelegate(
|
|||
onDirectionsClicked: (Place) -> Unit,
|
||||
onDirectionsLongPressed: () -> Boolean,
|
||||
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
||||
cameraPickLauncherForResult: ActivityResultLauncher<Intent>,
|
||||
galleryPickLauncherForResult: ActivityResultLauncher<Intent>
|
||||
) = adapterDelegateViewBinding<Place, Place, ItemPlaceBinding>({ layoutInflater, parent ->
|
||||
ItemPlaceBinding.inflate(layoutInflater, parent, false)
|
||||
}) {
|
||||
|
|
@ -44,10 +47,10 @@ fun placeAdapterDelegate(
|
|||
onItemClick?.invoke(item)
|
||||
}
|
||||
}
|
||||
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher) }
|
||||
nearbyButtonLayout.cameraButton.setOnClickListener { onCameraClicked(item, inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult) }
|
||||
nearbyButtonLayout.cameraButton.setOnLongClickListener { onCameraLongPressed() }
|
||||
|
||||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item) }
|
||||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) }
|
||||
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
||||
bookmarkButtonImage.setOnClickListener {
|
||||
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import androidx.room.Dao;
|
|||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import io.reactivex.Completable;
|
||||
|
||||
/**
|
||||
|
|
@ -38,8 +37,21 @@ public abstract class PlaceDao {
|
|||
*/
|
||||
public Completable save(final Place place) {
|
||||
return Completable
|
||||
.fromAction(() -> {
|
||||
saveSynchronous(place);
|
||||
});
|
||||
.fromAction(() -> 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;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import io.reactivex.Completable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
|
@ -36,4 +35,8 @@ public class PlacesLocalDataSource {
|
|||
public Completable savePlace(Place 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.location.LatLng;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
|
|
@ -38,4 +39,13 @@ public class PlacesRepository {
|
|||
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,
|
||||
lng,
|
||||
)
|
||||
} as Callable<SingleSource<Boolean?>>,
|
||||
},
|
||||
).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ aBoolean: Boolean? ->
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ class CommonPlaceClickActions
|
|||
private val activity: Activity,
|
||||
private val contributionController: ContributionController,
|
||||
) {
|
||||
fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>) -> Unit =
|
||||
{ place, launcher ->
|
||||
fun onCameraClicked(): (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit =
|
||||
{ place, launcher, resultLauncher ->
|
||||
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
||||
showLoginDialog()
|
||||
} else {
|
||||
Timber.d("Camera button tapped. Image title: ${place.getName()}Image desc: ${place.longDescription}")
|
||||
storeSharedPrefs(place)
|
||||
contributionController.initiateCameraPick(activity, launcher)
|
||||
contributionController.initiateCameraPick(activity, launcher, resultLauncher)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,14 +72,14 @@ class CommonPlaceClickActions
|
|||
true
|
||||
}
|
||||
|
||||
fun onGalleryClicked(): (Place) -> Unit =
|
||||
{
|
||||
fun onGalleryClicked(): (Place, ActivityResultLauncher<Intent>) -> Unit =
|
||||
{place, galleryPickLauncherForResult ->
|
||||
if (applicationKvStore.getBoolean("login_skipped", false)) {
|
||||
showLoginDialog()
|
||||
} else {
|
||||
Timber.d("Gallery button tapped. Image title: ${it.getName()}Image desc: ${it.getLongDescription()}")
|
||||
storeSharedPrefs(it)
|
||||
contributionController.initiateGalleryPick(activity, false)
|
||||
Timber.d("Gallery button tapped. Image title: ${place.getName()}Image desc: ${place.getLongDescription()}")
|
||||
storeSharedPrefs(place)
|
||||
contributionController.initiateGalleryPick(activity, galleryPickLauncherForResult, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,15 +43,18 @@ import android.view.ViewGroup;
|
|||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog.Builder;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
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.ViewUtil;
|
||||
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
|
@ -218,9 +222,36 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
private LatLng updatedLatLng;
|
||||
private boolean searchable;
|
||||
|
||||
private ConstraintLayout nearbyLegend;
|
||||
|
||||
private GridLayoutManager gridLayoutManager;
|
||||
private List<BottomSheetItem> dataList;
|
||||
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(
|
||||
new RequestMultiplePermissions(),
|
||||
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||
|
|
@ -236,7 +267,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
||||
inAppCameraLocationPermissionLauncher);
|
||||
inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
} else {
|
||||
controller.locationPermissionCallback.onLocationPermissionDenied(
|
||||
getActivity().getString(
|
||||
|
|
@ -302,6 +333,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
progressDialog.setCancelable(false);
|
||||
progressDialog.setMessage("Saving in progress...");
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
// Inflate the layout for this fragment
|
||||
return view;
|
||||
|
||||
|
|
@ -311,9 +343,21 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
||||
@NonNull final MenuInflater inflater) {
|
||||
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 saveAsGPXButton = menu.findItem(R.id.list_item_gpx);
|
||||
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() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
|
|
@ -362,6 +406,16 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}
|
||||
locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager,
|
||||
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);
|
||||
isPermissionDenied = false;
|
||||
recenterToUserLocation = false;
|
||||
|
|
@ -555,7 +609,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
return Unit.INSTANCE;
|
||||
},
|
||||
commonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
galleryPickLauncherForResult,
|
||||
cameraPickLauncherForResult
|
||||
);
|
||||
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() {
|
||||
final Observable<String> savePlacesObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
|
|
@ -2186,7 +2284,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
if (binding.fabCamera.isShown()) {
|
||||
Timber.d("Camera button tapped. Place: %s", selectedPlace.toString());
|
||||
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());
|
||||
storeSharedPrefs(selectedPlace);
|
||||
controller.initiateGalleryPick(getActivity(),
|
||||
galleryPickLauncherForResult,
|
||||
false);
|
||||
}
|
||||
});
|
||||
|
|
@ -2203,7 +2302,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
if (binding.fabCustomGallery.isShown()) {
|
||||
Timber.d("Gallery button tapped. Place: %s", selectedPlace.toString());
|
||||
storeSharedPrefs(selectedPlace);
|
||||
controller.initiateCustomGalleryPickWithPermission(getActivity());
|
||||
controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
|
|
@ -12,6 +13,8 @@ class PlaceAdapter(
|
|||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||
commonPlaceClickActions: CommonPlaceClickActions,
|
||||
inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>,
|
||||
galleryPickLauncherForResult: ActivityResultLauncher<Intent>,
|
||||
cameraPickLauncherForResult: ActivityResultLauncher<Intent>
|
||||
) : BaseDelegateAdapter<Place>(
|
||||
placeAdapterDelegate(
|
||||
bookmarkLocationsDao,
|
||||
|
|
@ -27,6 +30,8 @@ class PlaceAdapter(
|
|||
commonPlaceClickActions.onDirectionsClicked(),
|
||||
commonPlaceClickActions.onDirectionsLongPressed(),
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
cameraPickLauncherForResult,
|
||||
galleryPickLauncherForResult
|
||||
),
|
||||
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.csrf.InvalidLoginTokenException;
|
||||
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.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
|
|
@ -148,7 +149,11 @@ public class NotificationActivity extends BaseActivity {
|
|||
}
|
||||
adapter = new NotificatinAdapter(item -> {
|
||||
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);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -51,13 +51,23 @@ class NotificationClient
|
|||
}
|
||||
}
|
||||
|
||||
private fun WikimediaNotification.toCommonsNotification() =
|
||||
Notification(
|
||||
notificationType = NotificationType.UNKNOWN,
|
||||
notificationText = contents?.compactHeader ?: "",
|
||||
date = DateUtil.getMonthOnlyDateString(timestamp),
|
||||
link = contents?.links?.primary?.url ?: "",
|
||||
iconUrl = "",
|
||||
notificationId = id().toString(),
|
||||
)
|
||||
private fun WikimediaNotification.toCommonsNotification() :
|
||||
Notification {
|
||||
val notificationText = contents?.compactHeader ?: ""
|
||||
val notificationType =
|
||||
if (notificationText.contains("Sent you an email", ignoreCase = true)) {
|
||||
NotificationType.EMAIL
|
||||
} else {
|
||||
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"),
|
||||
EDIT_USER_TALK("edit-user-talk"),
|
||||
MENTION("mention"),
|
||||
EMAIL("email"),
|
||||
WELCOME("welcome"),
|
||||
UNKNOWN("unknown");
|
||||
private String type;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
|
|
@ -139,14 +140,14 @@ public class ProfileActivity extends BaseActivity {
|
|||
leaderboardFragment.setArguments(leaderBoardBundle);
|
||||
|
||||
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();
|
||||
Bundle contributionsListBundle = new Bundle();
|
||||
contributionsListBundle.putString(KEY_USERNAME, userName);
|
||||
contributionsFragment.setArguments(contributionsListBundle);
|
||||
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.notifyDataSetChanged();
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import fr.free.nrw.commons.profile.ProfileActivity;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
|
@ -361,7 +362,7 @@ public class AchievementsFragment extends CommonsDaggerSupportFragment {
|
|||
+ levelInfo.getMaxUniqueImages());
|
||||
binding.imageFeatured.setText(String.valueOf(achievements.getFeaturedImages()));
|
||||
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();
|
||||
binding.achievementLevel.setText(levelUpInfoString);
|
||||
binding.achievementBadgeImage.setImageDrawable(VectorDrawableCompat.create(getResources(), R.drawable.badge,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.recentlanguages;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
|
@ -117,6 +118,7 @@ public class RecentLanguagesDao {
|
|||
* @return Language object
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressLint("Range")
|
||||
Language fromCursor(final Cursor cursor) {
|
||||
// Hardcoding column positions!
|
||||
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.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class ReviewActivity extends BaseActivity {
|
||||
|
|
@ -241,7 +242,7 @@ public class ReviewActivity extends BaseActivity {
|
|||
|
||||
public void showSkipImageInfo(){
|
||||
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(android.R.string.ok),
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import android.widget.TextView;
|
|||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.MultiSelectListPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
|
@ -88,6 +89,15 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
private View separator;
|
||||
private ListView languageHistoryListView;
|
||||
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>>() {
|
||||
@Override
|
||||
public void onActivityResult(Map<String, Boolean> result) {
|
||||
|
|
@ -96,7 +106,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
areAllGranted = areAllGranted && b;
|
||||
}
|
||||
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)) {
|
||||
userName = sessionManager!!.getUserName()
|
||||
userName = sessionManager.getUserName()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,8 +96,8 @@ class FailedUploadsFragment :
|
|||
fun initRecyclerView() {
|
||||
binding.failedUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||
binding.failedUploadsRecyclerView.adapter = adapter
|
||||
pendingUploadsPresenter!!.getFailedContributions()
|
||||
pendingUploadsPresenter!!.failedContributionList.observe(
|
||||
pendingUploadsPresenter.getFailedContributions()
|
||||
pendingUploadsPresenter.failedContributionList.observe(
|
||||
viewLifecycleOwner,
|
||||
) { list: PagedList<Contribution?> ->
|
||||
adapter.submitList(list)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import java.math.BigInteger;
|
|||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import java.util.Locale;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class FileUtils {
|
||||
|
|
@ -139,7 +140,7 @@ public class FileUtils {
|
|||
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri
|
||||
.toString());
|
||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
|
||||
fileExtension.toLowerCase());
|
||||
fileExtension.toLowerCase(Locale.getDefault()));
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ class PendingUploadsFragment :
|
|||
fun initRecyclerView() {
|
||||
binding.pendingUploadsRecyclerView.setLayoutManager(LinearLayoutManager(this.context))
|
||||
binding.pendingUploadsRecyclerView.adapter = adapter
|
||||
pendingUploadsPresenter!!.setup()
|
||||
pendingUploadsPresenter!!.totalContributionList.observe(
|
||||
pendingUploadsPresenter.setup()
|
||||
pendingUploadsPresenter.totalContributionList.observe(
|
||||
viewLifecycleOwner,
|
||||
) { list: PagedList<Contribution?> ->
|
||||
contributionsSize = list.size
|
||||
|
|
|
|||
|
|
@ -320,6 +320,14 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
|||
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
|
||||
*/
|
||||
|
|
@ -433,14 +441,6 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
|||
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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@ public interface UploadContract {
|
|||
|
||||
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();
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import android.widget.ImageView;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
|
@ -57,27 +58,29 @@ public class UploadMediaDetailAdapter extends
|
|||
private int currentPosition;
|
||||
private Fragment fragment;
|
||||
private Activity activity;
|
||||
private final ActivityResultLauncher<Intent> voiceInputResultLauncher;
|
||||
private SelectedVoiceIcon selectedVoiceIcon;
|
||||
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
||||
|
||||
private RowItemDescriptionBinding binding;
|
||||
|
||||
public UploadMediaDetailAdapter(Fragment fragment, String savedLanguageValue,
|
||||
RecentLanguagesDao recentLanguagesDao) {
|
||||
RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher<Intent> voiceInputResultLauncher) {
|
||||
uploadMediaDetails = new ArrayList<>();
|
||||
selectedLanguages = new HashMap<>();
|
||||
this.savedLanguageValue = savedLanguageValue;
|
||||
this.recentLanguagesDao = recentLanguagesDao;
|
||||
this.fragment = fragment;
|
||||
this.voiceInputResultLauncher = voiceInputResultLauncher;
|
||||
}
|
||||
|
||||
public UploadMediaDetailAdapter(Activity activity, final String savedLanguageValue,
|
||||
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao) {
|
||||
List<UploadMediaDetail> uploadMediaDetails, RecentLanguagesDao recentLanguagesDao, ActivityResultLauncher<Intent> voiceInputResultLauncher) {
|
||||
this.uploadMediaDetails = uploadMediaDetails;
|
||||
selectedLanguages = new HashMap<>();
|
||||
this.savedLanguageValue = savedLanguageValue;
|
||||
this.recentLanguagesDao = recentLanguagesDao;
|
||||
this.activity = activity;
|
||||
this.voiceInputResultLauncher = voiceInputResultLauncher;
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
|
|
@ -150,11 +153,7 @@ public class UploadMediaDetailAdapter extends
|
|||
);
|
||||
|
||||
try {
|
||||
if (activity == null) {
|
||||
fragment.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
||||
} else {
|
||||
activity.startActivityForResult(intent, REQUEST_CODE_FOR_VOICE_INPUT);
|
||||
}
|
||||
voiceInputResultLauncher.launch(intent);
|
||||
} catch (Exception e) {
|
||||
Timber.e(e.getMessage());
|
||||
}
|
||||
|
|
@ -407,7 +406,7 @@ public class UploadMediaDetailAdapter extends
|
|||
recentLanguagesDao
|
||||
.addRecentLanguage(new Language(languageName, languageCode));
|
||||
|
||||
selectedLanguages.remove(position);
|
||||
selectedLanguages.clear();
|
||||
selectedLanguages.put(position, languageCode);
|
||||
((LanguagesAdapter) adapterView
|
||||
.getAdapter()).setSelectedLangCode(languageCode);
|
||||
|
|
@ -497,7 +496,7 @@ public class UploadMediaDetailAdapter extends
|
|||
}
|
||||
recentLanguagesDao.addRecentLanguage(new Language(languageName, languageCode));
|
||||
|
||||
selectedLanguages.remove(position);
|
||||
selectedLanguages.clear();
|
||||
selectedLanguages.put(position, languageCode);
|
||||
((RecentLanguagesAdapter) adapterView
|
||||
.getAdapter()).setSelectedLangCode(languageCode);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
|||
view.returnToMainActivity();
|
||||
compositeDisposable.clear();
|
||||
Timber.e("failed to upload: " + e.getMessage());
|
||||
|
||||
//is submission error, not need to go to the uploadActivity
|
||||
//not start the uploading progress
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -131,6 +134,10 @@ public class UploadPresenter implements UploadContract.UserActionListener {
|
|||
repository.cleanup();
|
||||
view.returnToMainActivity();
|
||||
compositeDisposable.clear();
|
||||
|
||||
//after finish the uploadActivity, if successful,
|
||||
//directly go to the upload progress activity
|
||||
view.goToUploadProgressActivity();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,15 +10,13 @@ abstract class BaseDelegateAdapter<T>(
|
|||
areContentsTheSame: (T, T) -> Boolean = { old, new -> old == new },
|
||||
) : AsyncListDifferDelegationAdapter<T>(
|
||||
object : DiffUtil.ItemCallback<T>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: T,
|
||||
newItem: T,
|
||||
) = areItemsTheSame(oldItem, newItem)
|
||||
override fun areItemsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
|
||||
return areItemsTheSame(oldItem, newItem)
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: T,
|
||||
newItem: T,
|
||||
) = areContentsTheSame(oldItem, newItem)
|
||||
override fun areContentsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
|
||||
return areContentsTheSame(oldItem, newItem)
|
||||
}
|
||||
},
|
||||
*delegates,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
|||
return false;
|
||||
});
|
||||
|
||||
Objects.requireNonNull(getView()).setFocusableInTouchMode(true);
|
||||
requireView().setFocusableInTouchMode(true);
|
||||
getView().requestFocus();
|
||||
getView().setOnKeyListener((v, keyCode, event) -> {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
|
|
@ -387,7 +387,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
|||
});
|
||||
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||
.hide();
|
||||
|
||||
if (getParentFragment().getParentFragment().getParentFragment()
|
||||
|
|
@ -407,7 +407,7 @@ public class UploadCategoriesFragment extends UploadBaseFragment implements Cate
|
|||
super.onStop();
|
||||
if (media != null) {
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ abstract class DepictsDao {
|
|||
/**
|
||||
* 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>> =
|
||||
CoroutineScope(Dispatchers.IO).async {
|
||||
|
|
@ -48,7 +48,7 @@ abstract class DepictsDao {
|
|||
*
|
||||
* @param depictedItem The Depicts object to insert.
|
||||
*/
|
||||
private fun insertDepict(depictedItem: Depicts) =
|
||||
fun insertDepict(depictedItem: Depicts) =
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
insert(depictedItem)
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ abstract class DepictsDao {
|
|||
* @param n The number of depicts 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 {
|
||||
getDepictsForDeletion(n)
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ abstract class DepictsDao {
|
|||
*
|
||||
* @param depicts The Depicts object to delete.
|
||||
*/
|
||||
private suspend fun deleteDepicts(depicts: Depicts) =
|
||||
fun deleteDepicts(depicts: Depicts) =
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
delete(depicts)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
return false;
|
||||
});
|
||||
|
||||
Objects.requireNonNull(getView()).setFocusableInTouchMode(true);
|
||||
requireView().setFocusableInTouchMode(true);
|
||||
getView().requestFocus();
|
||||
getView().setOnKeyListener((v, keyCode, event) -> {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
|
|
@ -411,7 +411,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
});
|
||||
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||
.hide();
|
||||
|
||||
if (getParentFragment().getParentFragment().getParentFragment()
|
||||
|
|
@ -431,7 +431,7 @@ public class DepictsFragment extends UploadBaseFragment implements DepictsContra
|
|||
super.onStop();
|
||||
if (media != null) {
|
||||
Objects.requireNonNull(
|
||||
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar())
|
||||
((AppCompatActivity) requireActivity()).getSupportActionBar())
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ import android.view.ViewGroup;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
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.Nullable;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
|
@ -58,9 +61,24 @@ import timber.log.Timber;
|
|||
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
||||
|
||||
private static final int REQUEST_CODE = 1211;
|
||||
private static final int REQUEST_CODE_FOR_EDIT_ACTIVITY = 1212;
|
||||
private static final int REQUEST_CODE_FOR_VOICE_INPUT = 1213;
|
||||
private UploadMediaDetailAdapter uploadMediaDetailAdapter;
|
||||
|
||||
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 ;
|
||||
|
||||
|
|
@ -84,8 +102,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
private boolean hasUserRemovedLocation;
|
||||
|
||||
|
||||
private UploadMediaDetailAdapter uploadMediaDetailAdapter;
|
||||
|
||||
@Inject
|
||||
UploadMediaDetailsContract.UserActionListener presenter;
|
||||
|
||||
|
|
@ -279,7 +295,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
*/
|
||||
private void initRecyclerView() {
|
||||
uploadMediaDetailAdapter = new UploadMediaDetailAdapter(this,
|
||||
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao);
|
||||
defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, ""), recentLanguagesDao, voiceInputResultLauncher);
|
||||
uploadMediaDetailAdapter.setCallback(this::showInfoAlert);
|
||||
uploadMediaDetailAdapter.setEventListener(this);
|
||||
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.
|
||||
* 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
|
||||
* 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
|
||||
public void showEditActivity(UploadItem uploadItem) {
|
||||
editableUploadItem = uploadItem;
|
||||
Intent intent = new Intent(getContext(), EditActivity.class);
|
||||
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 defaultZoom = 16.0;
|
||||
|
||||
final Intent locationPickerIntent;
|
||||
|
||||
/* Retrieve image location from EXIF if present or
|
||||
check if user has provided location while using the in-app camera.
|
||||
Use location of last UploadItem if none of them is available */
|
||||
|
|
@ -624,10 +642,11 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
.getDecLatitude();
|
||||
defaultLongitude = uploadItem.getGpsCoords().getDecLongitude();
|
||||
defaultZoom = uploadItem.getGpsCoords().getZoomLevel();
|
||||
startActivityForResult(new LocationPicker.IntentBuilder()
|
||||
|
||||
locationPickerIntent = new LocationPicker.IntentBuilder()
|
||||
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
||||
.activityKey("UploadActivity")
|
||||
.build(getActivity()), REQUEST_CODE);
|
||||
.build(getActivity());
|
||||
} else {
|
||||
if (defaultKvStore.getString(LAST_LOCATION) != null) {
|
||||
final String[] locationLatLng
|
||||
|
|
@ -638,27 +657,20 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
if (defaultKvStore.getString(LAST_ZOOM) != null) {
|
||||
defaultZoom = Double.parseDouble(defaultKvStore.getString(LAST_ZOOM));
|
||||
}
|
||||
startActivityForResult(new LocationPicker.IntentBuilder()
|
||||
|
||||
locationPickerIntent = new LocationPicker.IntentBuilder()
|
||||
.defaultLocation(new CameraPosition(defaultLatitude,defaultLongitude,defaultZoom))
|
||||
.activityKey("NoLocationUploadActivity")
|
||||
.build(getActivity()), REQUEST_CODE);
|
||||
.build(getActivity());
|
||||
}
|
||||
startForResult.launch(locationPickerIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the coordinates and update the existing coordinates.
|
||||
* @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) {
|
||||
private void onCameraPosition(ActivityResult result){
|
||||
if (result.getResultCode() == RESULT_OK) {
|
||||
|
||||
assert data != null;
|
||||
final CameraPosition cameraPosition = LocationPicker.getCameraPosition(data);
|
||||
assert result.getData() != null;
|
||||
final CameraPosition cameraPosition = LocationPicker.getCameraPosition(result.getData());
|
||||
|
||||
if (cameraPosition != null) {
|
||||
|
||||
|
|
@ -678,8 +690,21 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
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")) {
|
||||
Timber.e("Error in rotating image");
|
||||
|
|
@ -687,24 +712,15 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
}
|
||||
try {
|
||||
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,
|
||||
result);
|
||||
path);
|
||||
} catch (Exception 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
|
||||
public void displayAddLocationDialog(final Runnable onSkipClicked) {
|
||||
isMissingLocationDialog = true;
|
||||
DialogUtil.showAlertDialog(Objects.requireNonNull(getActivity()),
|
||||
DialogUtil.showAlertDialog(requireActivity(),
|
||||
getString(R.string.no_location_found_title),
|
||||
getString(R.string.no_location_found_message),
|
||||
getString(R.string.add_location),
|
||||
|
|
|
|||
|
|
@ -129,9 +129,9 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
|
|||
if (place.location != null) {
|
||||
final String countryCode = reverseGeoCode(place.location);
|
||||
if (countryCode != null && WLM_SUPPORTED_COUNTRIES
|
||||
.contains(countryCode.toLowerCase())) {
|
||||
.contains(countryCode.toLowerCase(Locale.ROOT))) {
|
||||
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.WorkerParameters
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import fr.free.nrw.commons.BuildConfig.HOME_URL
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.Media
|
||||
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.di.ApplicationlessInjection
|
||||
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.upload.FileUtilsWrapper
|
||||
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.UploadResult
|
||||
import fr.free.nrw.commons.wikidata.WikidataEditService
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
|
@ -74,6 +77,9 @@ class UploadWorker(
|
|||
@Inject
|
||||
lateinit var fileUtilsWrapper: FileUtilsWrapper
|
||||
|
||||
@Inject
|
||||
lateinit var placesRepository: PlacesRepository
|
||||
|
||||
private val processingUploadsNotificationTag = BuildConfig.APPLICATION_ID + " : upload_tag"
|
||||
|
||||
private val processingUploadsNotificationId = 101
|
||||
|
|
@ -379,7 +385,7 @@ class UploadWorker(
|
|||
saveCompletedContribution(contribution, uploadResult)
|
||||
} else {
|
||||
Timber.d(
|
||||
"WikiDataEdit not required, making wikidata edit",
|
||||
"WikiDataEdit required, making wikidata edit",
|
||||
)
|
||||
makeWikiDataEdit(uploadResult, contribution)
|
||||
}
|
||||
|
|
@ -432,7 +438,7 @@ class UploadWorker(
|
|||
username,
|
||||
)
|
||||
CommonsApplication
|
||||
.getInstance()
|
||||
.instance!!
|
||||
.clearApplicationData(appContext, logoutListener)
|
||||
}
|
||||
}
|
||||
|
|
@ -471,6 +477,16 @@ class UploadWorker(
|
|||
contribution.media.captions,
|
||||
)
|
||||
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)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
|
|
@ -518,7 +534,7 @@ class UploadWorker(
|
|||
contribution.contentUri?.let {
|
||||
val imageSha1 = contribution.imageSHA1.toString()
|
||||
val modifiedSha1 = fileUtilsWrapper.getSHA1(fileUtilsWrapper.getFileInputStream(contribution.localUri?.path))
|
||||
MainScope().launch {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
uploadedStatusDao.insertUploaded(
|
||||
UploadedStatus(
|
||||
imageSha1,
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ public class PermissionUtils {
|
|||
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
final Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
activity.startActivityForResult(intent,
|
||||
CommonsApplication.OPEN_APPLICATION_DETAIL_SETTINGS);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
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_marginStart="16dp"
|
||||
android:contentDescription="@string/exit_location_picker"
|
||||
android:tint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="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>
|
||||
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
android:id="@+id/btn_edit_submit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:text="@string/submit"
|
||||
android:textColor="@android:color/white" />
|
||||
</RelativeLayout>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginRight="50dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
/>
|
||||
|
|
@ -58,6 +58,7 @@
|
|||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/button_background_selector"
|
||||
|
|
@ -69,8 +70,7 @@
|
|||
android:layout_gravity="center_horizontal"
|
||||
android:duplicateParentState="true"
|
||||
app:srcCompat="@drawable/ic_directions_black_24dp"
|
||||
android:tint="?attr/rowButtonColor"
|
||||
/>
|
||||
app:tint="?attr/rowButtonColor" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -89,6 +89,7 @@
|
|||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/button_background_selector"
|
||||
|
|
@ -118,6 +119,7 @@
|
|||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/button_background_selector"
|
||||
|
|
@ -153,8 +155,8 @@
|
|||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/large_height"
|
||||
android:layout_marginRight="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/large_height"
|
||||
android:layout_marginEnd="@dimen/standard_gap"
|
||||
android:layout_marginBottom="@dimen/standard_gap"
|
||||
android:textSize="16sp" />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/bookmarkButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:background="@drawable/button_background_selector"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
|
||||
|
|
@ -14,7 +16,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:tint="?attr/rowButtonColor" />
|
||||
app:tint="?attr/rowButtonColor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/buttonText"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/toolbar"
|
||||
android:background="?attr/achievementBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
|
@ -36,7 +35,6 @@
|
|||
style="?android:textAppearanceLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/level"
|
||||
|
|
@ -48,13 +46,11 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
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
|
||||
android:id="@+id/badge_layout"
|
||||
|
|
@ -108,7 +104,6 @@
|
|||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_upload_text_param"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
|
|
@ -120,12 +115,10 @@
|
|||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@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"
|
||||
android:tint="@color/primaryLightColor"
|
||||
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>
|
||||
|
||||
|
|
@ -189,7 +182,6 @@
|
|||
style="?android:textAppearanceMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:id="@+id/images_reverted_text"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:text="@string/image_reverts" />
|
||||
|
|
@ -200,24 +192,19 @@
|
|||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@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"
|
||||
android:tint="@color/primaryLightColor"
|
||||
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>
|
||||
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/achievements_revert_limit_message"
|
||||
android:textSize="@dimen/small_text"
|
||||
android:id="@+id/images_revert_limit_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_below="@id/images_reverted_info"/>
|
||||
|
||||
|
|
@ -278,7 +265,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/images_used_by_wiki_text"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/achievements_activity_margin_vertical"
|
||||
android:text="@string/images_used_by_wiki" />
|
||||
|
|
@ -289,12 +275,10 @@
|
|||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@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"
|
||||
android:tint="@color/primaryLightColor"
|
||||
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>
|
||||
|
||||
|
|
@ -353,7 +337,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="@string/statistics"
|
||||
style="?android:textAppearanceLarge"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_vertical"
|
||||
android:textAllCaps="true"/>
|
||||
|
|
@ -373,9 +356,7 @@
|
|||
android:id="@+id/images_nearby_info"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/wikidata_edits"
|
||||
android:layout_toLeftOf="@+id/wikidata_edits"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
|
|
@ -407,14 +388,13 @@
|
|||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_nearby_info_icon"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
android:layout_gravity="top"
|
||||
app:layout_constraintLeft_toRightOf="@id/images_nearby_data"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryLightColor" />
|
||||
app:tint="@color/primaryLightColor" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
@ -423,16 +403,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/wikidata_edits"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
@ -451,9 +429,7 @@
|
|||
android:id="@+id/images_featured_info"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/image_featured"
|
||||
android:layout_toLeftOf="@+id/image_featured"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
|
|
@ -486,14 +462,13 @@
|
|||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/images_featured_info_icon"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
app:layout_constraintLeft_toRightOf="@id/images_featured_data"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryLightColor" />
|
||||
app:tint="@color/primaryLightColor" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
@ -501,16 +476,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/image_featured"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
@ -529,9 +502,7 @@
|
|||
android:id="@+id/quality_images_info"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/quality_images"
|
||||
android:layout_toLeftOf="@+id/quality_images"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
|
|
@ -564,14 +535,13 @@
|
|||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/quality_images_info_icon"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
app:layout_constraintLeft_toRightOf="@id/quality_images_data"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryLightColor" />
|
||||
app:tint="@color/primaryLightColor" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
@ -579,7 +549,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
|
|
@ -587,9 +556,8 @@
|
|||
tools:text="2"
|
||||
android:text="0"
|
||||
android:id="@+id/quality_images"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
@ -608,9 +576,7 @@
|
|||
android:id="@+id/thanks_received_info"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toStartOf="@+id/thanks_received"
|
||||
android:layout_toLeftOf="@+id/thanks_received"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
|
|
@ -643,14 +609,13 @@
|
|||
android:layout_height="@dimen/medium_height"
|
||||
android:id="@+id/thanks_received_info_icon"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/activity_margin_horizontal"
|
||||
app:layout_constraintLeft_toRightOf="@id/thanks_received_data"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_gravity="top"
|
||||
app:srcCompat="@drawable/ic_info_outline_24dp"
|
||||
android:tint="@color/primaryLightColor" />
|
||||
app:tint="@color/primaryLightColor" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
@ -658,16 +623,14 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
tools:text="2"
|
||||
android:id="@+id/thanks_received"
|
||||
android:layout_marginEnd="@dimen/half_standard_height"
|
||||
android:layout_marginRight="@dimen/half_standard_height" />
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,33 @@
|
|||
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
||||
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>
|
||||
|
||||
<FrameLayout
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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
|
||||
android:id="@+id/icon"
|
||||
|
|
@ -30,7 +30,6 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginRight="@dimen/standard_gap"
|
||||
android:layout_marginTop="@dimen/standard_gap"
|
||||
|
|
@ -43,8 +42,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="@dimen/standard_gap"
|
||||
android:layout_marginEnd="@dimen/standard_gap"
|
||||
android:layout_marginTop="@dimen/large_gap"
|
||||
|
||||
/>
|
||||
|
|
@ -54,11 +52,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/distance"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:layout_toEndOf="@id/icon"
|
||||
android:layout_toLeftOf="@id/distance"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:layout_toStartOf="@id/distance"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
|
|
@ -71,8 +66,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignEnd="@id/distance"
|
||||
android:layout_alignLeft="@id/tvName"
|
||||
android:layout_alignRight="@id/distance"
|
||||
android:layout_alignStart="@id/tvName"
|
||||
android:layout_below="@id/tvName"
|
||||
android:layout_marginBottom="@dimen/standard_gap"
|
||||
|
|
|
|||
|
|
@ -19,17 +19,14 @@
|
|||
android:id="@+id/iv_campaign"
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_campaign"
|
||||
android:tint="?attr/card_item_color"
|
||||
/>
|
||||
app:tint="?attr/card_item_color" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:weightSum="4">
|
||||
|
|
@ -37,15 +34,13 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginRight="@dimen/tiny_margin"
|
||||
android:layout_centerInParent="true"
|
||||
>
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:layout_marginEnd="@dimen/tiny_margin">
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="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:textStyle="bold"
|
||||
tools:text="Campaign Title"
|
||||
|
|
@ -55,7 +50,7 @@
|
|||
android:id="@+id/tv_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:gravity="start"
|
||||
android:paddingTop="@dimen/miniscule_margin"
|
||||
android:textAlignment="textStart"
|
||||
|
|
@ -69,7 +64,7 @@
|
|||
android:id="@+id/tv_dates"
|
||||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="@dimen/miniscule_margin"
|
||||
android:text="@string/ends_on"
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@
|
|||
android:background="@android:color/transparent"
|
||||
android:padding="@dimen/activity_margin_horizontal"
|
||||
android:src="@drawable/ic_wikipedia"
|
||||
android:tint="?attr/contributionsListTextSecondary"
|
||||
android:text="@string/menu_cancel_upload"
|
||||
android:visibility="visible" />
|
||||
android:visibility="visible"
|
||||
app:tint="?attr/contributionsListTextSecondary" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginTop="@dimen/activity_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/activity_margin_horizontal"
|
||||
|
|
@ -30,34 +29,28 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/content_layout"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_centerInParent="true"
|
||||
/>
|
||||
android:id="@+id/progressBar" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/nearby_icon"
|
||||
android:layout_width="@dimen/dimen_40"
|
||||
android:layout_height="@dimen/dimen_40"
|
||||
android:layout_marginLeft="@dimen/standard_gap"
|
||||
android:layout_marginStart="@dimen/standard_gap"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@drawable/ic_location_white_24dp"
|
||||
android:tint="?attr/card_item_color"
|
||||
/>
|
||||
app:tint="?attr/card_item_color" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:weightSum="4"
|
||||
|
|
@ -68,8 +61,7 @@
|
|||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
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"
|
||||
tools:text="test distance"
|
||||
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:background="@drawable/button_background_selector"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
|
||||
|
|
@ -24,8 +25,8 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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
|
||||
android:id="@+id/cameraButtonText"
|
||||
|
|
@ -45,6 +46,7 @@
|
|||
android:background="@drawable/button_background_selector"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/nearby_row_image"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
|
||||
|
|
@ -53,8 +55,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
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
|
||||
android:id="@+id/galleryButtonText"
|
||||
|
|
@ -72,6 +74,7 @@
|
|||
android:layout_width="@dimen/dimen_0"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/standard_gap"
|
||||
android:clickable="true"
|
||||
android:orientation="vertical"
|
||||
|
|
@ -82,8 +85,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
app:srcCompat="@drawable/ic_directions_black_24dp"
|
||||
android:tint="?attr/bookmarkButtonColor"
|
||||
android:duplicateParentState="true"/>
|
||||
android:duplicateParentState="true"
|
||||
app:tint="?attr/bookmarkButtonColor" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -102,6 +105,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_gap">
|
||||
|
||||
|
|
@ -110,8 +114,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:duplicateParentState="true"
|
||||
android:tint="?attr/bookmarkButtonColor"
|
||||
app:srcCompat="@drawable/ic_overflow" />
|
||||
app:srcCompat="@drawable/ic_overflow"
|
||||
app:tint="?attr/bookmarkButtonColor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iconOverflowText"
|
||||
|
|
|
|||
|
|
@ -42,10 +42,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:contentDescription="@string/exit_location_picker"
|
||||
android:tint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="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>
|
||||
|
|
@ -1,17 +1,25 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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"
|
||||
android:title="@string/list_sheet"
|
||||
app:showAsAction="ifRoom|withText"
|
||||
android:icon="@drawable/ic_list_white_24dp"
|
||||
/>
|
||||
|
||||
<item android:id="@+id/list_item_gpx"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:title="Save as GPX file" />
|
||||
|
||||
<item android:id="@+id/list_item_kml"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:title="Save as KML file" />
|
||||
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -527,6 +527,7 @@
|
|||
<string name="no_notification">ليس لديك أي إشعارات غير مقروءة</string>
|
||||
<string name="no_read_notification">ليس لديك أي إشعاراتٍ غير مقروءة</string>
|
||||
<string name="share_logs_using">مشاركة السجلات باستخدام</string>
|
||||
<string name="check_your_email_inbox">تحقق من صندوق بريدك الإلكتروني</string>
|
||||
<string name="menu_option_read">عرض المقروءة</string>
|
||||
<string name="menu_option_unread">عرض غير المقروءة</string>
|
||||
<string name="error_occurred_in_picking_images">حدث خطأ أثناء التقاط الصور</string>
|
||||
|
|
@ -690,6 +691,7 @@
|
|||
<string name="leaderboard_nearby">مجاور</string>
|
||||
<string name="leaderboard_used">مستخدَم</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_disabled">وضع الاتصال المحدود مُعطل. سيجري استئناف التحميلات المعلقة الآن.</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_button_limit_text">الحد الأقصى: %1$d</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="display_monuments">عرض الآثار</string>
|
||||
<string name="wlm_month_message">إنه شهر Wiki Loves Monuments!</string>
|
||||
|
|
@ -788,16 +791,66 @@
|
|||
<string name="image_selected">تم تحديد الصورة</string>
|
||||
<string name="image_marked_as_not_for_upload">تم وضع علامة على الصورة على أنها ليست للتحميل</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_user">أخطر عن هذا المستخدم</string>
|
||||
<string name="report_content">الإبلاغ عن هذا المحتوى</string>
|
||||
<string name="request_user_block">طلب منع هذا المستخدم</string>
|
||||
<string name="welcome_to_full_screen_mode_text">مرحبًا بك في وضع التحديد بملء الشاشة</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="unable_to_share_upload_item">تعذر مشاركة هذا العنصر</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="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>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
<!-- Authors:
|
||||
* Dağlı95
|
||||
* Khan27
|
||||
* Nemoralis
|
||||
-->
|
||||
<resources>
|
||||
<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_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_ok_toast">Təşəkkür!</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ürlər!</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -12,34 +12,60 @@
|
|||
* Şeyx Şamil
|
||||
-->
|
||||
<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">
|
||||
<item quantity="one">%1$d fayl yüklənir</item>
|
||||
<item quantity="other">%1$d fayllar yüklənir</item>
|
||||
</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_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="username">Ləqəb</string>
|
||||
<string name="username">İstifadəçi adı</string>
|
||||
<string name="password">Parol</string>
|
||||
<string name="login">Daxil ol</string>
|
||||
<string name="signup">Qeydiyyatdan keç</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_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="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="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_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_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="title_activity_contributions">Yükləmələrim</string>
|
||||
<string name="contribution_state_queued">Sırada</string>
|
||||
<string name="upload_failed_notification_subtitle">Baxmaq üçün toxun</string>
|
||||
<string name="title_activity_contributions">Son Yükləmələrim</string>
|
||||
<string name="contribution_state_queued">Növbəyə alındı</string>
|
||||
<string name="contribution_state_failed">Uğursuz</string>
|
||||
<string name="contribution_state_in_progress">%1$d%% tamamlandı</string>
|
||||
<string name="contribution_state_starting">Yüklənir</string>
|
||||
|
|
@ -52,15 +78,15 @@
|
|||
<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_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_2fa_needed">İki faktorlu giriş doğrulama kodunu verməlisiniz.</string>
|
||||
<string name="login_failed_blocked">Bağışlayın, bu istifadəçi Vikianbardan bloklanıb</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="share_upload_button">Yüklə</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="categories_search_text_hint">Kateqoriyaları axtar</string>
|
||||
<string name="menu_save_categories">Qeyd et</string>
|
||||
<string name="categories_search_text_hint">Kateqoriyalarda axtar</string>
|
||||
<string name="menu_save_categories">Yadda saxla</string>
|
||||
<string name="refresh_button">Yenilə</string>
|
||||
<string name="display_list_button">Siyahı</string>
|
||||
<string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string>
|
||||
|
|
|
|||
|
|
@ -307,4 +307,5 @@
|
|||
<string name="please_wait">Моля, изчакайте...</string>
|
||||
<string name="delete_helper_ask_spam_blurry">напълно размазано</string>
|
||||
<string name="leaderboard_nearby">Наблизо</string>
|
||||
<string name="read_help_link">Прочетете повече</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -242,8 +242,8 @@
|
|||
<string name="nominated_for_deletion">Meneget eo bet ar skeudenn evit lemel.</string>
|
||||
<string name="skip_login">Lezel a-gostez</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_message" fuzzy="true">Da gevreañ ho po en amzer-da-zont evit pellgargañ skeudennoù.</string>
|
||||
<string name="skip_login_title">Ha n\'ho peus ket c\'hoant, evit gwir, da gevreañ ?</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="copy_wikicode">Eilañ an destenn wiki 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="share_title_hint">Куьг йазор (Т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="login_failed_network">Чувала(йала) тара цало — сетан гӀалат</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_read_notification">Du har ingen læste notifikationer</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_unread">Vis ulæste</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="failed">Mislykkedes</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>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* Sujan
|
||||
* Sushi
|
||||
* Tacsipacsi
|
||||
* TheRabbit22
|
||||
* ThisCarthing
|
||||
* Tobi 406
|
||||
* 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_header">Hinweis zu Mehrfach-Uploads</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>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
* JenyxGym
|
||||
* KATRINE1992
|
||||
* Koreller
|
||||
* Mahabarata
|
||||
* McDutchie
|
||||
* Melissadeba95
|
||||
* Metroitendo
|
||||
|
|
@ -516,6 +517,7 @@
|
|||
<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="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_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>
|
||||
|
|
@ -814,7 +816,7 @@
|
|||
<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="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="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>
|
||||
|
|
@ -824,5 +826,8 @@
|
|||
<string name="uploads">Téléversements</string>
|
||||
<string name="pending">En attente</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>
|
||||
|
|
|
|||
|
|
@ -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="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="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_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>
|
||||
|
|
@ -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_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="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="getting_edit_token">Szerkesztő token beszerzé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_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_ask_spam_selfie" fuzzy="true">Egy szelfi</string>
|
||||
<string name="delete_helper_ask_spam_blurry" fuzzy="true">Homályos</string>
|
||||
<string name="delete_helper_ask_spam_nonsense" fuzzy="true">Nonszensz</string>
|
||||
<string name="delete_helper_ask_spam_selfie">egy szelfi, amely egyetlen cikkben sem szerepel</string>
|
||||
<string name="delete_helper_ask_spam_blurry">teljesen homályos</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_internet_photo">Random fénykép az Internetről</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_type">Hely típusa:</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_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>
|
||||
|
|
|
|||
|
|
@ -765,8 +765,15 @@
|
|||
<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="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="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="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>
|
||||
|
|
|
|||
|
|
@ -760,4 +760,7 @@
|
|||
<item quantity="one">%d immagine selezionata</item>
|
||||
<item quantity="other">%d immagini selezionate</item>
|
||||
</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>
|
||||
|
|
|
|||
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