mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-28 13:23:58 +01:00
Merge branch 'main' into showMessageIfAllImagesUploadedOrMarked
This commit is contained in:
commit
1823f8359c
32 changed files with 344 additions and 236 deletions
|
|
@ -184,32 +184,32 @@ class LoginActivity : AccountAuthenticatorActivity() {
|
|||
// if progressDialog is visible during the configuration change then store state as true else false so that
|
||||
// we maintain visibility of progressDialog after configuration change
|
||||
if (progressDialog != null && progressDialog!!.isShowing) {
|
||||
outState.putBoolean(saveProgressDialog, true)
|
||||
outState.putBoolean(SAVE_PROGRESS_DIALOG, true)
|
||||
} else {
|
||||
outState.putBoolean(saveProgressDialog, false)
|
||||
outState.putBoolean(SAVE_PROGRESS_DIALOG, false)
|
||||
}
|
||||
outState.putString(
|
||||
saveErrorMessage,
|
||||
SAVE_ERROR_MESSAGE,
|
||||
binding!!.errorMessage.text.toString()
|
||||
) //Save the errorMessage
|
||||
outState.putString(
|
||||
saveUsername,
|
||||
SAVE_USERNAME,
|
||||
binding!!.loginUsername.text.toString()
|
||||
) // Save the username
|
||||
outState.putString(
|
||||
savePassword,
|
||||
SAVE_PASSWORD,
|
||||
binding!!.loginPassword.text.toString()
|
||||
) // Save the password
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
binding!!.loginUsername.setText(savedInstanceState.getString(saveUsername))
|
||||
binding!!.loginPassword.setText(savedInstanceState.getString(savePassword))
|
||||
if (savedInstanceState.getBoolean(saveProgressDialog)) {
|
||||
binding!!.loginUsername.setText(savedInstanceState.getString(SAVE_USERNAME))
|
||||
binding!!.loginPassword.setText(savedInstanceState.getString(SAVE_PASSWORD))
|
||||
if (savedInstanceState.getBoolean(SAVE_PROGRESS_DIALOG)) {
|
||||
performLogin()
|
||||
}
|
||||
val errorMessage = savedInstanceState.getString(saveErrorMessage)
|
||||
val errorMessage = savedInstanceState.getString(SAVE_ERROR_MESSAGE)
|
||||
if (sessionManager.isUserLoggedIn) {
|
||||
showMessage(R.string.login_success, R.color.primaryDarkColor)
|
||||
} else {
|
||||
|
|
@ -396,9 +396,9 @@ class LoginActivity : AccountAuthenticatorActivity() {
|
|||
fun startYourself(context: Context) =
|
||||
context.startActivity(Intent(context, LoginActivity::class.java))
|
||||
|
||||
const val saveProgressDialog: String = "ProgressDialog_state"
|
||||
const val saveErrorMessage: String = "errorMessage"
|
||||
const val saveUsername: String = "username"
|
||||
const val savePassword: String = "password"
|
||||
const val SAVE_PROGRESS_DIALOG: String = "ProgressDialog_state"
|
||||
const val SAVE_ERROR_MESSAGE: String = "errorMessage"
|
||||
const val SAVE_USERNAME: String = "username"
|
||||
const val SAVE_PASSWORD: String = "password"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
package fr.free.nrw.commons.concurrency;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
|
||||
public class BackgroundPoolExceptionHandler implements ExceptionHandler {
|
||||
/**
|
||||
* If an exception occurs on a background thread, this handler will crash for debug builds
|
||||
* but fail silently for release builds.
|
||||
* @param t
|
||||
*/
|
||||
@Override
|
||||
public void onException(@NonNull final Throwable t) {
|
||||
//Crash for debug build
|
||||
if (BuildConfig.DEBUG) {
|
||||
Thread thread = new Thread(() -> {
|
||||
throw new RuntimeException(t);
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package fr.free.nrw.commons.concurrency
|
||||
|
||||
import fr.free.nrw.commons.BuildConfig
|
||||
|
||||
|
||||
class BackgroundPoolExceptionHandler : ExceptionHandler {
|
||||
/**
|
||||
* If an exception occurs on a background thread, this handler will crash for debug builds
|
||||
* but fail silently for release builds.
|
||||
* @param t
|
||||
*/
|
||||
override fun onException(t: Throwable) {
|
||||
// Crash for debug build
|
||||
if (BuildConfig.DEBUG) {
|
||||
val thread = Thread {
|
||||
throw RuntimeException(t)
|
||||
}
|
||||
thread.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package fr.free.nrw.commons.concurrency;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
class ExceptionAwareThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
|
||||
private final ExceptionHandler exceptionHandler;
|
||||
|
||||
public ExceptionAwareThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory,
|
||||
ExceptionHandler exceptionHandler) {
|
||||
super(corePoolSize, threadFactory);
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
super.afterExecute(r, t);
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) future.get();
|
||||
} catch (CancellationException | InterruptedException e) {
|
||||
//ignore
|
||||
} catch (ExecutionException e) {
|
||||
t = e.getCause() != null ? e.getCause() : e;
|
||||
} catch (Exception e) {
|
||||
t = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (t != null) {
|
||||
exceptionHandler.onException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package fr.free.nrw.commons.concurrency
|
||||
|
||||
import java.util.concurrent.CancellationException
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||
import java.util.concurrent.ThreadFactory
|
||||
|
||||
|
||||
class ExceptionAwareThreadPoolExecutor(
|
||||
corePoolSize: Int,
|
||||
threadFactory: ThreadFactory,
|
||||
private val exceptionHandler: ExceptionHandler?
|
||||
) : ScheduledThreadPoolExecutor(corePoolSize, threadFactory) {
|
||||
|
||||
override fun afterExecute(r: Runnable, t: Throwable?) {
|
||||
super.afterExecute(r, t)
|
||||
var throwable = t
|
||||
|
||||
if (throwable == null && r is Future<*>) {
|
||||
try {
|
||||
if (r.isDone) {
|
||||
r.get()
|
||||
}
|
||||
} catch (e: CancellationException) {
|
||||
// ignore
|
||||
} catch (e: InterruptedException) {
|
||||
// ignore
|
||||
} catch (e: ExecutionException) {
|
||||
throwable = e.cause ?: e
|
||||
} catch (e: Exception) {
|
||||
throwable = e
|
||||
}
|
||||
}
|
||||
|
||||
throwable?.let {
|
||||
exceptionHandler?.onException(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package fr.free.nrw.commons.concurrency;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public interface ExceptionHandler {
|
||||
void onException(@NonNull Throwable t);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package fr.free.nrw.commons.concurrency
|
||||
|
||||
interface ExceptionHandler {
|
||||
|
||||
fun onException(t: Throwable)
|
||||
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
package fr.free.nrw.commons.concurrency;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This class is a thread pool which provides some additional features:
|
||||
* - it sets the thread priority to a value lower than foreground priority by default, or you can
|
||||
* supply your own priority
|
||||
* - it gives you a way to handle exceptions thrown in the thread pool
|
||||
*/
|
||||
|
||||
public class ThreadPoolService implements Executor {
|
||||
private final ScheduledThreadPoolExecutor backgroundPool;
|
||||
|
||||
private ThreadPoolService(final Builder b) {
|
||||
backgroundPool = new ExceptionAwareThreadPoolExecutor(b.poolSize,
|
||||
new ThreadFactory() {
|
||||
int count = 0;
|
||||
@Override
|
||||
public Thread newThread(@NonNull Runnable r) {
|
||||
count++;
|
||||
Thread t = new Thread(r, String.format("%s-%s", b.name, count));
|
||||
//If the priority is specified out of range, we set the thread priority to Thread.MIN_PRIORITY
|
||||
//It's done prevent IllegalArgumentException and to prevent setting of improper high priority for a less priority task
|
||||
t.setPriority(b.priority > Thread.MAX_PRIORITY || b.priority < Thread.MIN_PRIORITY ?
|
||||
Thread.MIN_PRIORITY : b.priority);
|
||||
return t;
|
||||
}
|
||||
}, b.exceptionHandler);
|
||||
}
|
||||
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long time, TimeUnit timeUnit) {
|
||||
return backgroundPool.schedule(callable, time, timeUnit);
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> schedule(Runnable runnable) {
|
||||
return schedule(runnable, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> schedule(Runnable runnable, long time, TimeUnit timeUnit) {
|
||||
return backgroundPool.schedule(runnable, time, timeUnit);
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(final Runnable task, long initialDelay,
|
||||
long period, final TimeUnit timeUnit) {
|
||||
return backgroundPool.scheduleAtFixedRate(task, initialDelay, period, timeUnit);
|
||||
}
|
||||
|
||||
public ScheduledThreadPoolExecutor executor() {
|
||||
return backgroundPool;
|
||||
}
|
||||
|
||||
public void shutdown(){
|
||||
backgroundPool.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
backgroundPool.execute(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link ThreadPoolService}
|
||||
*/
|
||||
public static class Builder {
|
||||
//Required
|
||||
private final String name;
|
||||
|
||||
//Optional
|
||||
private int poolSize = 1;
|
||||
private int priority = Thread.MIN_PRIORITY;
|
||||
private ExceptionHandler exceptionHandler = null;
|
||||
|
||||
/**
|
||||
* @param name the name of the threads in the service. if there are N threads,
|
||||
* the thread names will be like name-1, name-2, name-3,...,name-N
|
||||
*/
|
||||
public Builder(@NonNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param poolSize the number of threads to keep in the pool
|
||||
* @throws IllegalArgumentException if size of pool <=0
|
||||
*/
|
||||
public Builder setPoolSize(int poolSize) throws IllegalArgumentException {
|
||||
if (poolSize <= 0) {
|
||||
throw new IllegalArgumentException("Pool size must be grater than 0");
|
||||
}
|
||||
this.poolSize = poolSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param priority Priority of the threads in the service. You can supply a constant from
|
||||
* {@link java.lang.Thread} or
|
||||
* specify your own priority in the range 1(MIN_PRIORITY) to 10(MAX_PRIORITY)
|
||||
* By default, the priority is set to {@link java.lang.Thread#MIN_PRIORITY}
|
||||
*/
|
||||
public Builder setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param handler The handler to use to handle exceptions in the service
|
||||
*/
|
||||
public Builder setExceptionHandler(ExceptionHandler handler) {
|
||||
this.exceptionHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ThreadPoolService build() {
|
||||
return new ThreadPoolService(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package fr.free.nrw.commons.concurrency
|
||||
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
* This class is a thread pool which provides some additional features:
|
||||
* - it sets the thread priority to a value lower than foreground priority by default, or you can
|
||||
* supply your own priority
|
||||
* - it gives you a way to handle exceptions thrown in the thread pool
|
||||
*/
|
||||
class ThreadPoolService private constructor(builder: Builder) : Executor {
|
||||
private val backgroundPool: ScheduledThreadPoolExecutor = ExceptionAwareThreadPoolExecutor(
|
||||
builder.poolSize,
|
||||
object : ThreadFactory {
|
||||
private var count = 0
|
||||
override fun newThread(r: Runnable): Thread {
|
||||
count++
|
||||
val t = Thread(r, "${builder.name}-$count")
|
||||
// If the priority is specified out of range, we set the thread priority to
|
||||
// Thread.MIN_PRIORITY
|
||||
// It's done to prevent IllegalArgumentException and to prevent setting of
|
||||
// improper high priority for a less priority task
|
||||
t.priority =
|
||||
if (
|
||||
builder.priority > Thread.MAX_PRIORITY
|
||||
||
|
||||
builder.priority < Thread.MIN_PRIORITY
|
||||
) {
|
||||
Thread.MIN_PRIORITY
|
||||
} else {
|
||||
builder.priority
|
||||
}
|
||||
return t
|
||||
}
|
||||
},
|
||||
builder.exceptionHandler
|
||||
)
|
||||
|
||||
fun <V> schedule(callable: Callable<V>, time: Long, timeUnit: TimeUnit): ScheduledFuture<V> {
|
||||
return backgroundPool.schedule(callable, time, timeUnit)
|
||||
}
|
||||
|
||||
fun schedule(runnable: Runnable): ScheduledFuture<*> {
|
||||
return schedule(runnable, 0, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
fun schedule(runnable: Runnable, time: Long, timeUnit: TimeUnit): ScheduledFuture<*> {
|
||||
return backgroundPool.schedule(runnable, time, timeUnit)
|
||||
}
|
||||
|
||||
fun scheduleAtFixedRate(
|
||||
task: Runnable,
|
||||
initialDelay: Long,
|
||||
period: Long,
|
||||
timeUnit: TimeUnit
|
||||
): ScheduledFuture<*> {
|
||||
return backgroundPool.scheduleWithFixedDelay(task, initialDelay, period, timeUnit)
|
||||
}
|
||||
|
||||
fun executor(): ScheduledThreadPoolExecutor {
|
||||
return backgroundPool
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
backgroundPool.shutdown()
|
||||
}
|
||||
|
||||
override fun execute(command: Runnable) {
|
||||
backgroundPool.execute(command)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for [ThreadPoolService]
|
||||
*/
|
||||
class Builder(val name: String) {
|
||||
var poolSize: Int = 1
|
||||
var priority: Int = Thread.MIN_PRIORITY
|
||||
var exceptionHandler: ExceptionHandler? = null
|
||||
|
||||
/**
|
||||
* @param poolSize the number of threads to keep in the pool
|
||||
* @throws IllegalArgumentException if size of pool <= 0
|
||||
*/
|
||||
fun setPoolSize(poolSize: Int): Builder {
|
||||
if (poolSize <= 0) {
|
||||
throw IllegalArgumentException("Pool size must be greater than 0")
|
||||
}
|
||||
this.poolSize = poolSize
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* @param priority Priority of the threads in the service. You can supply a constant from
|
||||
* [java.lang.Thread] or
|
||||
* specify your own priority in the range 1(MIN_PRIORITY)
|
||||
* to 10(MAX_PRIORITY)
|
||||
* By default, the priority is set to [java.lang.Thread.MIN_PRIORITY]
|
||||
*/
|
||||
fun setPriority(priority: Int): Builder {
|
||||
this.priority = priority
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* @param handler The handler to use to handle exceptions in the service
|
||||
*/
|
||||
fun setExceptionHandler(handler: ExceptionHandler): Builder {
|
||||
exceptionHandler = handler
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): ThreadPoolService {
|
||||
return ThreadPoolService(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,7 @@
|
|||
package fr.free.nrw.commons.settings
|
||||
|
||||
object Prefs {
|
||||
const val GLOBAL_PREFS = "fr.free.nrw.commons.preferences"
|
||||
|
||||
const val TRACKING_ENABLED = "eventLogging"
|
||||
const val DEFAULT_LICENSE = "defaultLicense"
|
||||
const val UPLOADS_SHOWING = "uploadsShowing"
|
||||
const val MANAGED_EXIF_TAGS = "managed_exif_tags"
|
||||
const val DESCRIPTION_LANGUAGE = "languageDescription"
|
||||
const val APP_UI_LANGUAGE = "appUiLanguage"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import fr.free.nrw.commons.theme.BaseActivity
|
|||
class SettingsActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
// private var settingsDelegate: AppCompatDelegate? = null
|
||||
|
||||
/**
|
||||
* to be called when the activity starts
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package fr.free.nrw.commons.settings
|
||||
|
||||
import android.Manifest.permission
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
|
|
@ -11,7 +10,6 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.Button
|
||||
|
|
@ -131,7 +129,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
inAppCameraLocationPref?.setOnPreferenceChangeListener { _, newValue ->
|
||||
val isInAppCameraLocationTurnedOn = newValue as Boolean
|
||||
if (isInAppCameraLocationTurnedOn) {
|
||||
createDialogsAndHandleLocationPermissions(requireActivity())
|
||||
createDialogsAndHandleLocationPermissions()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
@ -256,7 +254,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
*
|
||||
* @param activity
|
||||
*/
|
||||
private fun createDialogsAndHandleLocationPermissions(activity: Activity) {
|
||||
private fun createDialogsAndHandleLocationPermissions() {
|
||||
inAppCameraLocationPermissionLauncher.launch(arrayOf(permission.ACCESS_FINE_LOCATION))
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +282,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
return object : PreferenceGroupAdapter(preferenceScreen) {
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
|
||||
super.onBindViewHolder(holder, position)
|
||||
val preference = getItem(position)
|
||||
val iconFrame: View? = holder.itemView.findViewById(R.id.icon_frame)
|
||||
iconFrame?.visibility = View.GONE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -13,6 +16,7 @@ import androidx.paging.PagedListAdapter
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import java.io.File
|
||||
|
|
@ -51,6 +55,24 @@ class FailedUploadsAdapter(
|
|||
position: Int,
|
||||
) {
|
||||
val item: Contribution? = getItem(position)
|
||||
val itemView = holder.itemView
|
||||
val clipboardManager =
|
||||
itemView.context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
val clip = ClipData.newPlainText(
|
||||
itemView.context.getString(R.string.caption),
|
||||
item?.media?.displayTitle
|
||||
)
|
||||
clipboardManager.setPrimaryClip(clip)
|
||||
Snackbar.make(
|
||||
itemView,
|
||||
itemView.context.getString(R.string.caption_copied_to_clipboard),
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
true
|
||||
}
|
||||
|
||||
if (item != null) {
|
||||
holder.titleTextView.setText(item.media.displayTitle)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@ class FileUtilsWrapper @Inject constructor(private val context: Context) {
|
|||
while ((bis.read(buffer).also { size = it }) > 0) {
|
||||
buffers.add(
|
||||
writeToFile(
|
||||
buffer.copyOf(size),
|
||||
buffer,
|
||||
file.name ?: "",
|
||||
getFileExt(file.name)
|
||||
getFileExt(file.name),
|
||||
size
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -67,7 +68,7 @@ class FileUtilsWrapper @Inject constructor(private val context: Context) {
|
|||
* Create a temp file containing the passed byte data.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
private fun writeToFile(data: ByteArray, fileName: String, fileExtension: String): File {
|
||||
private fun writeToFile(data: ByteArray, fileName: String, fileExtension: String, size: Int): File {
|
||||
val file = File.createTempFile(fileName, fileExtension, context.cacheDir)
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
|
|
@ -75,7 +76,7 @@ class FileUtilsWrapper @Inject constructor(private val context: Context) {
|
|||
}
|
||||
|
||||
FileOutputStream(file).use { fos ->
|
||||
fos.write(data)
|
||||
fos.write(data, 0, size)
|
||||
}
|
||||
} catch (throwable: Exception) {
|
||||
Timber.e(throwable, "Failed to create file")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -13,6 +16,7 @@ import androidx.paging.PagedListAdapter
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.contributions.Contribution
|
||||
import java.io.File
|
||||
|
|
@ -99,6 +103,22 @@ class PendingUploadsAdapter(
|
|||
|
||||
fun bind(contribution: Contribution) {
|
||||
titleTextView.text = contribution.media.displayTitle
|
||||
val clipboardManager =
|
||||
itemView.context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
val clip = ClipData.newPlainText(
|
||||
itemView.context.getString(R.string.caption),
|
||||
titleTextView.text
|
||||
)
|
||||
clipboardManager.setPrimaryClip(clip)
|
||||
Snackbar.make(
|
||||
itemView,
|
||||
itemView.context.getString(R.string.caption_copied_to_clipboard),
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
true
|
||||
}
|
||||
|
||||
val imageSource: String = contribution.localUri.toString()
|
||||
var imageRequest: ImageRequest? = null
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class MwQueryPage : BaseModel() {
|
|||
|
||||
fun title(): String = title!!
|
||||
|
||||
fun categoryInfo(): CategoryInfo = categoryinfo!!
|
||||
fun categoryInfo(): CategoryInfo? = categoryinfo
|
||||
|
||||
fun index(): Int = index
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
android:layout_width="@dimen/landscape_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="@dimen/small_gap">
|
||||
android:layout_marginTop="@dimen/login_gap">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/landscape_width"
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<LinearLayout 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:fillViewport="true"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@
|
|||
<string name="login_success">Uğurlu giriş!</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="retry_limit_reached">Maksimum təkrar cəhd limitinə çatdınız! Yükləməni ləğv edin və yenidən cəhd edin</string>
|
||||
<string name="unrestricted_battery_mode">Batareya optimallaşdırılmasını söndürmək?</string>
|
||||
<string name="retry_limit_reached">Maksimum təkrar cəhd limitinə çatdınız! Zəhmət olmasa, yükləməni ləğv edin və yenidən cəhd edin</string>
|
||||
<string name="unrestricted_battery_mode">Batareya optimallaşdırılması söndürülsün?</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>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
* Reedy
|
||||
* RucolaSpacecat
|
||||
* Sebastian Wallroth
|
||||
* SergeCroise
|
||||
* SpaceEnergy
|
||||
* Sujan
|
||||
* Sushi
|
||||
|
|
@ -313,6 +314,7 @@
|
|||
<string name="copy_wikicode">Den Wikitext in die Zwischenablage kopieren</string>
|
||||
<string name="wikicode_copied">Der Wikitext wurde in die Zwischenablage kopiert</string>
|
||||
<string name="nearby_location_not_available">„In der Nähe“ arbeiten möglicherwiese nicht richtig. Der Standort ist nicht verfügbar.</string>
|
||||
<string name="nearby_showing_pins_offline">Internet ist nicht verfügbar. Es werden nur zwischengespeicherte Orte angezeigt.</string>
|
||||
<string name="upload_location_access_denied">Standortzugriff verweigert. Bitte lege deinen Standort manuell fest, um diese Funktion nutzen zu können.</string>
|
||||
<string name="location_permission_rationale_nearby">Berechtigung zur Anzeige einer Liste mit Orten in der Nähe erforderlich</string>
|
||||
<string name="location_permission_rationale_explore">Berechtigung zur Anzeige einer Liste mit Orten in der Nähe erforderlich</string>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Astralnet
|
||||
* Domdomegg
|
||||
* Evropi
|
||||
* Fotis A.
|
||||
* Geraki
|
||||
* Giannaras99
|
||||
* Giorgos456
|
||||
|
|
@ -296,6 +297,7 @@
|
|||
<string name="copy_wikicode">Αντιγράψτε το wikitext στο πρόχειρο</string>
|
||||
<string name="wikicode_copied">Το wikitext αντιγράφηκε στο πρόχειρο</string>
|
||||
<string name="nearby_location_not_available">Η λειτουργία «Κοντά σας» ενδέχεται να μη δουλεύει σωστά, η Τοποθεσία δεν είναι διαθέσιμη.</string>
|
||||
<string name="nearby_showing_pins_offline">Το Διαδίκτυο δεν είναι διαθέσιμο. Εμφάνιση μόνο αποθηκευμένων τοποθεσιών.</string>
|
||||
<string name="upload_location_access_denied">Δεν επιτρέπεται η πρόσβαση στην τοποθεσία. Ρυθμίστε την τοποθεσία σας με χειροκίνητο τρόπο για να χρησιμοποιήσετε αυτήν τη δυνατότητα.</string>
|
||||
<string name="location_permission_rationale_nearby">Απαιτείται άδεια για την εμφάνιση καταλόγου κοντινών σημείων</string>
|
||||
<string name="location_permission_rationale_explore">Απαιτείται άδεια για την εμφάνιση καταλόγου κοντινών εικόνων</string>
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@
|
|||
<string name="menu_from_camera">Prender photo</string>
|
||||
<string name="menu_nearby">A proximitate</string>
|
||||
<string name="provider_contributions">Mi incargamentos</string>
|
||||
<string name="menu_copy_link">Copiar ligamine</string>
|
||||
<string name="menu_link_copied">Le ligamine ha essite copiate al area de transferentia</string>
|
||||
<string name="menu_share">Condivider</string>
|
||||
<string name="menu_view_file_page">Visitar le pagina del file</string>
|
||||
<string name="share_title_hint">Legenda (obligatori)</string>
|
||||
|
|
@ -118,6 +120,7 @@
|
|||
<string name="categories_search_text_hint">Cercar categorias</string>
|
||||
<string name="depicts_search_text_hint">Cerca elementos que tu file representa (montania, Taj Mahal, etc.)</string>
|
||||
<string name="menu_save_categories">Salveguardar</string>
|
||||
<string name="menu_overflow_desc">Menu de disbordamento</string>
|
||||
<string name="refresh_button">Refrescar</string>
|
||||
<string name="display_list_button">Listar</string>
|
||||
<string name="contributions_subtitle_zero">(Nihil incargate ancora)</string>
|
||||
|
|
@ -269,6 +272,7 @@
|
|||
<string name="copy_wikicode">Copiar le wikitexto al area de transferentia</string>
|
||||
<string name="wikicode_copied">Le wikitexto ha essite copiate al area de transferentia</string>
|
||||
<string name="nearby_location_not_available">“A proximitate” poterea non functionar perque le localisation non es disponibile.</string>
|
||||
<string name="nearby_showing_pins_offline">Internet indisponibile. Appare solmente le locos in cache.</string>
|
||||
<string name="upload_location_access_denied">Le accesso al localisation ha essite refusate. Per favor indica tu localisation manualmente pro usar iste function.</string>
|
||||
<string name="location_permission_rationale_nearby">Permission necessari pro monstrar un lista de locos a proximitate</string>
|
||||
<string name="location_permission_rationale_explore">Permission necessari pro monstrar un lista de imagines a proximitate</string>
|
||||
|
|
@ -352,11 +356,13 @@
|
|||
<string name="delete">Deler</string>
|
||||
<string name="Achievements">Realisationes</string>
|
||||
<string name="Profile">Profilo</string>
|
||||
<string name="badges">Insignias</string>
|
||||
<string name="statistics">Statisticas</string>
|
||||
<string name="statistics_thanks">Regratiamentos recipite</string>
|
||||
<string name="statistics_featured">Imagines eminente</string>
|
||||
<string name="statistics_wikidata_edits">Imagines via “Locos a proximitate”</string>
|
||||
<string name="level" fuzzy="true">Nivello</string>
|
||||
<string name="level">Nivello %d</string>
|
||||
<string name="profileLevel">%s (Nivello %s)</string>
|
||||
<string name="images_uploaded">Imagines incargate</string>
|
||||
<string name="image_reverts">Imagines non revertite</string>
|
||||
<string name="images_used_by_wiki">Imagines usate</string>
|
||||
|
|
@ -388,6 +394,7 @@
|
|||
<string name="map_application_missing">Necun application cartographic compatibile pote esser trovate sur tu apparato. Per favor installa un application cartographic pro usar iste function.</string>
|
||||
<string name="title_page_bookmarks_pictures">Imagines</string>
|
||||
<string name="title_page_bookmarks_locations">Locos</string>
|
||||
<string name="title_page_bookmarks_categories">Categorias</string>
|
||||
<string name="menu_bookmark">Adder al/Remover del marcapaginas</string>
|
||||
<string name="provider_bookmarks">Marcapaginas</string>
|
||||
<string name="bookmark_empty">Tu non ha addite alcun marcapagina</string>
|
||||
|
|
@ -469,6 +476,7 @@
|
|||
<string name="no_notification">Tu non ha notificationes non legite</string>
|
||||
<string name="no_read_notification">Tu non ha notificationes legite</string>
|
||||
<string name="share_logs_using">Condivider registros usante</string>
|
||||
<string name="check_your_email_inbox">Consulta tu cassa de entrata</string>
|
||||
<string name="menu_option_read">Vider legites</string>
|
||||
<string name="menu_option_unread">Vider non legites</string>
|
||||
<string name="error_occurred_in_picking_images">Un error ha occurrite durante le selection de imagines</string>
|
||||
|
|
@ -776,4 +784,21 @@
|
|||
<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>
|
||||
<string name="custom_selector_delete_folder">Deler dossier</string>
|
||||
<string name="custom_selector_confirm_deletion_title">Confirmar deletion</string>
|
||||
<string name="custom_selector_confirm_deletion_message">Es tu secur de voler deler le dossier %1$s que contine %2$d objectos?</string>
|
||||
<string name="custom_selector_delete">Deler</string>
|
||||
<string name="custom_selector_cancel">Cancellar</string>
|
||||
<string name="custom_selector_folder_deleted_success">Le dossier %1$s ha essite delite</string>
|
||||
<string name="custom_selector_folder_deleted_failure">Le dossier %1$s non ha potite esser delite</string>
|
||||
<string name="custom_selector_error_trashing_folder_contents">Error durante le elimination del contento del dossier: %1$s</string>
|
||||
<string name="custom_selector_folder_not_found_error">Non poteva recuperar le percurso al dossier pro le “bucket ID” %1$d</string>
|
||||
<string name="red_pin">Iste loco non ha ancora un photo. Proque non prender un?</string>
|
||||
<string name="green_pin">Iste loco ja ha un photo.</string>
|
||||
<string name="grey_pin">Ora se verifica si iste loco ha un photo.</string>
|
||||
<string name="error_while_loading">Error durante le cargamento</string>
|
||||
<string name="no_usages_found">Necun uso trovate</string>
|
||||
<string name="usages_on_commons_heading">Commons</string>
|
||||
<string name="usages_on_other_wikis_heading">Altere wikis</string>
|
||||
<string name="file_usages_container_heading">Usos del file</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Authors:
|
||||
* A67-A67
|
||||
* ABPMAB
|
||||
* Bouman4
|
||||
* Ciell
|
||||
* Dutchy45
|
||||
|
|
@ -299,6 +300,7 @@
|
|||
<string name="copy_wikicode">Kopieer de wikitekst naar het klembord</string>
|
||||
<string name="wikicode_copied">De wikitekst is gekopieerd naar het klembord</string>
|
||||
<string name="nearby_location_not_available">In de buurt werkt mogelijk niet naar behoren. Locatie niet beschikbaar.</string>
|
||||
<string name="nearby_showing_pins_offline">Internet niet beschikbaar. Alleen gecachte plaatsen worden getoond.</string>
|
||||
<string name="upload_location_access_denied">Locatietoegang geweigerd. Stel uw locatie handmatig in om deze functie te gebruiken.</string>
|
||||
<string name="location_permission_rationale_nearby">Toestemming vereist om een lijst van nabije plaatsen weer te geven</string>
|
||||
<string name="location_permission_rationale_explore">Toestemming vereist om een lijst van nabije afbeeldingen weer te geven</string>
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@
|
|||
<string name="license_name_cc_by_4_0">CC BY 4.0</string>
|
||||
<string name="tutorial_1_text">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਜ਼ਿਆਦਾਤਰ ਉਹ ਤਸਵੀਰਾਂ ਦਾ ਭੰਡਾਰ ਹੈ ਜੋ ਵਿਕੀਪੀਡੀਆ \'ਤੇ ਵਰਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।</string>
|
||||
<string name="tutorial_1_subtext">ਤੁਹਾਡੀਆਂ ਤਸਵੀਰਾਂ ਵਿਸ਼ਵ ਦੇ ਬਾਕੀ ਲੋਕਾਂ ਨੂੰ ਸਿੱਖਿਅਤ ਕਰਨ ਲਈ ਸਹਾਈ ਹਨ!</string>
|
||||
<string name="tutorial_2_text">ਕਿਰਪਾ ਕਰਕੇ ਉਹ ਤਸਵੀਰਾਂ ਅਪਲੋਡ ਕਰੋ ਜੋ ਤੁਹਾਡੇ ਦੁਆਰਾ ਲਈਆਂ ਗਈਆਂ ਹਨ ਜਾਂ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ:</string>
|
||||
<string name="tutorial_2_text">ਕਿਰਪਾ ਕਰਕੇ ਉਹ ਤਸਵੀਰਾਂ ਨੂੰ ਚੜ੍ਹਾਉ ਜੋ ਤੁਹਾਡੇ ਵੱਲੋਂ ਲਈਆਂ ਗਈਆਂ ਹਨ ਜਾਂ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ:</string>
|
||||
<string name="tutorial_3_text">ਕਿਰਪਾ ਕਰਕੇ ਅਪਲੋਡ ਨਾ ਕਰੋ:</string>
|
||||
<string name="tutorial_4_text">ਉਦਾਹਰਣ ਵਜੋਂ ਇਹ ਅਪਲੋਡ:</string>
|
||||
<string name="welcome_wikipedia_text">ਆਪਣੀਆਂ ਤਸਵੀਰਾਂ ਦਾ ਯੋਗਦਾਨ ਪਾਓ। ਵਿਕੀਪੀਡੀਆ ਲੇਖਾਂ ਨੂੰ ਸੁਰਜੀਤ ਕਰ ਦਿਓ!</string>
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@
|
|||
<string name="welcome_help_button_text">Lassedieđut</string>
|
||||
<string name="detail_panel_cats_label">Kategoriijat</string>
|
||||
<string name="detail_panel_cats_loading">Luđeme...</string>
|
||||
<string name="detail_panel_cats_none">Ii guhtege válljejuvvon</string>
|
||||
<string name="detail_panel_cats_none">Ii oktage válljejuvvon</string>
|
||||
<string name="detail_caption_empty">Ii leat govvateaksta</string>
|
||||
<string name="detail_description_empty">Ii gávdno govvádus</string>
|
||||
<string name="detail_discussion_empty">Ii digaštallojuvvo</string>
|
||||
|
|
@ -217,6 +217,10 @@
|
|||
<string name="next">Čuovvovaš</string>
|
||||
<string name="title_page_bookmarks_pictures">Govat</string>
|
||||
<string name="title_page_bookmarks_locations">Sajit</string>
|
||||
<string name="provider_bookmarks">Girjemearkkat</string>
|
||||
<string name="provider_bookmarks_location">Girjemearkkat</string>
|
||||
<string name="no_categories_selected">Ii oktage kategoriija leat válljejuvvon</string>
|
||||
<string name="no_depictions_selected">Ii oktage govvádus leat válljejuvvon</string>
|
||||
<string name="back_button_warning">Gaskkalduhte fiilla vurkema</string>
|
||||
<string name="review_thanks_yes_button_text">Čuovvovaš govva</string>
|
||||
<string name="exif_tag_name_author">Vuoigŋadahkki</string>
|
||||
|
|
@ -230,9 +234,11 @@
|
|||
<string name="caption_edit_helper_edit_message_else">Govvateavstta lasiheapmi ii lihkostuvvan.</string>
|
||||
<string name="description_activity_title">Rievdat govvádusaid ja govvateavsttaid</string>
|
||||
<string name="nearby_search_hint">Šaldi, musea, hotealla jna.</string>
|
||||
<string name="title_app_shortcut_bookmark">Girjemearkkat</string>
|
||||
<string name="load_more">Luđe lasi</string>
|
||||
<string name="add_picture_to_wikipedia_article_title">Lasit gova Wikipediai</string>
|
||||
<string name="resume">joatkke</string>
|
||||
<string name="bookmarks">Girjemearkkat</string>
|
||||
<string name="leaderboard_column_user">Geavaheaddji</string>
|
||||
<string name="cancelling_upload">Fiilla vurkema gaskkalduhttomin…</string>
|
||||
<string name="license_step_title">Medialiseansa</string>
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@
|
|||
<string name="storage_permission_title">ಶೇಖರಣ ಅನುಮತಿ ಕೇಣುನು</string>
|
||||
<string name="read_storage_permission_rationale">ಅಗತ್ಯ ಇಪ್ಪುನ ಅನುಮತಿ: ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆನ್ ಓದಿ. ಇದೆಂಡ್ತ್ ಇರ್ ಗ್ಯಾಲರಿಗ್ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರವೇಶಗ್ ಸಾಧ್ಯ ಇಜ್ಜಿ.</string>
|
||||
<string name="write_storage_permission_rationale" fuzzy="true">ಅಗತ್ಯ ಇಪ್ಪುನ ಅನುಮತಿ: ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆನ್ ಬರೆಲೆ. ಇದೆಂಡ್ತ್ ಅಪ್ಲಿಕೇಶನ್ ಇರೆನ ಕ್ಯಾಮರೊನ್ ಪ್ರವೇಶ ಮಾಲ್ಪಯರ ಸಾಧ್ಯಿಜ್ಜಿ.</string>
|
||||
<string name="ok">ಅವು</string>
|
||||
<string name="ok">ಆವು</string>
|
||||
<string name="warning">ಎಚ್ಚರಿಕೆ</string>
|
||||
<string name="yes">ಅಂದ್</string>
|
||||
<string name="no">ಅತ್ತ್</string>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* Simon Shek
|
||||
* StephDC
|
||||
* Tranve
|
||||
* Wehwei
|
||||
* Winston Sung
|
||||
* Wwycheuk
|
||||
* ZhaoGang
|
||||
|
|
@ -122,6 +123,8 @@
|
|||
<string name="menu_from_camera">拍照</string>
|
||||
<string name="menu_nearby">附近</string>
|
||||
<string name="provider_contributions">我的上傳</string>
|
||||
<string name="menu_copy_link">複製連結</string>
|
||||
<string name="menu_link_copied">連結已複製到剪貼簿。</string>
|
||||
<string name="menu_share">分享</string>
|
||||
<string name="menu_view_file_page">檢視檔案頁面</string>
|
||||
<string name="share_title_hint">說明(必填)</string>
|
||||
|
|
@ -140,6 +143,7 @@
|
|||
<string name="categories_search_text_hint">搜尋分類</string>
|
||||
<string name="depicts_search_text_hint">搜尋您的媒體描繪項目(山、泰姬瑪哈陵等)</string>
|
||||
<string name="menu_save_categories">儲存</string>
|
||||
<string name="menu_overflow_desc">溢出選單</string>
|
||||
<string name="refresh_button">重新整理</string>
|
||||
<string name="display_list_button">清單</string>
|
||||
<string name="contributions_subtitle_zero">(尚未上傳)</string>
|
||||
|
|
@ -296,6 +300,7 @@
|
|||
<string name="copy_wikicode">複製 wikitext 到剪貼簿</string>
|
||||
<string name="wikicode_copied">Wikitext 已複製到剪貼簿</string>
|
||||
<string name="nearby_location_not_available">位置無效,應用程式在此地附近可能無法正常運作。</string>
|
||||
<string name="nearby_showing_pins_offline">網路無法使用。僅顯示快取位置。</string>
|
||||
<string name="upload_location_access_denied">位置存取遭拒。請手動設定您的位置才能使用此功能。</string>
|
||||
<string name="location_permission_rationale_nearby">需權限來顯示附近地點清單</string>
|
||||
<string name="location_permission_rationale_explore">需要權限來顯示附近圖片清單</string>
|
||||
|
|
@ -379,11 +384,13 @@
|
|||
<string name="delete">刪除</string>
|
||||
<string name="Achievements">成果</string>
|
||||
<string name="Profile">個人檔案</string>
|
||||
<string name="badges">徽章:</string>
|
||||
<string name="statistics">統計內容</string>
|
||||
<string name="statistics_thanks">已收到的感謝</string>
|
||||
<string name="statistics_featured">特色圖片</string>
|
||||
<string name="statistics_wikidata_edits">圖片來自“附近的地方”</string>
|
||||
<string name="level" fuzzy="true">等級</string>
|
||||
<string name="level">等級 %d</string>
|
||||
<string name="profileLevel">%s(%s級)</string>
|
||||
<string name="images_uploaded">已上傳的圖片</string>
|
||||
<string name="image_reverts">沒有被還原回復的圖片</string>
|
||||
<string name="images_used_by_wiki">有被使用到的圖片</string>
|
||||
|
|
@ -415,6 +422,7 @@
|
|||
<string name="map_application_missing">在您的裝置上找不到相容的地圖應用程式,請安裝地圖應用程式來使用此功能。</string>
|
||||
<string name="title_page_bookmarks_pictures">圖片</string>
|
||||
<string name="title_page_bookmarks_locations">位置</string>
|
||||
<string name="title_page_bookmarks_categories">分類</string>
|
||||
<string name="menu_bookmark">添加/移除至書籤</string>
|
||||
<string name="provider_bookmarks">書籤</string>
|
||||
<string name="bookmark_empty">您尚未添加任何書籤</string>
|
||||
|
|
@ -806,7 +814,21 @@
|
|||
<string name="pending">待處理</string>
|
||||
<string name="failed">失敗</string>
|
||||
<string name="could_not_load_place_data">無法載入地點資料</string>
|
||||
<string name="custom_selector_delete_folder">刪除資料夾</string>
|
||||
<string name="custom_selector_confirm_deletion_title">確認刪除</string>
|
||||
<string name="custom_selector_confirm_deletion_message">您確定要刪除包含%2$d項目的資料夾%1$s嗎?</string>
|
||||
<string name="custom_selector_delete">刪除</string>
|
||||
<string name="custom_selector_cancel">取消</string>
|
||||
<string name="custom_selector_folder_deleted_success">%1$s資料夾刪除成功</string>
|
||||
<string name="custom_selector_folder_deleted_failure">無法刪除資料夾%1$s</string>
|
||||
<string name="custom_selector_error_trashing_folder_contents">刪除資料夾內容時發生錯誤: %1$s</string>
|
||||
<string name="custom_selector_folder_not_found_error">無法取得儲存桶 ID 的資料夾路徑: %1$d</string>
|
||||
<string name="red_pin">這個地點還沒有照片,來拍一張吧!</string>
|
||||
<string name="green_pin">這個地點已有照片。</string>
|
||||
<string name="grey_pin">現在檢查這個地點是否有照片。</string>
|
||||
<string name="error_while_loading">載入時出錯</string>
|
||||
<string name="no_usages_found">找不到頁面。</string>
|
||||
<string name="usages_on_commons_heading">維基共享資源</string>
|
||||
<string name="usages_on_other_wikis_heading">其它 wiki</string>
|
||||
<string name="file_usages_container_heading">檔案用途</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@
|
|||
<string name="menu_from_camera">拍照</string>
|
||||
<string name="menu_nearby">附近</string>
|
||||
<string name="provider_contributions">我的上传</string>
|
||||
<string name="menu_copy_link">复制链接</string>
|
||||
<string name="menu_link_copied">链接已复制到剪贴板。</string>
|
||||
<string name="menu_share">分享</string>
|
||||
<string name="menu_view_file_page">查看文件页面</string>
|
||||
<string name="share_title_hint">说明(必需)</string>
|
||||
|
|
@ -329,6 +331,7 @@
|
|||
<string name="copy_wikicode">复制wikitext到剪贴板</string>
|
||||
<string name="wikicode_copied">wikitext已经复制到剪贴板</string>
|
||||
<string name="nearby_location_not_available">附近可能无法正常工作,位置不可用。</string>
|
||||
<string name="nearby_showing_pins_offline">互联网不可用。仅显示缓存的位置。</string>
|
||||
<string name="upload_location_access_denied">位置权限被拒绝。请手动设置您的位置以使用此功能。</string>
|
||||
<string name="location_permission_rationale_nearby">需要权限以显示附近地点列表</string>
|
||||
<string name="location_permission_rationale_explore">需要权限以显示附近图片列表</string>
|
||||
|
|
@ -412,11 +415,13 @@
|
|||
<string name="delete">删除</string>
|
||||
<string name="Achievements">成就</string>
|
||||
<string name="Profile">个人资料</string>
|
||||
<string name="badges">徽章</string>
|
||||
<string name="statistics">统计</string>
|
||||
<string name="statistics_thanks">已收到感谢</string>
|
||||
<string name="statistics_featured">特色图片</string>
|
||||
<string name="statistics_wikidata_edits">来自“附近地点”的图片</string>
|
||||
<string name="level" fuzzy="true">等级</string>
|
||||
<string name="level">等级%d</string>
|
||||
<string name="profileLevel">%s(%s級)</string>
|
||||
<string name="images_uploaded">已上传图片</string>
|
||||
<string name="image_reverts">未还原图片</string>
|
||||
<string name="images_used_by_wiki">使用过的图片</string>
|
||||
|
|
@ -448,6 +453,7 @@
|
|||
<string name="map_application_missing">您的设备上无法找到兼容的地图应用程序。请安装地图应用程序来使用此功能。</string>
|
||||
<string name="title_page_bookmarks_pictures">图片</string>
|
||||
<string name="title_page_bookmarks_locations">方位</string>
|
||||
<string name="title_page_bookmarks_categories">分类</string>
|
||||
<string name="menu_bookmark">添加/删除书签</string>
|
||||
<string name="provider_bookmarks">书签</string>
|
||||
<string name="bookmark_empty">您还未加入任何书签</string>
|
||||
|
|
@ -850,4 +856,8 @@
|
|||
<string name="red_pin">这个地点还没有照片,快去拍一张吧!</string>
|
||||
<string name="green_pin">这个地点已经有照片了。</string>
|
||||
<string name="grey_pin">现在检查这个地点是否有照片。</string>
|
||||
<string name="error_while_loading">加载时出错</string>
|
||||
<string name="usages_on_commons_heading">维基共享资源</string>
|
||||
<string name="usages_on_other_wikis_heading">其它wiki</string>
|
||||
<string name="file_usages_container_heading">文件用途</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<dimen name="gigantic_gap">64dp</dimen>
|
||||
<dimen name="standard_gap">16dp</dimen>
|
||||
<dimen name="small_gap">8dp</dimen>
|
||||
<dimen name="login_gap">20dp</dimen>
|
||||
<dimen name="small_height">7dp</dimen>
|
||||
<dimen name="tiny_gap">4dp</dimen>
|
||||
<dimen name="very_tiny_gap">2dp</dimen>
|
||||
|
|
|
|||
|
|
@ -860,5 +860,7 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="usages_on_other_wikis_heading">Other wikis</string>
|
||||
<string name="bullet_point">•</string>
|
||||
<string name="file_usages_container_heading">File usages</string>
|
||||
<string name="caption">Caption</string>
|
||||
<string name="caption_copied_to_clipboard">Caption copied to clipboard</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ class NearbyParentFragmentPresenterTest {
|
|||
// 111.19 km real distance, return false if 148306.444306 > currentLocationSearchRadius
|
||||
NearbyController.currentLocationSearchRadius = 148306.0
|
||||
val isClose = nearbyPresenter.searchCloseToCurrentLocation()
|
||||
assertFalse(isClose!!.equals(false))
|
||||
assertFalse(!isClose)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -318,7 +318,7 @@ class NearbyParentFragmentPresenterTest {
|
|||
// 111.19 km real distance, return false if 148253.333 > currentLocationSearchRadius
|
||||
NearbyController.currentLocationSearchRadius = 148307.0
|
||||
val isClose = nearbyPresenter.searchCloseToCurrentLocation()
|
||||
assertTrue(isClose!!)
|
||||
assertTrue(isClose)
|
||||
}
|
||||
|
||||
fun expectMapAndListUpdate() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue