Merge branch 'main' into fix/email-verification-input

This commit is contained in:
Nicolas Raoul 2025-07-05 13:11:54 +09:00 committed by GitHub
commit aa7184cffe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 688 additions and 533 deletions

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.Intent.ACTION_VIEW
import android.net.Uri
import android.os.Bundle
import android.view.Menu
@ -16,6 +18,9 @@ import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import java.util.Collections
import androidx.core.net.toUri
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.setUnderlinedText
/**
* Represents about screen of this app
@ -59,30 +64,12 @@ class AboutActivity : BaseActivity() {
binding!!.aboutImprove.setHtmlText(improveText)
binding!!.aboutVersion.text = applicationContext.getVersionNameWithSha()
Utils.setUnderlinedText(
binding!!.aboutFaq, R.string.about_faq,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutRateUs, R.string.about_rate_us,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutUserGuide, R.string.user_guide,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutPrivacyPolicy, R.string.about_privacy_policy,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutTranslate, R.string.about_translate,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutCredits, R.string.about_credits,
applicationContext
)
binding!!.aboutFaq.setUnderlinedText(R.string.about_faq)
binding!!.aboutRateUs.setUnderlinedText(R.string.about_rate_us)
binding!!.aboutUserGuide.setUnderlinedText(R.string.user_guide)
binding!!.aboutPrivacyPolicy.setUnderlinedText(R.string.about_privacy_policy)
binding!!.aboutTranslate.setUnderlinedText(R.string.about_translate)
binding!!.aboutCredits.setUnderlinedText(R.string.about_credits)
/*
To set listeners, we can create a separate method and use lambda syntax.
@ -106,47 +93,56 @@ class AboutActivity : BaseActivity() {
fun launchFacebook(view: View?) {
val intent: Intent
try {
intent = Intent(Intent.ACTION_VIEW, Uri.parse(Urls.FACEBOOK_APP_URL))
intent = Intent(ACTION_VIEW, Urls.FACEBOOK_APP_URL.toUri())
intent.setPackage(Urls.FACEBOOK_PACKAGE_NAME)
startActivity(intent)
} catch (e: Exception) {
Utils.handleWebUrl(this, Uri.parse(Urls.FACEBOOK_WEB_URL))
handleWebUrl(this, Urls.FACEBOOK_WEB_URL.toUri())
}
}
fun launchGithub(view: View?) {
val intent: Intent
try {
intent = Intent(Intent.ACTION_VIEW, Uri.parse(Urls.GITHUB_REPO_URL))
intent = Intent(ACTION_VIEW, Urls.GITHUB_REPO_URL.toUri())
intent.setPackage(Urls.GITHUB_PACKAGE_NAME)
startActivity(intent)
} catch (e: Exception) {
Utils.handleWebUrl(this, Uri.parse(Urls.GITHUB_REPO_URL))
handleWebUrl(this, Urls.GITHUB_REPO_URL.toUri())
}
}
fun launchWebsite(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.WEBSITE_URL))
handleWebUrl(this, Urls.WEBSITE_URL.toUri())
}
fun launchRatings(view: View?) {
Utils.rateApp(this)
try {
startActivity(
Intent(
ACTION_VIEW,
(Urls.PLAY_STORE_PREFIX + packageName).toUri()
)
)
} catch (_: ActivityNotFoundException) {
handleWebUrl(this, (Urls.PLAY_STORE_URL_PREFIX + packageName).toUri())
}
}
fun launchCredits(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.CREDITS_URL))
handleWebUrl(this, Urls.CREDITS_URL.toUri())
}
fun launchUserGuide(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.USER_GUIDE_URL))
handleWebUrl(this, Urls.USER_GUIDE_URL.toUri())
}
fun launchPrivacyPolicy(view: View?) {
Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL))
handleWebUrl(this, BuildConfig.PRIVACY_POLICY_URL.toUri())
}
fun launchFrequentlyAskedQuesions(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.FAQ_URL))
handleWebUrl(this, Urls.FAQ_URL.toUri())
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -193,7 +189,7 @@ class AboutActivity : BaseActivity() {
val positiveButtonRunnable = Runnable {
val langCode = instance.languageLookUpTable!!.getCodes()[spinner.selectedItemPosition]
Utils.handleWebUrl(this@AboutActivity, Uri.parse(Urls.TRANSLATE_WIKI_URL + langCode))
handleWebUrl(this@AboutActivity, (Urls.TRANSLATE_WIKI_URL + langCode).toUri())
}
showAlertDialog(
this,

View file

@ -1,18 +0,0 @@
package fr.free.nrw.commons;
import androidx.annotation.NonNull;
/**
* Base presenter, enforcing contracts to atach and detach view
*/
public interface BasePresenter<T> {
/**
* Until a view is attached, it is open to listen events from the presenter
*/
void onAttachView(@NonNull T view);
/**
* Detaching a view makes sure that the view no more receives events from the presenter
*/
void onDetachView();
}

View file

@ -0,0 +1,10 @@
package fr.free.nrw.commons
/**
* Base presenter, enforcing contracts to attach and detach view
*/
interface BasePresenter<T> {
fun onAttachView(view: T)
fun onDetachView()
}

View file

@ -1,79 +0,0 @@
package fr.free.nrw.commons;
import androidx.annotation.Nullable;
/**
* represents Licence object
*/
public class License {
private String key;
private String template;
private String url;
private String name;
/**
* Constructs a new instance of License.
*
* @param key license key
* @param template license template
* @param url license URL
* @param name licence name
*
* @throws RuntimeException if License.key or Licence.template is null
*/
public License(String key, String template, String url, String name) {
if (key == null) {
throw new RuntimeException("License.key must not be null");
}
if (template == null) {
throw new RuntimeException("License.template must not be null");
}
this.key = key;
this.template = template;
this.url = url;
this.name = name;
}
/**
* Gets the license key.
* @return license key as a String.
*/
public String getKey() {
return key;
}
/**
* Gets the license template.
* @return license template as a String.
*/
public String getTemplate() {
return template;
}
/**
* Gets the license name. If name is null, return license key.
* @return license name as string. if name null, license key as String
*/
public String getName() {
if (name == null) {
// hack
return getKey();
} else {
return name;
}
}
/**
* Gets the license URL
*
* @param language license language
* @return URL
*/
public @Nullable String getUrl(String language) {
if (url == null) {
return null;
} else {
return url.replace("$lang", language);
}
}
}

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons
import android.os.Parcelable
import fr.free.nrw.commons.BuildConfig.COMMONS_URL
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.wikidata.model.WikiSite
import fr.free.nrw.commons.wikidata.model.page.PageTitle
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@ -173,7 +175,8 @@ class Media constructor(
* Gets file page title
* @return New media page title
*/
val pageTitle: PageTitle get() = Utils.getPageTitle(filename!!)
val pageTitle: PageTitle
get() = PageTitle(filename!!, WikiSite(COMMONS_URL))
/**
* Returns wikicode to use the media file on a MediaWiki site

View file

@ -1,8 +0,0 @@
package fr.free.nrw.commons;
/**
* Base interface for all the views
*/
public interface MvpView {
void showMessage(String message);
}

View file

@ -1,264 +0,0 @@
package fr.free.nrw.commons;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import java.util.Calendar;
import java.util.Date;
import fr.free.nrw.commons.wikidata.model.WikiSite;
import fr.free.nrw.commons.wikidata.model.page.PageTitle;
import java.util.Locale;
import java.util.regex.Pattern;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;
public class Utils {
public static PageTitle getPageTitle(@NonNull String title) {
return new PageTitle(title, new WikiSite(BuildConfig.COMMONS_URL));
}
/**
* Generates licence name with given ID
* @param license License ID
* @return Name of license
*/
public static int licenseNameFor(String license) {
switch (license) {
case Prefs.Licenses.CC_BY_3:
return R.string.license_name_cc_by;
case Prefs.Licenses.CC_BY_4:
return R.string.license_name_cc_by_four;
case Prefs.Licenses.CC_BY_SA_3:
return R.string.license_name_cc_by_sa;
case Prefs.Licenses.CC_BY_SA_4:
return R.string.license_name_cc_by_sa_four;
case Prefs.Licenses.CC0:
return R.string.license_name_cc0;
}
throw new IllegalStateException("Unrecognized license value: " + license);
}
/**
* Generates license url with given ID
* @param license License ID
* @return Url of license
*/
@NonNull
public static String licenseUrlFor(String license) {
switch (license) {
case Prefs.Licenses.CC_BY_3:
return "https://creativecommons.org/licenses/by/3.0/";
case Prefs.Licenses.CC_BY_4:
return "https://creativecommons.org/licenses/by/4.0/";
case Prefs.Licenses.CC_BY_SA_3:
return "https://creativecommons.org/licenses/by-sa/3.0/";
case Prefs.Licenses.CC_BY_SA_4:
return "https://creativecommons.org/licenses/by-sa/4.0/";
case Prefs.Licenses.CC0:
return "https://creativecommons.org/publicdomain/zero/1.0/";
default:
throw new IllegalStateException("Unrecognized license value: " + license);
}
}
/**
* Adds extension to filename. Converts to .jpg if system provides .jpeg, adds .jpg if no extension detected
* @param title File name
* @param extension Correct extension
* @return File with correct extension
*/
public static String fixExtension(String title, String extension) {
Pattern jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE);
// People are used to ".jpg" more than ".jpeg" which the system gives us.
if (extension != null && extension.toLowerCase(Locale.ENGLISH).equals("jpeg")) {
extension = "jpg";
}
title = jpegPattern.matcher(title).replaceFirst(".jpg");
if (extension != null && !title.toLowerCase(Locale.getDefault())
.endsWith("." + extension.toLowerCase(Locale.ENGLISH))) {
title += "." + extension;
}
// If extension is still null, make it jpg. (Hotfix for https://github.com/commons-app/apps-android-commons/issues/228)
// If title has an extension in it, if won't be true
if (extension == null && title.lastIndexOf(".")<=0) {
extension = "jpg";
title += "." + extension;
}
return title;
}
/**
* Launches intent to rate app
* @param context
*/
public static void rateApp(Context context) {
final String appPackageName = context.getPackageName();
try {
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Urls.PLAY_STORE_PREFIX + appPackageName)));
}
catch (android.content.ActivityNotFoundException anfe) {
handleWebUrl(context, Uri.parse(Urls.PLAY_STORE_URL_PREFIX + appPackageName));
}
}
/**
* Opens Custom Tab Activity with in-app browser for the specified URL.
* Launches intent for web URL
* @param context
* @param url
*/
public static void handleWebUrl(Context context, Uri url) {
Timber.d("Launching web url %s", url.toString());
final CustomTabColorSchemeParams color = new CustomTabColorSchemeParams.Builder()
.setToolbarColor(ContextCompat.getColor(context, R.color.primaryColor))
.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.primaryDarkColor))
.build();
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setDefaultColorSchemeParams(color);
builder.setExitAnimations(context, android.R.anim.slide_in_left, android.R.anim.slide_out_right);
CustomTabsIntent customTabsIntent = builder.build();
// Clear previous browser tasks, so that back/exit buttons work as intended.
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
customTabsIntent.launchUrl(context, url);
}
/**
* Util function to handle geo coordinates. It no longer depends on google maps and any app
* capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
*/
public static void handleGeoCoordinates(final Context context, final LatLng latLng) {
handleGeoCoordinates(context, latLng, 16);
}
/**
* Util function to handle geo coordinates with specified zoom level. It no longer depends on
* google maps and any app capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
* @param zoomLevel The zoom level
*/
public static void handleGeoCoordinates(final Context context, final LatLng latLng,
final double zoomLevel) {
final Intent mapIntent = new Intent(Intent.ACTION_VIEW, latLng.getGmmIntentUri(zoomLevel));
if (mapIntent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(mapIntent);
} else {
ViewUtil.showShortToast(context, context.getString(R.string.map_application_missing));
}
}
/**
* To take screenshot of the screen and return it in Bitmap format
*
* @param view
* @return
*/
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap drawingCache = screenView.getDrawingCache();
if (drawingCache != null) {
Bitmap bitmap = Bitmap.createBitmap(drawingCache);
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
return null;
}
/*
*Copies the content to the clipboard
*
*/
public static void copy(String label,String text, Context context){
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(label, text);
clipboard.setPrimaryClip(clip);
}
/**
* This method sets underlined string text to a TextView
*
* @param textView TextView associated with string resource
* @param stringResourceName string resource name
* @param context
*/
public static void setUnderlinedText(TextView textView, int stringResourceName, Context context) {
SpannableString content = new SpannableString(context.getString(stringResourceName));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
textView.setText(content);
}
/**
* For now we are enabling the monuments only when the date lies between 1 Sept & 31 OCt
* @param date
* @return
*/
public static boolean isMonumentsEnabled(final Date date) {
if (date.getMonth() == 8) {
return true;
}
return false;
}
/**
* Util function to get the start date of wlm monument
* For this release we are hardcoding it to be 1st September
* @return
*/
public static String getWLMStartDate() {
return "1 Sep";
}
/***
* Util function to get the end date of wlm monument
* For this release we are hardcoding it to be 31st October
* @return
*/
public static String getWLMEndDate() {
return "30 Sep";
}
/***
* Function to get the current WLM year
* It increments at the start of September in line with the other WLM functions
* (No consideration of locales for now)
* @param calendar
* @return
*/
public static int getWikiLovesMonumentsYear(Calendar calendar) {
int year = calendar.get(Calendar.YEAR);
if (calendar.get(Calendar.MONTH) < Calendar.SEPTEMBER) {
year -= 1;
}
return year;
}
}

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
@ -7,6 +9,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import androidx.viewpager.widget.PagerAdapter;
import fr.free.nrw.commons.utils.UnderlineUtils;
public class WelcomePagerAdapter extends PagerAdapter {
private static final int[] PAGE_LAYOUTS = new int[]{
@ -46,8 +49,8 @@ public class WelcomePagerAdapter extends PagerAdapter {
if (position == PAGE_LAYOUTS.length - 1) {
// Add link to more information
TextView moreInfo = layout.findViewById(R.id.welcomeInfo);
Utils.setUnderlinedText(moreInfo, R.string.welcome_help_button_text, container.getContext());
moreInfo.setOnClickListener(view -> Utils.handleWebUrl(
UnderlineUtils.setUnderlinedText(moreInfo, R.string.welcome_help_button_text);
moreInfo.setOnClickListener(view -> handleWebUrl(
container.getContext(),
Uri.parse("https://commons.wikimedia.org/wiki/Help:Contents")
));

View file

@ -25,7 +25,6 @@ import androidx.core.content.ContextCompat
import fr.free.nrw.commons.BuildConfig
import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.login.LoginCallback
import fr.free.nrw.commons.auth.login.LoginClient
import fr.free.nrw.commons.auth.login.LoginResult
@ -38,6 +37,7 @@ import fr.free.nrw.commons.utils.ActivityUtils.startActivityWithFlags
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.hideKeyboard
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import java.util.Locale
@ -263,10 +263,10 @@ class LoginActivity : AccountAuthenticatorActivity() {
}
private fun forgotPassword() =
Utils.handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL))
handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL))
private fun onPrivacyPolicyClicked() =
Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL))
handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL))
private fun signUp() =
startActivity(Intent(this, SignupActivity::class.java))

View file

@ -7,7 +7,6 @@ import android.view.LayoutInflater
import android.view.View
import androidx.core.content.ContextCompat
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.campaigns.models.Campaign
import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.databinding.LayoutCampaginBinding
@ -16,6 +15,7 @@ import fr.free.nrw.commons.utils.CommonsDateUtil.getIso8601DateFormatShort
import fr.free.nrw.commons.utils.DateUtil.getExtraShortDateString
import fr.free.nrw.commons.utils.SwipableCardView
import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.handleWebUrl
import timber.log.Timber
import java.text.ParseException
@ -74,7 +74,7 @@ class CampaignView : SwipableCardView {
if (it.isWLMCampaign) {
((context) as MainActivity).showNearby()
} else {
Utils.handleWebUrl(context, Uri.parse(it.link))
handleWebUrl(context, Uri.parse(it.link))
}
}
}

View file

@ -26,7 +26,7 @@ class CampaignsPresenter @Inject constructor(
private val okHttpJsonApiClient: OkHttpJsonApiClient?,
@param:Named(IO_THREAD) private val ioScheduler: Scheduler,
@param:Named(MAIN_THREAD) private val mainThreadScheduler: Scheduler
) : BasePresenter<ICampaignsView?> {
) : BasePresenter<ICampaignsView> {
private var view: ICampaignsView? = null
private var disposable: Disposable? = null
private var campaign: Campaign? = null

View file

@ -1,11 +1,10 @@
package fr.free.nrw.commons.campaigns
import fr.free.nrw.commons.MvpView
import fr.free.nrw.commons.campaigns.models.Campaign
/**
* Interface which defines the view contracts of the campaign view
*/
interface ICampaignsView : MvpView {
interface ICampaignsView {
fun showCampaigns(campaign: Campaign?)
}

View file

@ -13,9 +13,9 @@ import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import fr.free.nrw.commons.BuildConfig.COMMONS_URL
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.ViewPagerAdapter
import fr.free.nrw.commons.databinding.ActivityCategoryDetailsBinding
import fr.free.nrw.commons.explore.categories.media.CategoriesMediaFragment
@ -23,6 +23,9 @@ import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesFragment
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.model.WikiSite
import fr.free.nrw.commons.wikidata.model.page.PageTitle
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -199,8 +202,9 @@ class CategoryDetailsActivity : BaseActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_browser_current_category -> {
val title = Utils.getPageTitle(CATEGORY_PREFIX + categoryName)
Utils.handleWebUrl(this, Uri.parse(title.canonicalUri))
val title = PageTitle(CATEGORY_PREFIX + categoryName, WikiSite(COMMONS_URL))
handleWebUrl(this, Uri.parse(title.canonicalUri))
true
}

View file

@ -9,7 +9,6 @@ import fr.free.nrw.commons.BasePresenter
interface ContributionsContract {
interface View {
fun showMessage(localizedMessage: String)
fun getContext(): Context?
}

View file

@ -30,7 +30,6 @@ import androidx.work.WorkManager
import fr.free.nrw.commons.MapController.NearbyPlacesInfo
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.campaigns.CampaignView
import fr.free.nrw.commons.campaigns.CampaignsPresenter
@ -64,6 +63,9 @@ import fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween
import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished
import fr.free.nrw.commons.utils.PermissionUtils.hasPermission
import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.isMonumentsEnabled
import fr.free.nrw.commons.utils.wLMEndDate
import fr.free.nrw.commons.utils.wLMStartDate
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
@ -242,8 +244,8 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
private fun initWLMCampaign() {
wlmCampaign = Campaign(
getString(R.string.wlm_campaign_title),
getString(R.string.wlm_campaign_description), Utils.getWLMStartDate().toString(),
Utils.getWLMEndDate().toString(), NearbyParentFragment.WLM_URL, true
getString(R.string.wlm_campaign_description), wLMStartDate,
wLMEndDate, NearbyParentFragment.WLM_URL, true
)
}
@ -729,7 +731,7 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
* of campaigns on the campaigns card
*/
private fun fetchCampaigns() {
if (Utils.isMonumentsEnabled(Date())) {
if (isMonumentsEnabled) {
if (binding != null) {
binding!!.campaignsView.setCampaign(wlmCampaign)
binding!!.campaignsView.visibility = View.VISIBLE
@ -743,10 +745,6 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
}
}
override fun showMessage(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
override fun showCampaigns(campaign: Campaign?) {
if (campaign != null && !isUserProfile) {
if (binding != null) {

View file

@ -15,7 +15,7 @@ class ContributionsListContract {
fun showNoContributionsUI(shouldShow: Boolean)
}
interface UserActionListener : BasePresenter<View?> {
interface UserActionListener : BasePresenter<View> {
fun refreshList(swipeRefreshLayout: SwipeRefreshLayout?)
}
}

View file

@ -29,7 +29,6 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.contributions.WikipediaInstructionsDialogFragment.Companion.newInstance
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding
@ -41,6 +40,8 @@ import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.model.WikiSite
import org.apache.commons.lang3.StringUtils
import javax.inject.Inject
@ -527,14 +528,13 @@ class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsL
*/
override fun onConfirmClicked(contribution: Contribution?, copyWikicode: Boolean) {
if (copyWikicode) {
val wikicode = contribution!!.media.wikiCode
Utils.copy("wikicode", wikicode, context)
requireContext().copyToClipboard("wikicode", contribution!!.media.wikiCode)
}
val url =
languageWikipediaSite!!.mobileUrl() + "/wiki/" + (contribution!!.wikidataPlace
?.getWikipediaPageTitle())
Utils.handleWebUrl(context, Uri.parse(url))
handleWebUrl(requireContext(), Uri.parse(url))
}
fun getContributionStateAt(position: Int): Int {

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.explore.depictions;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@ -8,16 +10,11 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.ViewPagerAdapter;
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
import fr.free.nrw.commons.category.CategoryImagesCallback;
@ -249,7 +246,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
case R.id.browser_actions_menu_items:
String entityId=getIntent().getStringExtra("entityId");
Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId);
Utils.handleWebUrl(this, uri);
handleWebUrl(this, uri);
return true;
case R.id.menu_bookmark_current_item:

View file

@ -2,7 +2,9 @@ package fr.free.nrw.commons.explore.map;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
import static fr.free.nrw.commons.utils.GeoCoordinatesKt.handleGeoCoordinates;
import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.Manifest.permission;
import android.annotation.SuppressLint;
@ -36,7 +38,6 @@ import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.MapController;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.databinding.FragmentExploreMapBinding;
@ -639,13 +640,13 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
*/
private void passInfoToSheet(final Place place) {
binding.bottomSheetDetailsBinding.directionsButton.setOnClickListener(
view -> Utils.handleGeoCoordinates(getActivity(),
view -> handleGeoCoordinates(requireActivity(),
place.getLocation(), binding.mapView.getZoomLevelDouble()));
binding.bottomSheetDetailsBinding.commonsButton.setVisibility(
place.hasCommonsLink() ? View.VISIBLE : View.GONE);
binding.bottomSheetDetailsBinding.commonsButton.setOnClickListener(
view -> Utils.handleWebUrl(getContext(), place.siteLinks.getCommonsLink()));
view -> handleWebUrl(getContext(), place.siteLinks.getCommonsLink()));
int index = 0;
for (Media media : mediaList) {

View file

@ -30,7 +30,6 @@ import fr.free.nrw.commons.CameraPosition
import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
import fr.free.nrw.commons.coordinates.CoordinateEditHelper
@ -45,6 +44,7 @@ import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Compani
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Companion.LAST_ZOOM
import fr.free.nrw.commons.utils.DialogUtil
import fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL
import fr.free.nrw.commons.utils.handleGeoCoordinates
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@ -432,8 +432,8 @@ class LocationPickerActivity : BaseActivity(), LocationPermissionCallback {
position?.let {
mapView?.zoomLevelDouble?.let { zoomLevel ->
Utils.handleGeoCoordinates(this, it, zoomLevel)
} ?: Utils.handleGeoCoordinates(this, it)
handleGeoCoordinates(this, it, zoomLevel)
} ?: handleGeoCoordinates(this, it)
}
}

View file

@ -77,7 +77,7 @@ import fr.free.nrw.commons.CommonsApplication.Companion.instance
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.utils.UnderlineUtils
import fr.free.nrw.commons.actions.ThanksClient
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
@ -119,6 +119,10 @@ import fr.free.nrw.commons.utils.PermissionUtils.hasPermission
import fr.free.nrw.commons.utils.ViewUtil
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
import fr.free.nrw.commons.utils.ViewUtilWrapper
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.setUnderlinedText
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.Revision
import io.reactivex.Observable
import io.reactivex.Single
@ -316,8 +320,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
_binding = FragmentMediaDetailBinding.inflate(inflater, container, false)
val view: View = binding.root
Utils.setUnderlinedText(binding.seeMore, R.string.nominated_see_more, requireContext())
binding.seeMore.setUnderlinedText(R.string.nominated_see_more)
if (isCategoryImage) {
binding.authorLinearLayout.visibility = View.VISIBLE
@ -909,7 +912,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
private fun onMediaDetailLicenceClicked() {
val url: String? = media!!.licenseUrl
if (!StringUtils.isBlank(url) && activity != null) {
Utils.handleWebUrl(activity, Uri.parse(url))
handleWebUrl(requireContext(), Uri.parse(url))
} else {
viewUtil.showShortToast(requireActivity(), getString(R.string.null_url))
}
@ -917,17 +920,17 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
private fun onMediaDetailCoordinatesClicked() {
if (media!!.coordinates != null && activity != null) {
Utils.handleGeoCoordinates(activity, media!!.coordinates)
handleGeoCoordinates(requireContext(), media!!.coordinates!!)
}
}
private fun onCopyWikicodeClicked() {
val data: String =
"[[" + media!!.filename + "|thumb|" + media!!.fallbackDescription + "]]"
Utils.copy("wikiCode", data, context)
requireContext().copyToClipboard("wikiCode", data)
Timber.d("Generated wikidata copy code: %s", data)
Toast.makeText(context, getString(R.string.wikicode_copied), Toast.LENGTH_SHORT)
Toast.makeText(requireContext(), getString(R.string.wikicode_copied), Toast.LENGTH_SHORT)
.show()
}
@ -1765,7 +1768,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
private fun onSeeMoreClicked() {
if (binding.nominatedDeletionBanner.visibility == View.VISIBLE && activity != null) {
Utils.handleWebUrl(activity, Uri.parse(media!!.pageTitle.mobileUri))
handleWebUrl(requireContext(), Uri.parse(media!!.pageTitle.mobileUri))
}
}

View file

@ -1,6 +1,6 @@
package fr.free.nrw.commons.media;
import static fr.free.nrw.commons.Utils.handleWebUrl;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.os.Handler;
import android.os.Looper;
@ -31,7 +31,7 @@ import com.google.android.material.snackbar.Snackbar;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.utils.ClipboardUtils;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.bookmarks.models.Bookmark;
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
@ -216,7 +216,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
return true;
case R.id.menu_copy_link:
String uri = m.getPageTitle().getCanonicalUri();
Utils.copy("shareLink", uri, requireContext());
ClipboardUtils.copy("shareLink", uri, requireContext());
Timber.d("Copied share link to clipboard: %s", uri);
Toast.makeText(requireContext(), getString(R.string.menu_link_copied),
Toast.LENGTH_SHORT).show();

View file

@ -10,12 +10,13 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.PopupMenu
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.LoginActivity
import fr.free.nrw.commons.contributions.ContributionController
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.utils.ActivityUtils
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.WikidataConstants
import timber.log.Timber
import javax.inject.Inject
@ -104,7 +105,7 @@ class CommonPlaceClickActions
fun onDirectionsClicked(): (Place) -> Unit =
{
Utils.handleGeoCoordinates(activity, it.getLocation())
handleGeoCoordinates(activity, it.getLocation())
}
private fun storeSharedPrefs(selectedPlace: Place) {
@ -113,7 +114,7 @@ class CommonPlaceClickActions
}
private fun openWebView(link: Uri): Boolean {
Utils.handleWebUrl(activity, link)
handleWebUrl(activity, link)
return true
}

View file

@ -58,12 +58,10 @@ import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.MapController.NearbyPlacesInfo
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
import fr.free.nrw.commons.contributions.ContributionController
import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment
import fr.free.nrw.commons.customselector.ui.selector.ImageLoader
import fr.free.nrw.commons.databinding.FragmentNearbyParentBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.filepicker.FilePicker
@ -76,7 +74,6 @@ import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
import fr.free.nrw.commons.location.LocationUpdateListener
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.navtab.NavTab
import fr.free.nrw.commons.nearby.BottomSheetAdapter
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
@ -105,6 +102,10 @@ import fr.free.nrw.commons.utils.NearbyFABUtils.removeAnchorFromFAB
import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished
import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.isMonumentsEnabled
import fr.free.nrw.commons.wikidata.WikidataConstants
import fr.free.nrw.commons.wikidata.WikidataEditListener
import fr.free.nrw.commons.wikidata.WikidataEditListener.WikidataP18EditListener
@ -140,7 +141,6 @@ import java.util.UUID
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Named
import javax.sql.DataSource
import kotlin.concurrent.Volatile
@ -467,7 +467,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
}
}
_isDarkTheme = systemThemeUtils?.isDeviceInNightMode() == true
if (Utils.isMonumentsEnabled(Date())) {
if (isMonumentsEnabled) {
binding?.rlContainerWlmMonthMessage?.visibility = View.VISIBLE
} else {
binding?.rlContainerWlmMonthMessage?.visibility = View.GONE
@ -836,7 +836,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
loadAnimations()
setBottomSheetCallbacks()
addActionToTitle()
if (!Utils.isMonumentsEnabled(Date())) {
if (!isMonumentsEnabled) {
NearbyFilterState.setWlmSelected(false)
}
}
@ -1017,11 +1017,10 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
*/
private fun addActionToTitle() {
binding!!.bottomSheetDetails.title.setOnLongClickListener { view ->
Utils.copy(
"place", binding!!.bottomSheetDetails.title.text.toString(),
context
requireContext().copyToClipboard(
"place", binding!!.bottomSheetDetails.title.text.toString()
)
Toast.makeText(context, fr.free.nrw.commons.R.string.text_copy, Toast.LENGTH_SHORT)
Toast.makeText(requireContext(), fr.free.nrw.commons.R.string.text_copy, Toast.LENGTH_SHORT)
.show()
true
}
@ -1580,7 +1579,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
searchLatLng,
false,
true,
Utils.isMonumentsEnabled(Date()),
isMonumentsEnabled,
customQuery
)
}
@ -1633,7 +1632,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
searchLatLng,
false,
true,
Utils.isMonumentsEnabled(Date()),
isMonumentsEnabled,
customQuery
)
}
@ -2854,14 +2853,14 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
R.drawable.ic_directions_black_24dp -> {
selectedPlace?.let {
Utils.handleGeoCoordinates(this.context, it.getLocation())
handleGeoCoordinates(requireContext(), it.getLocation())
binding?.map?.zoomLevelDouble ?: 0.0
}
}
R.drawable.ic_wikidata_logo_24dp -> {
selectedPlace?.siteLinks?.wikidataLink?.let {
Utils.handleWebUrl(this.context, it)
handleWebUrl(requireContext(), it)
}
}
@ -2879,13 +2878,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
R.drawable.ic_wikipedia_logo_24dp -> {
selectedPlace?.siteLinks?.wikipediaLink?.let {
Utils.handleWebUrl(this.context, it)
handleWebUrl(requireContext(), it)
}
}
R.drawable.ic_commons_icon_vector -> {
selectedPlace?.siteLinks?.commonsLink?.let {
Utils.handleWebUrl(this.context, it)
handleWebUrl(requireContext(), it)
}
}

View file

@ -13,7 +13,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.databinding.ActivityNotificationBinding
@ -22,6 +21,7 @@ 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
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@ -197,7 +197,7 @@ class NotificationActivity : BaseActivity() {
private fun handleUrl(url: String?) {
if (url.isNullOrEmpty()) return
Utils.handleWebUrl(this, Uri.parse(url))
handleWebUrl(this, Uri.parse(url))
}
private fun setItems(notificationList: List<Notification>?) {

View file

@ -3,16 +3,16 @@ package fr.free.nrw.commons.profile
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.ViewPagerAdapter
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.contributions.ContributionsFragment
@ -23,7 +23,7 @@ import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.DialogUtil
import java.io.File
import java.io.FileOutputStream
import java.util.*
import java.util.Locale
import javax.inject.Inject
/**
@ -133,7 +133,7 @@ class ProfileActivity : BaseActivity() {
return when (item.itemId) {
R.id.share_app_icon -> {
val rootView = window.decorView.findViewById<View>(android.R.id.content)
val screenShot = Utils.getScreenShot(rootView)
val screenShot = getScreenShot(rootView)
if (screenShot == null) {
Log.e("ERROR", "ScreenShot is null")
return false
@ -212,6 +212,24 @@ class ProfileActivity : BaseActivity() {
binding.tabLayout.visibility = if (isVisible) View.VISIBLE else View.GONE
}
/**
* To take screenshot of the screen and return it in Bitmap format
*
* @param view
* @return
*/
fun getScreenShot(view: View): Bitmap? {
val screenView = view.rootView
screenView.isDrawingCacheEnabled = true
val drawingCache = screenView.drawingCache
if (drawingCache != null) {
val bitmap = Bitmap.createBitmap(drawingCache)
screenView.isDrawingCacheEnabled = false
return bitmap
}
return null
}
companion object {
const val KEY_USERNAME = "username"
const val KEY_SHOULD_SHOW_CONTRIBUTIONS = "shouldShowContributions"

View file

@ -15,7 +15,6 @@ import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.badge.ExperimentalBadgeUtils
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.databinding.FragmentAchievementsBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
@ -27,6 +26,7 @@ import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.ViewUtil.showDismissibleSnackBar
import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.StringUtils
@ -524,7 +524,7 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
getString(R.string.ok),
getString(R.string.read_help_link),
{},
{ Utils.handleWebUrl(requireContext(), Uri.parse(helpLinkUrl)) },
{ handleWebUrl(requireContext(), Uri.parse(helpLinkUrl)) },
null
)
}

View file

@ -33,9 +33,7 @@ import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import fr.free.nrw.commons.BuildConfig.MOBILE_META_URL
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.activity.SingleWebViewActivity
import fr.free.nrw.commons.campaigns.CampaignView
import fr.free.nrw.commons.contributions.ContributionController
@ -53,6 +51,7 @@ import fr.free.nrw.commons.utils.DialogUtil
import fr.free.nrw.commons.utils.PermissionUtils
import fr.free.nrw.commons.utils.StringUtil
import fr.free.nrw.commons.utils.ViewUtil
import fr.free.nrw.commons.utils.handleWebUrl
import java.util.Locale
import javax.inject.Inject
import javax.inject.Named
@ -239,7 +238,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
val betaTesterPreference: Preference? = findPreference("becomeBetaTester")
betaTesterPreference?.setOnPreferenceClickListener {
Utils.handleWebUrl(requireActivity(), Uri.parse(getString(R.string.beta_opt_in_link)))
handleWebUrl(
requireActivity(),
Uri.parse(getString(R.string.beta_opt_in_link))
)
true
}
@ -296,7 +298,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
getString(R.string.ok),
getString(R.string.read_help_link),
{ },
{ Utils.handleWebUrl(requireContext(), Uri.parse(GET_CONTENT_PICKER_HELP_URL)) },
{ handleWebUrl(requireContext(), Uri.parse(GET_CONTENT_PICKER_HELP_URL)) },
null
)
}

View file

@ -1,11 +1,11 @@
package fr.free.nrw.commons.upload
import android.content.Context
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.filepicker.UploadableFile.DateTimeWithSource
import fr.free.nrw.commons.settings.Prefs.Licenses
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
import fr.free.nrw.commons.utils.getWikiLovesMonumentsYear
import org.apache.commons.lang3.StringUtils
import java.text.SimpleDateFormat
import java.util.Calendar
@ -49,7 +49,7 @@ class PageContentsCreator @Inject constructor(private val context: Context) {
String.format(
Locale.ENGLISH,
"{{Wiki Loves Monuments %d|1= %s}}\n",
Utils.getWikiLovesMonumentsYear(Calendar.getInstance()),
getWikiLovesMonumentsYear(Calendar.getInstance()),
contribution.countryCode
)
)

View file

@ -1,10 +1,10 @@
package fr.free.nrw.commons.upload
import android.net.Uri
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper.Companion.getExtensionFromMimeType
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.utils.ImageUtils
import fr.free.nrw.commons.utils.fixExtension
class UploadItem(
var mediaUri: Uri?,
@ -32,7 +32,7 @@ class UploadItem(
* languages have been entered, the first language is used.
*/
val filename: String
get() = Utils.fixExtension(
get() = fixExtension(
uploadMediaDetails[0].captionText,
getExtensionFromMimeType(mimeType)
)

View file

@ -16,11 +16,13 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.TextView
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.databinding.FragmentMediaLicenseBinding
import fr.free.nrw.commons.upload.UploadActivity
import fr.free.nrw.commons.upload.UploadBaseFragment
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.toLicenseName
import fr.free.nrw.commons.utils.toLicenseUrl
import timber.log.Timber
import javax.inject.Inject
@ -126,20 +128,20 @@ class MediaLicenseFragment : UploadBaseFragment(), MediaLicenseContract.View {
}
override fun setSelectedLicense(license: String?) {
var position = licenses!!.indexOf(getString(Utils.licenseNameFor(license)))
var position = license?.let { licenses!!.indexOf(getString(it.toLicenseName())) } ?: -1
// Check if position is valid
if (position < 0) {
Timber.d("Invalid position: %d. Using default licenses", position)
position = licenses!!.size - 1
} else {
Timber.d("Position: %d %s", position, getString(Utils.licenseNameFor(license)))
}
binding.spinnerLicenseList.setSelection(position)
}
override fun updateLicenseSummary(selectedLicense: String?, numberOfItems: Int) {
val licenseHyperLink = "<a href='" + Utils.licenseUrlFor(selectedLicense) + "'>" +
getString(Utils.licenseNameFor(selectedLicense)) + "</a><br>"
if (selectedLicense == null) return
val licenseHyperLink = "<a href='" + selectedLicense.toLicenseUrl() + "'>" +
getString(selectedLicense.toLicenseName()) + "</a><br>"
setTextViewHTML(
binding.tvShareLicenseSummary, resources
@ -184,7 +186,7 @@ class MediaLicenseFragment : UploadBaseFragment(), MediaLicenseContract.View {
}
private fun launchBrowser(hyperLink: String) =
Utils.handleWebUrl(context, Uri.parse(hyperLink))
handleWebUrl(requireContext(), Uri.parse(hyperLink))
override fun onDestroyView() {
presenter.onDetachView()

View file

@ -1,9 +1,9 @@
package fr.free.nrw.commons.upload.license
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.settings.Prefs
import fr.free.nrw.commons.utils.toLicenseName
import timber.log.Timber
import java.lang.reflect.Method
import java.lang.reflect.Proxy
@ -34,12 +34,14 @@ class MediaLicensePresenter @Inject constructor(
val licenses = repository.getLicenses()
view.setLicenses(licenses)
var selectedLicense = defaultKVStore.getString(
//CC_BY_SA_4 is the default one used by the commons web app
var selectedLicense: String = defaultKVStore.getString(
Prefs.DEFAULT_LICENSE,
Prefs.Licenses.CC_BY_SA_4
) //CC_BY_SA_4 is the default one used by the commons web app
) ?: Prefs.Licenses.CC_BY_SA_4
try { //I have to make sure that the stored default license was not one of the deprecated one's
Utils.licenseNameFor(selectedLicense)
selectedLicense.toLicenseName()
} catch (exception: IllegalStateException) {
Timber.e(exception)
selectedLicense = Prefs.Licenses.CC_BY_SA_4

View file

@ -54,7 +54,7 @@ interface UploadMediaDetailsContract {
fun showBadImagePopup(errorCode: Int, index: Int, uploadItem: UploadItem)
}
interface UserActionListener : BasePresenter<View?> {
interface UserActionListener : BasePresenter<View> {
fun setupBasicKvStoreFactory(factory: (String) -> BasicKvStore)
fun receiveImage(

View file

@ -0,0 +1,20 @@
package fr.free.nrw.commons.utils
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
object ClipboardUtils {
// Convenience for Java usages - remove when they are converted.
@JvmStatic
fun copy(label: String?, text: String?, context: Context) {
context.copyToClipboard(label, text)
}
}
fun Context.copyToClipboard(label: String?, text: String?) {
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
setPrimaryClip(ClipData.newPlainText(label, text))
}
}

View file

@ -0,0 +1,38 @@
package fr.free.nrw.commons.utils
import java.util.Locale
import java.util.regex.Pattern
private val jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE)
/**
* Adds extension to filename. Converts to .jpg if system provides .jpeg, adds .jpg if no extension detected
* @param theTitle File name
* @param ext Correct extension
* @return File with correct extension
*/
fun fixExtension(theTitle: String, ext: String?): String {
var result = theTitle
var extension = ext
// People are used to ".jpg" more than ".jpeg" which the system gives us.
if (extension != null && extension.lowercase() == "jpeg") {
extension = "jpg"
}
result = jpegPattern.matcher(result).replaceFirst(".jpg")
if (extension != null &&
!result.lowercase(Locale.getDefault()).endsWith("." + extension.lowercase())
) {
result += ".$extension"
}
// If extension is still null, make it jpg. (Hotfix for https://github.com/commons-app/apps-android-commons/issues/228)
// If title has an extension in it, if won't be true
if (extension == null && result.lastIndexOf(".") <= 0) {
extension = "jpg"
result += ".$extension"
}
return result
}

View file

@ -0,0 +1,27 @@
package fr.free.nrw.commons.utils
import android.content.Context
import android.content.Intent
import fr.free.nrw.commons.R
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
/**
* Util function to handle geo coordinates with specified zoom level. It no longer depends on
* google maps and any app capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
* @param zoomLevel The zoom level
*/
fun handleGeoCoordinates(
context: Context, latLng: LatLng,
zoomLevel: Double = 16.0
) {
val mapIntent = Intent(Intent.ACTION_VIEW, latLng.getGmmIntentUri(zoomLevel))
if (mapIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(mapIntent)
} else {
showShortToast(context, context.getString(R.string.map_application_missing))
}
}

View file

@ -0,0 +1,31 @@
package fr.free.nrw.commons.utils
import fr.free.nrw.commons.R
import fr.free.nrw.commons.settings.Prefs
/**
* Generates licence name with given ID
* @return Name of license
*/
fun String.toLicenseName(): Int = when (this) {
Prefs.Licenses.CC_BY_3 -> R.string.license_name_cc_by
Prefs.Licenses.CC_BY_4 -> R.string.license_name_cc_by_four
Prefs.Licenses.CC_BY_SA_3 -> R.string.license_name_cc_by_sa
Prefs.Licenses.CC_BY_SA_4 -> R.string.license_name_cc_by_sa_four
Prefs.Licenses.CC0 -> R.string.license_name_cc0
else -> throw IllegalStateException("Unrecognized license value: $this")
}
/**
* Generates license url with given ID
* @return Url of license
*/
fun String.toLicenseUrl(): String = when (this) {
Prefs.Licenses.CC_BY_3 -> "https://creativecommons.org/licenses/by/3.0/"
Prefs.Licenses.CC_BY_4 -> "https://creativecommons.org/licenses/by/4.0/"
Prefs.Licenses.CC_BY_SA_3 -> "https://creativecommons.org/licenses/by-sa/3.0/"
Prefs.Licenses.CC_BY_SA_4 -> "https://creativecommons.org/licenses/by-sa/4.0/"
Prefs.Licenses.CC0 -> "https://creativecommons.org/publicdomain/zero/1.0/"
else -> throw IllegalStateException("Unrecognized license value: $this")
}

View file

@ -0,0 +1,39 @@
package fr.free.nrw.commons.utils
import java.util.Calendar
import java.util.Date
/**
* Get the start date of wlm monument
* For this release we are hardcoding it to be 1st September
* @return
*/
const val wLMStartDate: String = "1 Sep"
/***
* Get the end date of wlm monument
* For this release we are hardcoding it to be 31st October
* @return
*/
const val wLMEndDate: String = "30 Sep"
/**
* For now we are enabling the monuments only when the date lies between 1 Sept & 31 OCt
*/
val isMonumentsEnabled: Boolean
get() = Date().month == 8
/***
* Function to get the current WLM year
* It increments at the start of September in line with the other WLM functions
* (No consideration of locales for now)
* @param calendar
* @return
*/
fun getWikiLovesMonumentsYear(calendar: Calendar): Int {
var year = calendar[Calendar.YEAR]
if (calendar[Calendar.MONTH] < Calendar.SEPTEMBER) {
year -= 1
}
return year
}

View file

@ -0,0 +1,19 @@
package fr.free.nrw.commons.utils
import android.widget.TextView
import androidx.core.text.buildSpannedString
import androidx.core.text.underline
object UnderlineUtils {
// Convenience method for Java usages - remove when those classes are converted
@JvmStatic
fun setUnderlinedText(textView: TextView, stringResourceName: Int) {
textView.setUnderlinedText(stringResourceName)
}
}
fun TextView.setUnderlinedText(stringResourceName: Int) {
text = buildSpannedString {
underline { append(context.getString(stringResourceName)) }
}
}

View file

@ -0,0 +1,33 @@
package fr.free.nrw.commons.utils
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import fr.free.nrw.commons.R
import timber.log.Timber
/**
* Opens Custom Tab Activity with in-app browser for the specified URL.
* Launches intent for web URL
*/
fun handleWebUrl(context: Context, url: Uri) {
Timber.d("Launching web url %s", url.toString())
val color = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ContextCompat.getColor(context, R.color.primaryColor))
.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.primaryDarkColor))
.build()
val customTabsIntent = CustomTabsIntent.Builder()
.setDefaultColorSchemeParams(color)
.setExitAnimations(
context, android.R.anim.slide_in_left, android.R.anim.slide_out_right
).build()
// Clear previous browser tasks, so that back/exit buttons work as intended.
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
customTabsIntent.launchUrl(context, url)
}

View file

@ -135,31 +135,266 @@
<string name="display_list_button">Siyahı</string>
<string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string>
<string name="categories_not_found">%1$s axtarışına uyğun kateqoriya tapılmadı</string>
<string name="depictions_not_found">%1$s uyğun heç bir Vikidata elementi tapılmadı</string>
<string name="no_child_classes">%1$s alt sinifləri yoxdur</string>
<string name="no_parent_classes">%1$s üst sinfi yoxdur</string>
<string name="categories_skip_explanation">Şəkillərinizi Vikianbarda daha tapıla bilən etmək üçün kateqoriyalar əlavə edin.\nKateqoriyalar əlavə etmək üçün yazmağa başlayın.</string>
<string name="categories_activity_title">Kateqoriyalar</string>
<string name="title_activity_settings">Nizamlamalar</string>
<string name="title_activity_signup">Qeydiyyatdan keç</string>
<string name="title_activity_featured_images">Seçilmiş şəkillər</string>
<string name="title_activity_custom_selector">Xüsusi Seçici</string>
<string name="title_activity_category_details">Kateqoriya</string>
<string name="title_activity_review">Yoxlanış</string>
<string name="menu_about">Haqqında</string>
<string name="about_license">Vikianbar proqramı Vikimedia icmasının qrant alanları və könüllüləri tərəfindən yaradılmış və dəstəklənən açıq mənbəli proqramdır. Vikimedia Fondu proqramın yaradılması, inkişafı və ya texniki xidmətində iştirak etmir.</string>
<string name="about_improve">Xəta hesabatları və təkliflər üçün yeni &lt;a href=\"%1$s\"&gt;GitHub sorğusu&lt;/a&gt; yaradın.</string>
<string name="about_privacy_policy">Məxfilik siyasəti</string>
<string name="about_credits">Töhfə verənlər</string>
<string name="title_activity_about">Haqqında</string>
<string name="menu_feedback">Rəy göndər (e-poçt vasitəsilə)</string>
<string name="no_email_client">Heç bir e-poçt tətbiqi quraşdırılmayıb</string>
<string name="provider_categories">Son istifadə olunan kateqoriyalar</string>
<string name="waiting_first_sync">İlk sinxronizasiya gözlənilir…</string>
<string name="no_uploads_yet">Siz hələ heç bir şəkil yükləməmisiniz.</string>
<string name="menu_retry_upload">Yenidən cəhd edin</string>
<string name="menu_cancel_upload">İmtina</string>
<string name="media_upload_policy">Bu şəkli yükləməklə bildirirəm ki, bu mənim şəxsi işimdir, onda müəllif hüququ ilə qorunan material və ya selfilər yoxdur və &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\"&gt;Vikianbar qaydalarına&lt;/a&gt; riayət edir.</string>
<string name="menu_download">Endir</string>
<string name="preference_license">Defolt lisenziya</string>
<string name="use_previous">Əvvəlki başlıq və təsvirdən istifadə et</string>
<string name="preference_theme">Tema</string>
<string name="license_name_cc_by_3_0">CC BY 3.0</string>
<string name="tutorial_1_text">Vikianbar Vikipediyada istifadə olunan şəkillərin əksəriyyətinə ev sahibliyi edir.</string>
<string name="tutorial_1_subtext">Şəkilləriniz bütün dünyada insanları maarifləndirməyə kömək edir!</string>
<string name="tutorial_2_text">Tamamilə özünüz tərəfindən çəkilmiş və ya yaradılmış şəkilləri yükləyin:</string>
<string name="tutorial_2_subtext_1">Təbii obyektlər (çiçəklər, heyvanlar, dağlar)</string>
<string name="tutorial_2_subtext_2">Faydalı obyektlər (velosipedlər, qatar stansiyaları)</string>
<string name="tutorial_2_subtext_3">Məşhur insanlar (icra başçınız, tanış olduğunuz olimpiya idmançıları)</string>
<string name="tutorial_3_text">Zəhmət olmasa, YÜKLƏMƏYİN:</string>
<string name="tutorial_3_subtext_1">Selfi və ya dostlarınızın şəkilləri</string>
<string name="tutorial_3_subtext_2">İnternetdə tapdığınız şəkillər</string>
<string name="tutorial_3_subtext_3">Özəl proqramların ekran görüntüləri</string>
<string name="tutorial_4_text">Yükləmə nümunəsi:</string>
<string name="tutorial_4_subtext_1">Başlıq: Sidney Opera Evi</string>
<string name="tutorial_4_subtext_2">Təsvir: Sidney Opera Evinin körfəzdən görünüşü</string>
<string name="tutorial_4_subtext_3">Kateqoriyalar: Sidney Opera Evi Qərb istiqamətindən, Sidney Opera Evinin uzaqdan mənzərələri</string>
<string name="welcome_wikipedia_text">Şəkilləriniz ilə töhfə verin. Vikipediya məqalələrinin canlanmasına kömək edin!</string>
<string name="welcome_wikipedia_subtext">Vikipediyadakı şəkillər Vikianbardan götürülüb.</string>
<string name="welcome_copyright_text">Şəkilləriniz bütün dünyada insanları maarifləndirməyə kömək edir.</string>
<string name="welcome_copyright_subtext">İnternetdən tapdığınız müəllif hüquqları ilə qorunan materialları, eləcə də afişaların, kitab üzlüklərinin və s. şəkillərini yükləməkdən çəkinin.</string>
<string name="welcome_final_text">Sizcə bunu başa düşdünüz?</string>
<string name="welcome_final_button_text">Bəli!</string>
<string name="welcome_help_button_text">Əlavə məlumat</string>
<string name="detail_panel_cats_label">Kateqoriyalar</string>
<string name="detail_panel_cats_loading">Yüklənir...</string>
<string name="detail_panel_cats_none">Heç biri seçilməmişdir</string>
<string name="detail_caption_empty">Başlıq yoxdur</string>
<string name="detail_description_empty">Təsvir yoxdur</string>
<string name="detail_discussion_empty">Müzakirə yoxdur</string>
<string name="detail_license_empty">Naməlum lisenziya</string>
<string name="menu_refresh">Yenilə</string>
<string name="storage_permission_title">Yaddaşa giriş icazəsi tələb olunur</string>
<string name="read_storage_permission_rationale">Tələb olunan icazə: Xarici yaddaşı oxumaq. Bu olmadan proqram qalereyanıza daxil ola bilməz.</string>
<string name="write_storage_permission_rationale">Tələb olunan icazə: Xarici yaddaşa yazmaq. Bu olmadan proqram kameranıza/qalereyanıza daxil ola bilməz.</string>
<string name="location_permission_title">Məkan icazəsi tələb olunur</string>
<string name="in_app_camera_location_permission_title">Tətbiqdaxili çəkilişlər üçün məkanı qeyd et</string>
<string name="in_app_camera_location_switch_pref_summary">Cihaz kamerası onu qeyd etmədiyi halda, məkanı tətbiqdaxili çəkilişlərlə əlavə etmək üçün bunu aktiv edin</string>
<string name="ok">Oldu</string>
<string name="warning">Xəbərdarlıq</string>
<string name="duplicate_file_name">Dublikat fayl adı tapıldı</string>
<string name="upload">Yüklə</string>
<string name="yes">Bəli</string>
<string name="no">Xeyr</string>
<string name="media_detail_caption">Başlıq</string>
<string name="media_detail_title">Başlıq</string>
<string name="media_detail_depiction">Təsvirlər</string>
<string name="media_detail_description">Təsvir</string>
<string name="media_detail_discussion">Müzakirə</string>
<string name="media_detail_author">Müəllif</string>
<string name="media_detail_uploaded_date">Yüklənmə tarixi</string>
<string name="media_detail_license">Lisenziya</string>
<string name="media_detail_coordinates">Koordinatlar</string>
<string name="media_detail_coordinates_empty">Heç biri göstərilməyib</string>
<string name="become_a_tester_title">Beta Tester ol</string>
<string name="become_a_tester_description">Google Play-də beta kanalımıza qoşulun və yeni funksiyalara və xəta həllərinə erkən giriş əldə edin</string>
<string name="_2fa_code">2FA kodu</string>
<string name="email_auth_code">E-poçt doğrulama kodu</string>
<string name="logout_verification">Həqiqətən çıxış etmək istəyirsiniz?</string>
<string name="mediaimage_failed">Media şəkli uğursuz oldu</string>
<string name="no_subcategory_found">Heç bir alt kateqoriya tapılmadı</string>
<string name="no_parentcategory_found">Heç bir üst kateqoriya tapılmadı</string>
<string name="welcome_image_mount_zao">Zao dağı</string>
<string name="welcome_image_llamas">Lamalar</string>
<string name="welcome_image_rainbow_bridge">Göy qurşağı körpüsü</string>
<string name="welcome_image_tulip">Lalə</string>
<string name="welcome_image_welcome_wikipedia">Vikipediyaya xoş gəlmisiniz</string>
<string name="welcome_image_welcome_copyright">Müəlliflik hüquqlarına xoş gəlmisiniz</string>
<string name="welcome_image_sydney_opera_house">Sidney Opera Evi</string>
<string name="cancel">İmtina</string>
<string name="navigation_drawer_open"></string>
<string name="navigation_drawer_close">Bağla</string>
<string name="navigation_item_home">Ana səhifə</string>
<string name="navigation_item_upload">Yüklə</string>
<string name="navigation_item_nearby">Yaxınlıqdakılar</string>
<string name="navigation_item_about">Haqqında</string>
<string name="navigation_item_settings">Parametrlər</string>
<string name="navigation_item_feedback">Rəy</string>
<string name="navigation_item_feedback_github">GitHub vasitəsilə rəy</string>
<string name="navigation_item_logout">Çıxış</string>
<string name="navigation_item_info">Təlimat</string>
<string name="navigation_item_notification">Bildirişlər</string>
<string name="navigation_item_review">Yoxla</string>
<string name="no_description_found">təsvir tapılmadı</string>
<string name="nearby_info_menu_commons_article">Commons fayl səhifəsi</string>
<string name="nearby_info_menu_wikidata_article">Vikidata elementi</string>
<string name="nearby_info_menu_wikipedia_article">Vikipediya məqaləsi</string>
<string name="description_info">Zəhmət olmasa, medianı mümkün qədər təsvir edin: Harada çəkilib? Nəyi təsvir edir? Kontekst nədir? Obyektləri və ya şəxsləri təsvir edin. Asanlıqla təxmin edilə bilməyən məlumatları, məsələn, bir mənzərədirsə, günün saatını qeyd edin. Əgər media qeyri-adi bir şey göstərirsə, zəhmət olmasa, onu izah edin.</string>
<string name="caption_info">Zəhmət olmasa şəklin qısa təsvirini yazın. İlk başlıq şəkil üçün Başlıq kimi istifadə olunacaq. 255 simvolla məhdudlaşır.</string>
<string name="upload_problem_exist">Bu şəkil ilə bağlı potensial problemlər:</string>
<string name="upload_problem_image_dark">Şəkil çox qaranlıqdır.</string>
<string name="upload_problem_image_blurry">Şəkil bulanıqdır.</string>
<string name="upload_problem_image_duplicate">Şəkil artıq Vikianbarda var.</string>
<string name="upload_problem_different_geolocation">Bu şəkil başqa yerdə çəkilib.</string>
<string name="upload_problem_fbmd">Zəhmət olmasa, yalnız özünüz çəkdiyiniz şəkilləri yükləyin. Başqalarının Facebook hesablarında tapdığınız şəkilləri yükləməyin.</string>
<string name="upload_problem_do_you_continue">Hələ də bu şəkli yükləmək istəyirsiniz?</string>
<string name="upload_connection_error_alert_title">Bağlantı xətası</string>
<string name="upload_connection_error_alert_detail">Yükləmə prosesi aktiv internetə çıxış tələb edir. Şəbəkə bağlantınızı yoxlayın.</string>
<string name="upload_problem_image">Şəkildə tapılan problemlər</string>
<string name="internet_downloaded">Zəhmət olmasa, yalnız özünüz çəkdiyiniz şəkilləri yükləyin. İnternetdən tapdığınız şəkilləri yükləməyin.</string>
<string name="use_external_storage">Tətbiqdaxili kadrları yadda saxla</string>
<string name="use_external_storage_summary">Tətbiqdaxili kamera ilə çəkilmiş şəkilləri cihazın yaddaşında saxla</string>
<string name="login_to_your_account">Hesabınıza daxil olun</string>
<string name="send_log_file">Jurnal faylını göndərin</string>
<string name="send_log_file_description">Proqramla bağlı problemlərin aradan qaldırılmasına kömək etmək üçün jurnal faylını tərtibatçılara e-poçt vasitəsilə göndərin. Qeyd: jurnallar potensial olaraq şəxsi məlumatları ehtiva edə bilər</string>
<string name="no_web_browser">URL-i açmaq üçün heç bir veb brauzer tapılmadı</string>
<string name="null_url">Xəta! URL tapılmadı</string>
<string name="nominate_deletion">Silinməyə namizəd göstər</string>
<string name="nominated_for_deletion">Bu şəkil silinməyə namizəddir.</string>
<string name="nominated_see_more">Ətraflı məlumat üçün veb səhifəsinə bax</string>
<string name="skip_login">Ötür</string>
<string name="navigation_item_login">Daxil ol</string>
<string name="skip_login_title">Daxil olma mərhələsini keçmək istədiyinizə əminsiniz?</string>
<string name="skip_login_message">Gələcəkdə şəkilləri yükləmək üçün daxil olmalısınız.</string>
<string name="login_alert_message">Bu funksiyadan istifadə etmək üçün zəhmət olmasa daxil olun</string>
<string name="copy_wikicode">Vikimətni mübadilə buferinə köçür</string>
<string name="wikicode_copied">Vikimətn mübadilə buferinə köçürüldü</string>
<string name="nearby_location_not_available">Yaxınlıqdakılar düzgün işləməyə bilər, məkan əlçatan deyil.</string>
<string name="nearby_showing_pins_offline">İnternet əlçatan deyil. Yalnız keşlənmiş yerlər göstərilir.</string>
<string name="upload_location_access_denied">Məkan girişi rədd edildi. Bu funksiyadan istifadə etmək üçün yerinizi manual təyin edin.</string>
<string name="location_permission_rationale_nearby">Yaxınlıqdakı yerlərin siyahısını göstərmək üçün icazə tələb olunur</string>
<string name="location_permission_rationale_explore">Yaxınlıqdakı şəkillərin siyahısını göstərmək üçün icazə tələb olunur</string>
<string name="nearby_directions">İstiqamətlər</string>
<string name="nearby_wikidata">Vikidata</string>
<string name="nearby_wikipedia">Vikipediya</string>
<string name="nearby_commons">Vikianbar</string>
<string name="about_rate_us">Bizi qiymətləndir</string>
<string name="about_faq">TSS</string>
<string name="user_guide">İstifadəçi təlimatı</string>
<string name="welcome_skip_button">Təlimatı ötür</string>
<string name="no_internet">İnternet əlçatan deyil</string>
<string name="error_notifications">Bildirişləri əldə edərkən xəta baş verdi</string>
<string name="error_review">Şəkli nəzərdən keçirmək üçün gətirilərkən xəta baş verdi. Yenidən cəhd etmək üçün yeniləmə düyməsini basın.</string>
<string name="no_notifications">Heç bir bildiriş tapılmadı</string>
<string name="about_translate">Tərcümə et</string>
<string name="about_translate_title">Dillər</string>
<string name="about_translate_message">Tərcümələri təqdim etmək istədiyiniz dili seçin</string>
<string name="about_translate_proceed">Davam et</string>
<string name="about_translate_cancel">İmtina</string>
<string name="retry">Yenidən cəhd et</string>
<string name="showcase_view_whole_nearby_activity">Bunlar sizə yaxın yerlərdir və onların Vikipediya məqalələrini təsvir etmək üçün şəkillərə ehtiyac duyurlar.\n\n\'BU SAHƏDƏ AXTAR\' düyməsinə klikləməklə, xəritə kilidləyib həmin məkan ətrafında yaxınlıqda axtarış başlaya bilərsiniz.</string>
<string name="showcase_view_needs_photo">Bu yerə şəkil lazımdır.</string>
<string name="showcase_view_has_photo">Bu yerin artıq şəkli var.</string>
<string name="showcase_view_no_longer_exists">Bu yer artıq mövcud deyil.</string>
<string name="no_images_found">Şəkil tapılmadı!</string>
<string name="error_loading_images">Şəkillər yüklənərkən xəta baş verdi.</string>
<string name="image_uploaded_by">%1$s tərəfindən yüklənilib</string>
<string name="block_notification_title">Bloklanıb</string>
<string name="block_notification">Sizə Vikianbarı redaktə etmək qadağan edilib</string>
<string name="app_widget_heading">Günün Şəkli</string>
<string name="menu_search_button">Axtar</string>
<string name="search_commons">Vikianbarda axtar</string>
<string name="title_activity_search">Axtar</string>
<string name="search_recent_header">Son axtarışlar:</string>
<string name="provider_searches">Bu yaxınlarda axtarılanlar</string>
<string name="provider_recent_languages">Son dil sorğuları</string>
<string name="error_loading_categories">Kateqoriyalar yüklənərkən xəta baş verdi.</string>
<string name="error_loading_depictions">Təsvirləri yükləyərkən xəta baş verdi.</string>
<string name="search_tab_title_media">Media</string>
<string name="search_tab_title_categories">Kateqoriyalar</string>
<string name="search_tab_title_depictions">Elementlər</string>
<string name="explore_tab_title_featured">Seçilmiş</string>
<string name="explore_tab_title_mobile">Mobil tətbiq vasitəsilə yüklənib</string>
<string name="explore_tab_title_map">Xəritə</string>
<string name="successful_wikidata_edit">Şəkil Vikidatada %1$s elementinə əlavə edildi</string>
<string name="wikidata_edit_failure">Müvafiq Vikidata obyektini yeniləmək alınmadı!</string>
<string name="menu_set_wallpaper">Divar kağızı kimi təyin et</string>
<string name="wallpaper_set_successfully">Divar kağızı uğurla təyin edildi!</string>
<string name="quiz">Sorğu</string>
<string name="quiz_question_string">Bu şəkli yükləmək olar?</string>
<string name="question">Sual</string>
<string name="result">Nəticə</string>
<string name="quiz_back_button">Silinməyi tələb edilən şəkilləri yükləməyə davam etsəniz, hesabınız blok olunacaq. Sorğunu bitirmək istədiyinizə əminsiniz?</string>
<string name="quiz_alert_message">Yüklədiyiniz şəkillərin %1$s+ ədədi silinib. Silinməyi tələb edilən şəkilləri yükləməyə davam etsəniz, hesabınız blok olunacaq.\n\nTəlimata yenidən baxmaq və sonra hansı növ şəkilləri yükləməli və ya yükləməməli olduğunuzu öyrənməyə kömək etmək üçün testdən keçmək istəyirsiniz?</string>
<string name="selfie_answer">Selfielərin o qədər də məlumatlandırıcı dəyəri yoxdur. Haqqınızda Vikipediya məqaləsi yoxdursa, zəhmət olmasa, şəklinizi yükləməyin.</string>
<string name="taj_mahal_answer">Abidələrin və mənzərələrin şəkillərini əksər ölkələrdə yükləmək olar. Nəzərə alın ki, xaricdəki müvəqqəti incəsənət abidələri tez-tez müəllif hüquqları ilə qorunur və yükləmək düzgün deyil.</string>
<string name="screenshot_answer">Veb saytların skrinşotları törəmə əsərlər hesab edilir və veb-saytdakı müəllif hüququna tabedir. Bunlar müəllifin icazəsindən sonra istifadə edilə bilər. Belə icazə olmadan, onların işi əsasında yaratdığınız hər hansı əsər qanuni olaraq orijinal müəllifə məxsus lisenziyasız nüsxə sayılır.</string>
<string name="blurry_image_answer">Vikianbarın məqsədlərindən biri keyfiyyətli şəkillər toplamaqdır. Ona görə də bulanıq şəkillər yüklənməməlidir. Həmişə yaxşııqlandırma ilə gözəl şəkillər çəkməyə çalışın.</string>
<string name="construction_event_answer">Texnologiya və ya mədəniyyəti təsvir edən şəkillər üçün Vikianbarda həmişə yer var.</string>
<string name="congratulatory_message_quiz">Cavabların %1$s ədədi düzgündür. Təbriklər!</string>
<string name="warning_for_no_answer">Suala cavab vermək üçün iki variantdan birini seçin</string>
<string name="user_not_logged_in">Giriş müddəti bitib. Zəhmət olmasa, yenidən daxil olun.</string>
<string name="quiz_result_share_message">Bunu dostlarınızla paylaşın!</string>
<string name="continue_message">Davam et</string>
<string name="correct">Düzgün Cavab</string>
<string name="wrong">Yanlış Cavab</string>
<string name="quiz_screenshot_question">Bu skrinşotu yükləmək olar?</string>
<string name="share_app_title">Proqramı paylaş</string>
<string name="rotate">Fırlat</string>
<string name="error_fetching_nearby_places">Yaxınlıqdakı yerləri yükləmək mümkün olmadı</string>
<string name="no_pictures_in_this_area">Bu ərazidə şəkillər yoxdur</string>
<string name="no_nearby_places_around">Yaxınlıqda yer tapılmadı</string>
<string name="error_fetching_nearby_monuments">Yaxınlıqdakı abidələri əldə edərkən xəta baş verdi.</string>
<string name="no_recent_searches">Son axtarışlar yoxdur</string>
<string name="delete_recent_searches_dialog">Axtarış tarixçəsini silmək istədiyindən əminsiniz?</string>
<string name="cancel_upload_dialog">Bu yükləməni ləğv etmək istədiyinizə əminsiniz?</string>
<string name="delete_search_dialog">Bu axtarışı silmək istəyirsiniz?</string>
<string name="search_history_deleted">Axtarış tarixçəsi silindi</string>
<string name="nominate_delete">Silinməyə namizəd göstər</string>
<string name="delete">Sil</string>
<string name="Achievements">Nailiyyətlər</string>
<string name="Profile">Profil</string>
<string name="badges">Rozetlər</string>
<string name="statistics">Statistika</string>
<string name="statistics_thanks">Qəbul edilən təşəkkürlər</string>
<string name="statistics_featured">Seçilmiş şəkillər</string>
<string name="statistics_wikidata_edits">\"Yaxınlıqdakı yerlər\" vasitəsilə şəkillər</string>
<string name="level">Səviyyə %d</string>
<string name="profileLevel">%s (Səviyyə %s)</string>
<string name="images_uploaded">Yüklənən şəkillər</string>
<string name="image_reverts">Geri qaytarılan şəkillər</string>
<string name="images_used_by_wiki">İstifadə olunan şəkillər</string>
<string name="achievements_share_message">Nailiyyətlərinizi dostlarınızla paylaşın!</string>
<string name="achievements_info_message">Bu tələbləri yerinə yetirdikcə səviyyəniz yüksəlir. \"Statistika\" bölməsindəki elementlər sizin səviyyənizi nəzərə almır.</string>
<string name="achievements_revert_limit_message">minimum tələb olunur:</string>
<string name="images_uploaded_explanation">İstənilən yükləmə proqramı vasitəsilə Vikianbara yüklədiyiniz şəkillərin sayı</string>
<string name="images_reverted_explanation">Vikianbara yüklədiyiniz və silinməyən şəkillərin faizi</string>
<string name="images_used_explanation">Vikianbara yüklədiyiniz və Vikimedia məqalələrində istifadə olunan şəkillərin sayı</string>
<string name="error_occurred">Xəta baş verdi!</string>
<string name="notifications_channel_name_all">Vikianbar bildirişi</string>
<string name="preference_author_name_toggle">Fərdi müəllif adından istifadə et</string>
<string name="preference_author_name_toggle_summary">Fotoşəkilləri yükləyərkən istifadəçi adınız əvəzinə fərdi müəllif adından istifadə edin</string>
<string name="preference_author_name">Fərdi müəllif adı</string>
<string name="contributions_fragment">Töhfələr</string>
<string name="nearby_fragment">Yaxınlıqdakılar</string>
<string name="notifications">Bildirişlər</string>
<string name="read_notifications">Bildirişlər (oxunmuş)</string>
<string name="display_nearby_notification">Yaxınlıqdakı bildirişini göstər</string>
<string name="display_nearby_notification_summary">Şəkillərə ehtiyacı olan ən yaxın yerlər üçün tətbiqdaxili bildiriş göstərin</string>
<string name="list_sheet">Siyahı</string>
<string name="storage_permission">Yaddaş icazəsi</string>
<string name="write_storage_permission_rationale_for_image_share">Şəkilləri yükləmək üçün cihazınızın xarici yaddaşına giriş icazəsi lazımdır.</string>
<string name="nearby_notification_dismiss_message">Artıq şəkillərə ehtiyacı olan ən yaxın yeri görməyəcəksiniz. Bununla belə, istəyirsinizsə, bu bildirişi Parametrlərdə yenidən aktivləşdirə bilərsiniz.</string>
<string name="send_thank_success_title">Təşəkkür uğurla göndərildi</string>
<string name="send_thank_failure_message">Təşəkkür göndərilə bilmədi %1$s</string>
<string name="send_thank_failure_title">Təşəkkür göndərilir: Xəta</string>

View file

@ -816,4 +816,5 @@
<string name="show_in_nearby">Monstrar in A proximitate</string>
<string name="image_tag_line_created_and_uploaded_by">Create e incargate per: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Create per %1$s e incargate per %2$s</string>
<string name="nominated_for_deletion_btn">Nominate pro deletion</string>
</resources>

View file

@ -772,7 +772,7 @@
<string name="learn_how_to_write_a_useful_caption">Impara come scrivere una didascalia utile</string>
<string name="see_your_achievements">Vedi i tuoi risultati</string>
<string name="edit_image">Modifica Immagine</string>
<string name="edit_location">Modifica Posizione</string>
<string name="edit_location">Modifica posizione</string>
<string name="location_updated">Posizione aggiornata!</string>
<string name="remove_location">Rimuovi posizione</string>
<string name="remove_location_warning_title">Rimuovi avviso di posizione</string>

View file

@ -413,7 +413,7 @@
<string name="deletion_reason_bad_for_my_privacy">Сфатив дека ќе ми ја наруши приватноста</string>
<string name="deletion_reason_no_longer_want_public">Се премислив. Не сакам повеќе да биде видлива</string>
<string name="deletion_reason_not_interesting">За жал, сликава не е соодветна за енциклопедија</string>
<string name="uploaded_by_myself" fuzzy="true">Подигнато од мене %1$s, кое се користи во %2$d статии.</string>
<string name="uploaded_by_myself">Подигнато од мене на %1$s, и се користи во барем {{PLURAL:%2$d|one=една статија|%2$d статии}}.</string>
<string name="no_uploads">Добре дојдовте на Ризницата!\n\nПодигнете ја вашата прва слика или снимка допирајќи го копчето за додавање.</string>
<string name="no_categories_selected">Нема избрано категории</string>
<string name="no_categories_selected_warning_desc">Некатегоризираните слики се слабо употребливи. Дали сигурно сакате да продолжите без да ставите категории?</string>
@ -825,4 +825,5 @@
<string name="show_in_nearby">Прикажи во „Во близина“</string>
<string name="image_tag_line_created_and_uploaded_by">Создал: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Создал %1$s, а подигнал %2$s</string>
<string name="nominated_for_deletion_btn">Предложено за бришење</string>
</resources>

View file

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Aca
* Vlad5250
-->
<resources>
<string name="crash_dialog_title">Commons se srušio</string>
<string name="crash_dialog_title">Aplikacija Ostava prestala je raditi</string>
<string name="crash_dialog_text">Ups. Nešto nije u redu!</string>
<string name="crash_dialog_comment_prompt">Recite nam šta radite, pa podijelite s nama putem e-pošte. Pomoći će nam da ih popravimo!</string>
<string name="crash_dialog_ok_toast">Hvala vam!</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Aca
* Vlad5250
-->
<resources>
@ -93,12 +94,12 @@
<string name="categories_search_text_hint">Pretraži kategorije</string>
<string name="menu_save_categories">Snimi</string>
<string name="refresh_button">Preučitaj</string>
<string name="display_list_button">Popis</string>
<string name="display_list_button">Lista</string>
<string name="contributions_subtitle_zero">(Još uvijek nema postavljenih datoteka)</string>
<string name="categories_not_found">Nema kategorija što odgovoraju %1$s</string>
<string name="categories_skip_explanation">Stavite kategorije slikama kako biste olakšali korisnicima njihovo pronalaženje na Ostavi.\n\nDa biste stavili kategoriju, počnite sa pisanjem njenog imena.</string>
<string name="categories_activity_title">Kategorije</string>
<string name="title_activity_settings">Podešavanja</string>
<string name="title_activity_settings">Postavke</string>
<string name="title_activity_signup">Registracija</string>
<string name="title_activity_featured_images">Izabrane slike</string>
<string name="title_activity_category_details">Kategorija</string>
@ -125,7 +126,7 @@
<string name="license_name_cc_by_four"> Autorstvo 4.0</string>
<string name="license_name_cc_by_sa"> Autorstvo-Dijeliti pod istim uslovima 3.0</string>
<string name="license_name_cc_by"> Autorstvo 3.0</string>
<string name="tutorial_1_text">Ostava je udomljač najvećine slika što se koriste na Wikipediji.</string>
<string name="tutorial_1_text">Wikimedijina ostava skladišti većinu slika koje se upotrebljavaju na Wikipediji.</string>
<string name="tutorial_1_subtext">Vaše slike pomažu u obrazovanju ljudi širom svijeta!</string>
<string name="tutorial_2_text">Postavljajte slike koje su u potpunosti Vaše djelo:</string>
<string name="tutorial_2_subtext_1">Objekti iz prirode (cvijeće, životinje, planine)</string>
@ -188,7 +189,7 @@
<string name="navigation_item_upload">Postavi</string>
<string name="navigation_item_nearby">U blizini</string>
<string name="navigation_item_about">O privitku</string>
<string name="navigation_item_settings">Podešavanja</string>
<string name="navigation_item_settings">Postavke</string>
<string name="navigation_item_feedback">Povratna informacija</string>
<string name="navigation_item_logout">Odjava</string>
<string name="navigation_item_info">Uputstva</string>
@ -214,7 +215,7 @@
<string name="skip_login_message" fuzzy="true">U budućnosti ćete se morati prijaviti kako biste postavili slike.</string>
<string name="login_alert_message">Prijavite se da biste koristili ovu funkciju</string>
<string name="nearby_location_not_available">„U blizini“ možda ne radi kako treba. Lokacija nije dostupna.</string>
<string name="location_permission_rationale_nearby">Potrebna je dozvola za popis liste lokacija u blizini</string>
<string name="location_permission_rationale_nearby">Potrebna je dozvola za prikaz liste lokacija u blizini</string>
<string name="nearby_directions">Upute</string>
<string name="nearby_wikidata">Wikidata</string>
<string name="nearby_wikipedia">Wikipedia</string>
@ -226,7 +227,7 @@
<string name="no_notifications">Nema obavijesti</string>
<string name="about_translate">Prevedi</string>
<string name="about_translate_title">Jezici</string>
<string name="about_translate_message">Odaberite za koji jezik bi želeli da pravite prijevode</string>
<string name="about_translate_message">Izaberite jezik na koji biste željeli prevoditi</string>
<string name="about_translate_proceed">Nastavi</string>
<string name="about_translate_cancel">Otkaži</string>
<string name="retry">Pokušaj ponovo</string>
@ -261,6 +262,6 @@
<string name="reset">Poništi</string>
<string name="location_message">Podaci o lokaciji pomažu Wikiurednicima da pronađu vašu sliku, čineći je mnogo korisnijom.\nVaše nedavne postavljene slike nemaju lokaciju.\nPredlažemo da uključite lokaciju u postavkama priloga kamere.\nHvala vam na učitavanju!</string>
<string name="explore_map_details">Detalji</string>
<string name="api_level">Razina priložnika</string>
<string name="api_level">Nivo API-ja</string>
<string name="android_version">Android verzija</string>
</resources>

View file

@ -132,6 +132,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>
@ -142,6 +144,7 @@
<string name="login_failed_throttled">Надто багато невдалих спроб. Будь ласка, спробуйте знову через кілька хвилин.</string>
<string name="login_failed_blocked">Вибачте, цього користувача було заблоковано на Вікісховищі</string>
<string name="login_failed_2fa_needed">Ви повинні надати код двофакторної автентифікації.</string>
<string name="login_failed_email_auth_needed">Код підтвердження входу надіслано на вашу адресу електронної пошти. Будь ласка, введіть код для входу.</string>
<string name="login_failed_generic">Не вдалося увійти</string>
<string name="share_upload_button">Завантажити</string>
<string name="multiple_share_base_title">Назвіть цю серію</string>
@ -150,6 +153,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>
@ -246,6 +250,7 @@
<string name="become_a_tester_title">Станьте бета-тестером</string>
<string name="become_a_tester_description">Підпишіться на наш бета-канал на Google Play і отримайте ранній доступ до нових функцій та виправлень баґів</string>
<string name="_2fa_code">Код 2FA</string>
<string name="email_auth_code">Код підтвердження електронної пошти</string>
<string name="logout_verification">Ви справді хочете вийти із системи?</string>
<string name="mediaimage_failed">Помилка медіазображення</string>
<string name="no_subcategory_found">Підкатегорій не знайдено</string>
@ -306,6 +311,7 @@
<string name="copy_wikicode">Скопіювати вікі-текст у буфер обміну</string>
<string name="wikicode_copied">Вікі-текст скопійовано у буфер обміну</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>
@ -389,11 +395,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>
@ -425,6 +433,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>
@ -435,7 +444,7 @@
<string name="deletion_reason_bad_for_my_privacy">Мені стало зрозуміло, що це шкодить моїй приватності</string>
<string name="deletion_reason_no_longer_want_public">Моя думка змінилась, я не хочу, щоб це було доступно публічно</string>
<string name="deletion_reason_not_interesting">Перепрошую, це зображення нецікаве для енциклопедії</string>
<string name="uploaded_by_myself" fuzzy="true">Завантажено мною на сайт «%1$s» та використано у {{PLURAL:%2$d|one=одній статті|%2$d статтях}}.</string>
<string name="uploaded_by_myself">Завантажено мною на сайт «%1$s» та використано у принаймні {{PLURAL:%2$d|one=одній статті|%2$d статтях}}.</string>
<string name="no_uploads">Ласкаво просимо до Вікісховища!\n\nЗавантажте Ваш перший медіафайл, натиснувши кнопку додавання.</string>
<string name="no_categories_selected">Жодної категорії не вибрано</string>
<string name="no_categories_selected_warning_desc">Зображення без категорій рідко використовуються. Ви впевнені, що хочете продовжити без вказаних категорій?</string>
@ -506,6 +515,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>
@ -725,7 +735,7 @@
<string name="read_phone_state_permission_message">Для належної роботи мапи поблизу мають відображати стан PHONE STATE</string>
<string name="contributions_of_user">Внесок користувача: %s</string>
<string name="achievements_of_user">Досягнення користувача: %s</string>
<string name="menu_view_user_page" fuzzy="true">Переглянути сторінку користувача</string>
<string name="menu_view_user_page">Переглянути профіль користувача</string>
<string name="edit_depictions">Редагувати описи</string>
<string name="edit_categories">Редагувати категорії</string>
<string name="advanced_options">Розширені параметри</string>
@ -810,8 +820,45 @@
<string name="nearby_wikitalk">Повідомити у Вікідані про проблему з цим елементом</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_wikidata">«%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">Ваші відгуки розміщуються на ось цій вікісторінці: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile app/Feedback&lt;/a&gt;</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="custom_selector_delete_folder">Вилучити папку</string>
<string name="custom_selector_confirm_deletion_title">Підтвердити вилучення</string>
<string name="custom_selector_confirm_deletion_message">Ви впевнені, що бажаєте вилучити папку %1$s, у якій міститься %2$d елемент(ів)?</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">Інші вікі</string>
<string name="file_usages_container_heading">Використання файлу</string>
<string name="account">Обліковий запис</string>
<string name="vanish_account">Знищити обліковий запис</string>
<string name="account_vanish_request_confirm_title">Попередження про знищення облікового запису</string>
<string name="account_vanish_request_confirm">Зникнення є &lt;b&gt;останнім заходом&lt;/b&gt;, і &lt;b&gt;його слід використовувати лише тоді, коли ви хочете назавжди припинити редагування&lt;/b&gt;, а також щоб приховати якомога більше своїх минулих зв\'язків.&lt;br/&gt;&lt;br/&gt;Вилучення облікового запису у Вікісховищі робиться шляхом зміни імені вашого облікового запису, щоб інші не могли розпізнати ваші внески; це називають зникненням облікового запису. &lt;b&gt;Зникнення не гарантує повної анонімності і не вилучає внесок у проєкти&lt;/b&gt;.</string>
<string name="caption">Підпис</string>
<string name="caption_copied_to_clipboard">Підпис скопійовано до буферу обміну</string>
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Вітаємо, всі зображення в цьому альбомі або завантажені, або позначені як не для завантаження.</string>
<string name="show_in_explore">Показати в розділі «Дослідити»</string>
<string name="show_in_nearby">Показати в розділі «Поблизу»</string>
<string name="image_tag_line_created_and_uploaded_by">Створено та завантажено: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Створено %1$s та завантажено %2$s</string>
<string name="nominated_for_deletion_btn">Номіновано на вилучення</string>
</resources>

View file

@ -470,7 +470,7 @@
<string name="deletion_reason_bad_for_my_privacy">我意识到这对我的隐私不利</string>
<string name="deletion_reason_no_longer_want_public">我改变了主意,我不想再让公众看到它了</string>
<string name="deletion_reason_not_interesting">对不起,这幅图对百科全书没什么意思</string>
<string name="uploaded_by_myself" fuzzy="true">由我自己上传在%1$s使用于%2$d个条目。</string>
<string name="uploaded_by_myself">由我自己上传在%1$s使用于至少%2$d个条目。</string>
<string name="no_uploads">欢迎使用共享资源!\n\n通过点击添加按钮以上传您的首个媒体。</string>
<string name="no_categories_selected">未提交分类</string>
<string name="no_categories_selected_warning_desc">不带分类的图片很难有机会被利用到,您确定您要不选择分类来继续吗?</string>
@ -880,4 +880,5 @@
<string name="show_in_nearby">显示在附近</string>
<string name="image_tag_line_created_and_uploaded_by">创建并上传者: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">由%1$s创建并由%2$s上传</string>
<string name="nominated_for_deletion_btn">已提名删除</string>
</resources>

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons
import fr.free.nrw.commons.utils.getWikiLovesMonumentsYear
import org.junit.Test
import org.junit.jupiter.api.Assertions
import java.util.Calendar
@ -9,20 +10,20 @@ class UtilsTest {
fun wikiLovesMonumentsYearBeforeSeptember() {
val cal = Calendar.getInstance()
cal.set(2022, Calendar.FEBRUARY, 1)
Assertions.assertEquals(2021, Utils.getWikiLovesMonumentsYear(cal))
Assertions.assertEquals(2021, getWikiLovesMonumentsYear(cal))
}
@Test
fun wikiLovesMonumentsYearInSeptember() {
val cal = Calendar.getInstance()
cal.set(2022, Calendar.SEPTEMBER, 1)
Assertions.assertEquals(2022, Utils.getWikiLovesMonumentsYear(cal))
Assertions.assertEquals(2022, getWikiLovesMonumentsYear(cal))
}
@Test
fun wikiLovesMonumentsYearAfterSeptember() {
val cal = Calendar.getInstance()
cal.set(2022, Calendar.DECEMBER, 1)
Assertions.assertEquals(2022, Utils.getWikiLovesMonumentsYear(cal))
Assertions.assertEquals(2022, getWikiLovesMonumentsYear(cal))
}
}

View file

@ -248,13 +248,6 @@ class ContributionsFragmentUnitTests {
fragment.onDestroyView()
}
@Test
@Throws(Exception::class)
fun testShowMessage() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.showMessage("")
}
@Test
@Throws(Exception::class)
fun testShowCampaigns() {

View file

@ -1,11 +1,12 @@
package fr.free.nrw.commons.upload
import com.nhaarman.mockitokotlin2.verify
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.utils.UnderlineUtils
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.upload.license.MediaLicenseContract
import fr.free.nrw.commons.upload.license.MediaLicensePresenter
import fr.free.nrw.commons.utils.toLicenseName
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -25,7 +26,7 @@ import org.robolectric.RobolectricTestRunner
*/
@RunWith(RobolectricTestRunner::class)
@PrepareForTest(Utils::class)
@PrepareForTest(UnderlineUtils::class)
class MediaLicensePresenterTest {
@Mock
internal lateinit var repository: UploadRepository
@ -39,7 +40,7 @@ class MediaLicensePresenterTest {
@InjectMocks
lateinit var mediaLicensePresenter: MediaLicensePresenter
private lateinit var mockedUtil: MockedStatic<Utils>
private lateinit var mockedUtil: MockedStatic<UnderlineUtils>
/**
* initial setup test environemnt
@ -49,8 +50,7 @@ class MediaLicensePresenterTest {
fun setUp() {
MockitoAnnotations.openMocks(this)
mediaLicensePresenter.onAttachView(view)
mockedUtil = Mockito.mockStatic(Utils::class.java)
`when`(Utils.licenseNameFor(ArgumentMatchers.anyString())).thenReturn(1)
mockedUtil = Mockito.mockStatic(UnderlineUtils::class.java)
}
@After

View file

@ -1,6 +1,5 @@
package fr.free.nrw.commons.utils
import fr.free.nrw.commons.Utils.fixExtension
import org.junit.Assert.assertEquals
import org.junit.Test