mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-11-04 00:33:55 +01:00 
			
		
		
		
	Merge c549144f11 into 78d29bcf20
				
					
				
			This commit is contained in:
		
						commit
						b3088be1a7
					
				
					 10 changed files with 336 additions and 10 deletions
				
			
		| 
						 | 
					@ -484,19 +484,65 @@ class OkHttpJsonApiClient @Inject constructor(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Throws(IOException::class)
 | 
					    @Throws(IOException::class)
 | 
				
			||||||
    fun getPlaces(
 | 
					    fun getPlaces(
 | 
				
			||||||
        placeList: List<Place>, language: String
 | 
					        placeList: List<Place>, primaryLanguage: String, secondaryLanguages: String
 | 
				
			||||||
    ): List<Place>? {
 | 
					    ): List<Place>? {
 | 
				
			||||||
        val wikidataQuery = FileUtils.readFromResource("/queries/query_for_item.rq")
 | 
					        val wikidataQuery = FileUtils.readFromResource("/queries/query_for_item.rq")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Split the secondary languages string into an array to use in fallback queries
 | 
				
			||||||
 | 
					        val secondaryLanguagesArray = secondaryLanguages.split(",\\s*".toRegex())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Prepare the Wikidata entity IDs (QIDs) for each place in the list
 | 
				
			||||||
        var qids = ""
 | 
					        var qids = ""
 | 
				
			||||||
        for (place in placeList) {
 | 
					        for (place in placeList) {
 | 
				
			||||||
            qids += """
 | 
					            qids += "\nwd:${place.wikiDataEntityId}"
 | 
				
			||||||
${"wd:" + place.wikiDataEntityId}"""
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Build fallback descriptions for secondary languages in case the primary language is unavailable
 | 
				
			||||||
 | 
					        val fallBackDescription = StringBuilder()
 | 
				
			||||||
 | 
					        secondaryLanguagesArray.forEachIndexed { index, lang ->
 | 
				
			||||||
 | 
					            fallBackDescription.append("OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(". FILTER (lang(?itemDescriptionPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(") = \"")
 | 
				
			||||||
 | 
					                .append(lang)
 | 
				
			||||||
 | 
					                .append("\")}\n")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Build fallback labels for secondary languages
 | 
				
			||||||
 | 
					        val fallbackLabel = StringBuilder()
 | 
				
			||||||
 | 
					        secondaryLanguagesArray.forEachIndexed { index, lang ->
 | 
				
			||||||
 | 
					            fallbackLabel.append("OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(". FILTER (lang(?itemLabelPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(") = \"")
 | 
				
			||||||
 | 
					                .append(lang)
 | 
				
			||||||
 | 
					                .append("\")}\n")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Build fallback class labels for secondary languages
 | 
				
			||||||
 | 
					        val fallbackClassLabel = StringBuilder()
 | 
				
			||||||
 | 
					        secondaryLanguagesArray.forEachIndexed { index, lang ->
 | 
				
			||||||
 | 
					            fallbackClassLabel.append("OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(". FILTER (lang(?classLabelPreferredLanguage_")
 | 
				
			||||||
 | 
					                .append(index + 1)
 | 
				
			||||||
 | 
					                .append(") = \"")
 | 
				
			||||||
 | 
					                .append(lang)
 | 
				
			||||||
 | 
					                .append("\")}\n")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Replace placeholders in the query with actual data: QIDs, language codes, and fallback options
 | 
				
			||||||
        val query = wikidataQuery
 | 
					        val query = wikidataQuery
 | 
				
			||||||
            .replace("\${ENTITY}", qids)
 | 
					            .replace("\${ENTITY}", qids)
 | 
				
			||||||
            .replace("\${LANG}", language)
 | 
					            .replace("\${LANG}", primaryLanguage)
 | 
				
			||||||
        val urlBuilder: HttpUrl.Builder = sparqlQueryUrl.toHttpUrlOrNull()!!
 | 
					            .replace("\${SECONDARYDESCRIPTION}", fallBackDescription.toString())
 | 
				
			||||||
            .newBuilder()
 | 
					            .replace("\${SECONDARYLABEL}", fallbackLabel.toString())
 | 
				
			||||||
 | 
					            .replace("\${SECONDARYCLASSLABEL}", fallbackClassLabel.toString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Build the URL for the SparQL query with the formatted query string
 | 
				
			||||||
 | 
					        val urlBuilder = sparqlQueryUrl.toHttpUrlOrNull()!!.newBuilder()
 | 
				
			||||||
            .addQueryParameter("query", query)
 | 
					            .addQueryParameter("query", query)
 | 
				
			||||||
            .addQueryParameter("format", "json")
 | 
					            .addQueryParameter("format", "json")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -514,11 +560,12 @@ ${"wd:" + place.wikiDataEntityId}"""
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return places
 | 
					                return places
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                throw IOException("Unexpected response code: " + response.code)
 | 
					                throw IOException("Unexpected response code: ${response.code}")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Throws(Exception::class)
 | 
					    @Throws(Exception::class)
 | 
				
			||||||
    fun getPlacesAsKML(leftLatLng: LatLng, rightLatLng: LatLng): String? {
 | 
					    fun getPlacesAsKML(leftLatLng: LatLng, rightLatLng: LatLng): String? {
 | 
				
			||||||
        var kmlString = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
					        var kmlString = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,9 @@ import androidx.annotation.MainThread;
 | 
				
			||||||
import androidx.annotation.Nullable;
 | 
					import androidx.annotation.Nullable;
 | 
				
			||||||
import fr.free.nrw.commons.BaseMarker;
 | 
					import fr.free.nrw.commons.BaseMarker;
 | 
				
			||||||
import fr.free.nrw.commons.MapController;
 | 
					import fr.free.nrw.commons.MapController;
 | 
				
			||||||
 | 
					import fr.free.nrw.commons.kvstore.JsonKvStore;
 | 
				
			||||||
import fr.free.nrw.commons.location.LatLng;
 | 
					import fr.free.nrw.commons.location.LatLng;
 | 
				
			||||||
 | 
					import fr.free.nrw.commons.settings.Prefs;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
| 
						 | 
					@ -16,6 +18,7 @@ import java.util.ListIterator;
 | 
				
			||||||
import java.util.Locale;
 | 
					import java.util.Locale;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import javax.inject.Inject;
 | 
					import javax.inject.Inject;
 | 
				
			||||||
 | 
					import javax.inject.Named;
 | 
				
			||||||
import timber.log.Timber;
 | 
					import timber.log.Timber;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class NearbyController extends MapController {
 | 
					public class NearbyController extends MapController {
 | 
				
			||||||
| 
						 | 
					@ -34,6 +37,10 @@ public class NearbyController extends MapController {
 | 
				
			||||||
        this.nearbyPlaces = nearbyPlaces;
 | 
					        this.nearbyPlaces = nearbyPlaces;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Inject
 | 
				
			||||||
 | 
					    @Named("default_preferences")
 | 
				
			||||||
 | 
					    JsonKvStore defaultKvStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Prepares Place list to make their distance information update later.
 | 
					     * Prepares Place list to make their distance information update later.
 | 
				
			||||||
| 
						 | 
					@ -139,7 +146,9 @@ public class NearbyController extends MapController {
 | 
				
			||||||
     * @throws Exception If an error occurs during the retrieval process.
 | 
					     * @throws Exception If an error occurs during the retrieval process.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public List<Place> getPlaces(List<Place> placeList) throws Exception {
 | 
					    public List<Place> getPlaces(List<Place> placeList) throws Exception {
 | 
				
			||||||
        return nearbyPlaces.getPlaces(placeList, Locale.getDefault().getLanguage());
 | 
					        String secondaryLanguages = defaultKvStore.getString(Prefs.SECONDARY_LANGUAGES, "");
 | 
				
			||||||
 | 
					        String primaryLanguage = defaultKvStore.getString(Prefs.DESCRIPTION_LANGUAGE, "");
 | 
				
			||||||
 | 
					        return nearbyPlaces.getPlaces(placeList, primaryLanguage, secondaryLanguages);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static LatLng calculateNorthEast(double latitude, double longitude, double distance) {
 | 
					    public static LatLng calculateNorthEast(double latitude, double longitude, double distance) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,9 +191,9 @@ public class NearbyPlaces {
 | 
				
			||||||
     * @throws Exception If an error occurs during the retrieval process.
 | 
					     * @throws Exception If an error occurs during the retrieval process.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public List<Place> getPlaces(final List<Place> placeList,
 | 
					    public List<Place> getPlaces(final List<Place> placeList,
 | 
				
			||||||
        final String lang) throws Exception {
 | 
					        final String lang, final String lang2) throws Exception {
 | 
				
			||||||
        return okHttpJsonApiClient
 | 
					        return okHttpJsonApiClient
 | 
				
			||||||
            .getPlaces(placeList, lang);
 | 
					            .getPlaces(placeList, lang, lang2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					package fr.free.nrw.commons.recentlanguages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.view.LayoutInflater
 | 
				
			||||||
 | 
					import android.view.View
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import android.widget.ArrayAdapter
 | 
				
			||||||
 | 
					import fr.free.nrw.commons.R
 | 
				
			||||||
 | 
					import fr.free.nrw.commons.databinding.RowItemLanguagesSpinnerBinding
 | 
				
			||||||
 | 
					import fr.free.nrw.commons.utils.LangCodeUtils
 | 
				
			||||||
 | 
					import org.apache.commons.lang3.StringUtils
 | 
				
			||||||
 | 
					import java.util.HashMap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Array adapter for saved languages
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class SavedLanguagesAdapter constructor(
 | 
				
			||||||
 | 
					    context: Context,
 | 
				
			||||||
 | 
					    var savedLanguages: List<Language>,  // List of saved languages
 | 
				
			||||||
 | 
					    private val selectedLanguages: HashMap<*, String>,  // Selected languages map
 | 
				
			||||||
 | 
					) : ArrayAdapter<String?>(context, R.layout.row_item_languages_spinner) {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Selected language code in SavedLanguagesAdapter
 | 
				
			||||||
 | 
					     * Used for marking selected ones
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var selectedLangCode = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isEnabled(position: Int) =
 | 
				
			||||||
 | 
					        savedLanguages[position].languageCode.let {
 | 
				
			||||||
 | 
					            it.isNotEmpty() && !selectedLanguages.containsValue(it) && it != selectedLangCode
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getCount() = savedLanguages.size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getView(
 | 
				
			||||||
 | 
					        position: Int,
 | 
				
			||||||
 | 
					        convertView: View?,
 | 
				
			||||||
 | 
					        parent: ViewGroup,
 | 
				
			||||||
 | 
					    ): View {
 | 
				
			||||||
 | 
					        val binding: RowItemLanguagesSpinnerBinding
 | 
				
			||||||
 | 
					        var rowView = convertView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (rowView == null) {
 | 
				
			||||||
 | 
					            val layoutInflater =
 | 
				
			||||||
 | 
					                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
 | 
				
			||||||
 | 
					            binding = RowItemLanguagesSpinnerBinding.inflate(layoutInflater, parent, false)
 | 
				
			||||||
 | 
					            rowView = binding.root
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            binding = RowItemLanguagesSpinnerBinding.bind(rowView)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val languageCode = savedLanguages[position].languageCode
 | 
				
			||||||
 | 
					        val languageName = savedLanguages[position].languageName
 | 
				
			||||||
 | 
					        binding.tvLanguage.let {
 | 
				
			||||||
 | 
					            it.isEnabled = isEnabled(position)
 | 
				
			||||||
 | 
					            if (languageCode.isEmpty()) {
 | 
				
			||||||
 | 
					                it.text = StringUtils.capitalize(languageName)
 | 
				
			||||||
 | 
					                it.textAlignment = View.TEXT_ALIGNMENT_CENTER
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                it.text =
 | 
				
			||||||
 | 
					                    "${StringUtils.capitalize(languageName)}" +
 | 
				
			||||||
 | 
					                            " [${LangCodeUtils.fixLanguageCode(languageCode)}]"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return rowView
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Provides code of a language from saved languages for a specific position
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun getLanguageCode(position: Int): String = savedLanguages[position].languageCode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Provides name of a language from saved languages for a specific position
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun getLanguageName(position: Int): String = savedLanguages[position].languageName
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ object Prefs {
 | 
				
			||||||
    const val MANAGED_EXIF_TAGS = "managed_exif_tags"
 | 
					    const val MANAGED_EXIF_TAGS = "managed_exif_tags"
 | 
				
			||||||
    const val VANISHED_ACCOUNT = "vanishAccount"
 | 
					    const val VANISHED_ACCOUNT = "vanishAccount"
 | 
				
			||||||
    const val DESCRIPTION_LANGUAGE = "languageDescription"
 | 
					    const val DESCRIPTION_LANGUAGE = "languageDescription"
 | 
				
			||||||
 | 
					    const val SECONDARY_LANGUAGES = "secondaryLanguages"
 | 
				
			||||||
    const val APP_UI_LANGUAGE = "appUiLanguage"
 | 
					    const val APP_UI_LANGUAGE = "appUiLanguage"
 | 
				
			||||||
    const val KEY_THEME_VALUE = "appThemePref"
 | 
					    const val KEY_THEME_VALUE = "appThemePref"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ import android.widget.Button
 | 
				
			||||||
import android.widget.EditText
 | 
					import android.widget.EditText
 | 
				
			||||||
import android.widget.ListView
 | 
					import android.widget.ListView
 | 
				
			||||||
import android.widget.TextView
 | 
					import android.widget.TextView
 | 
				
			||||||
 | 
					import android.widget.Toast
 | 
				
			||||||
import androidx.activity.result.ActivityResultLauncher
 | 
					import androidx.activity.result.ActivityResultLauncher
 | 
				
			||||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
 | 
					import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
 | 
				
			||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 | 
					import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 | 
				
			||||||
| 
						 | 
					@ -78,6 +79,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
    private var vanishAccountPreference: Preference? = null
 | 
					    private var vanishAccountPreference: Preference? = null
 | 
				
			||||||
    private var themeListPreference: ListPreference? = null
 | 
					    private var themeListPreference: ListPreference? = null
 | 
				
			||||||
    private var descriptionLanguageListPreference: Preference? = null
 | 
					    private var descriptionLanguageListPreference: Preference? = null
 | 
				
			||||||
 | 
					    private var descriptionSecondaryLanguagesListPreference: Preference? = null
 | 
				
			||||||
    private var appUiLanguageListPreference: Preference? = null
 | 
					    private var appUiLanguageListPreference: Preference? = null
 | 
				
			||||||
    private var showDeletionButtonPreference: Preference? = null
 | 
					    private var showDeletionButtonPreference: Preference? = null
 | 
				
			||||||
    private var keyLanguageListPreference: String? = null
 | 
					    private var keyLanguageListPreference: String? = null
 | 
				
			||||||
| 
						 | 
					@ -229,6 +231,12 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        descriptionSecondaryLanguagesListPreference = findPreference("descriptionSecondaryLanguagesPref")
 | 
				
			||||||
 | 
					        descriptionSecondaryLanguagesListPreference?.setOnPreferenceClickListener {
 | 
				
			||||||
 | 
					            prepareSecondaryLanguagesDialog()
 | 
				
			||||||
 | 
					            true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        showDeletionButtonPreference = findPreference("displayDeletionButton")
 | 
					        showDeletionButtonPreference = findPreference("displayDeletionButton")
 | 
				
			||||||
        showDeletionButtonPreference?.setOnPreferenceChangeListener { _, newValue ->
 | 
					        showDeletionButtonPreference?.setOnPreferenceChangeListener { _, newValue ->
 | 
				
			||||||
            val isEnabled = newValue as Boolean
 | 
					            val isEnabled = newValue as Boolean
 | 
				
			||||||
| 
						 | 
					@ -324,6 +332,91 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun prepareSecondaryLanguagesDialog() {
 | 
				
			||||||
 | 
					        val languageCode = getCurrentLanguageCode("descriptionSecondaryLanguagesPref")
 | 
				
			||||||
 | 
					        val defaultCode = getCurrentLanguageCode("descriptionDefaultLanguagePref")
 | 
				
			||||||
 | 
					        val selectedLanguages = hashMapOf<Int, String>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var deflocale = Locale.getDefault()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (defaultCode != null){
 | 
				
			||||||
 | 
					            deflocale = createLocale(defaultCode)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        languageCode?.let {
 | 
				
			||||||
 | 
					            selectedLanguages[0] = deflocale.language
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val savedLanguages = arrayListOf<Language>()
 | 
				
			||||||
 | 
					        languageCode?.split(",\\s*".toRegex())?.forEach { code ->
 | 
				
			||||||
 | 
					            if (code != deflocale.language) {
 | 
				
			||||||
 | 
					                val locale = Locale(code)
 | 
				
			||||||
 | 
					                savedLanguages.add(Language(locale.displayLanguage, code))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val dialog = Dialog(requireActivity())
 | 
				
			||||||
 | 
					        dialog.setContentView(R.layout.dialog_select_secondary_languages)
 | 
				
			||||||
 | 
					        dialog.setCanceledOnTouchOutside(true)
 | 
				
			||||||
 | 
					        dialog.window?.setLayout(
 | 
				
			||||||
 | 
					            (resources.displayMetrics.widthPixels * 0.90).toInt(),
 | 
				
			||||||
 | 
					            (resources.displayMetrics.heightPixels * 0.90).toInt()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        dialog.show()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val editText: EditText = dialog.findViewById(R.id.search_language)
 | 
				
			||||||
 | 
					        val listView: ListView = dialog.findViewById(R.id.language_list)
 | 
				
			||||||
 | 
					        val savedLanguageListView: ListView = dialog.findViewById(R.id.language_history_list)
 | 
				
			||||||
 | 
					        val separator: View = dialog.findViewById(R.id.separator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        updateSavedLanguages(savedLanguageListView, savedLanguages, selectedLanguages)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val languagesAdapter = LanguagesAdapter(requireActivity(), selectedLanguages)
 | 
				
			||||||
 | 
					        listView.adapter = languagesAdapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        editText.addTextChangedListener(object : TextWatcher {
 | 
				
			||||||
 | 
					            override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) {}
 | 
				
			||||||
 | 
					            override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
 | 
				
			||||||
 | 
					                languagesAdapter.filter.filter(charSequence)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            override fun afterTextChanged(editable: Editable?) {}
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        savedLanguageListView.setOnItemClickListener { _, _, position, _ ->
 | 
				
			||||||
 | 
					            savedLanguages.removeAt(position)
 | 
				
			||||||
 | 
					            updateSavedLanguages(savedLanguageListView, savedLanguages, selectedLanguages)
 | 
				
			||||||
 | 
					            saveLanguageValue(
 | 
				
			||||||
 | 
					                savedLanguages.joinToString(", ") { it.languageCode },
 | 
				
			||||||
 | 
					                "descriptionSecondaryLanguagesPref"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        listView.setOnItemClickListener { _, _, position, _ ->
 | 
				
			||||||
 | 
					            val selectedLanguageCode = languagesAdapter.getLanguageCode(position)
 | 
				
			||||||
 | 
					            val selectedLanguageName = languagesAdapter.getLanguageName(position)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (savedLanguages.any { it.languageCode == selectedLanguageCode }) {
 | 
				
			||||||
 | 
					                Toast.makeText(requireActivity(), "Language already selected", Toast.LENGTH_SHORT).show()
 | 
				
			||||||
 | 
					                return@setOnItemClickListener
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            savedLanguages.add(Language(selectedLanguageName, selectedLanguageCode))
 | 
				
			||||||
 | 
					            updateSavedLanguages(savedLanguageListView, savedLanguages, selectedLanguages)
 | 
				
			||||||
 | 
					            saveLanguageValue(
 | 
				
			||||||
 | 
					                savedLanguages.joinToString(", ") { it.languageCode },
 | 
				
			||||||
 | 
					                "descriptionSecondaryLanguagesPref"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dialog.setOnDismissListener {
 | 
				
			||||||
 | 
					            saveLanguageValue(
 | 
				
			||||||
 | 
					                savedLanguages.joinToString(", ") { it.languageCode },
 | 
				
			||||||
 | 
					                "descriptionSecondaryLanguagesPref"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Prepare and Show language selection dialog box
 | 
					     * Prepare and Show language selection dialog box
 | 
				
			||||||
     * Uses previously saved language if there is any, if not uses phone locale as initial language.
 | 
					     * Uses previously saved language if there is any, if not uses phone locale as initial language.
 | 
				
			||||||
| 
						 | 
					@ -531,6 +624,16 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Helper function to update saved languages
 | 
				
			||||||
 | 
					    private fun updateSavedLanguages(
 | 
				
			||||||
 | 
					        savedLanguageListView: ListView,
 | 
				
			||||||
 | 
					        savedLanguages: List<Language>,
 | 
				
			||||||
 | 
					        selectedLanguages: HashMap<Int, String>
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        val savedLanguagesAdapter = RecentLanguagesAdapter(requireActivity(), savedLanguages, selectedLanguages)
 | 
				
			||||||
 | 
					        savedLanguageListView.adapter = savedLanguagesAdapter
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Save userSelected language in List Preference
 | 
					     * Save userSelected language in List Preference
 | 
				
			||||||
     * @param userSelectedValue
 | 
					     * @param userSelectedValue
 | 
				
			||||||
| 
						 | 
					@ -540,6 +643,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
        when (preferenceKey) {
 | 
					        when (preferenceKey) {
 | 
				
			||||||
            "appUiDefaultLanguagePref" -> defaultKvStore.putString(Prefs.APP_UI_LANGUAGE, userSelectedValue)
 | 
					            "appUiDefaultLanguagePref" -> defaultKvStore.putString(Prefs.APP_UI_LANGUAGE, userSelectedValue)
 | 
				
			||||||
            "descriptionDefaultLanguagePref" -> defaultKvStore.putString(Prefs.DESCRIPTION_LANGUAGE, userSelectedValue)
 | 
					            "descriptionDefaultLanguagePref" -> defaultKvStore.putString(Prefs.DESCRIPTION_LANGUAGE, userSelectedValue)
 | 
				
			||||||
 | 
					            "descriptionSecondaryLanguagesPref" -> defaultKvStore.putString(Prefs.SECONDARY_LANGUAGES, userSelectedValue)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -556,6 +660,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
 | 
				
			||||||
            "descriptionDefaultLanguagePref" -> defaultKvStore.getString(
 | 
					            "descriptionDefaultLanguagePref" -> defaultKvStore.getString(
 | 
				
			||||||
                Prefs.DESCRIPTION_LANGUAGE, ""
 | 
					                Prefs.DESCRIPTION_LANGUAGE, ""
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					            "descriptionSecondaryLanguagesPref" -> defaultKvStore.getString(
 | 
				
			||||||
 | 
					                Prefs.SECONDARY_LANGUAGES, ""
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            else -> null
 | 
					            else -> null
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,74 @@
 | 
				
			||||||
 | 
					<androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
 | 
					  xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					  xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
				
			||||||
 | 
					  android:layout_width="match_parent"
 | 
				
			||||||
 | 
					  android:layout_height="match_parent">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <EditText
 | 
				
			||||||
 | 
					    android:id="@+id/search_language"
 | 
				
			||||||
 | 
					    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					    android:layout_marginStart="8dp"
 | 
				
			||||||
 | 
					    android:layout_marginTop="8dp"
 | 
				
			||||||
 | 
					    android:layout_marginEnd="8dp"
 | 
				
			||||||
 | 
					    android:hint="Type Language Name"
 | 
				
			||||||
 | 
					    android:padding="12dp"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toTopOf="parent" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <TextView
 | 
				
			||||||
 | 
					    android:id="@+id/language_order_preference"
 | 
				
			||||||
 | 
					    android:layout_width="0dp"
 | 
				
			||||||
 | 
					    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					    android:layout_marginStart="8dp"
 | 
				
			||||||
 | 
					    android:layout_marginEnd="8dp"
 | 
				
			||||||
 | 
					    android:text="Language order preference"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toBottomOf="@id/search_language" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ListView
 | 
				
			||||||
 | 
					    android:id="@+id/language_history_list"
 | 
				
			||||||
 | 
					    android:layout_width="0dp"
 | 
				
			||||||
 | 
					    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					    android:layout_marginBottom="8dp"
 | 
				
			||||||
 | 
					    app:layout_constraintBottom_toTopOf="@id/separator"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintHorizontal_bias="0.0"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toBottomOf="@+id/language_order_preference" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <View
 | 
				
			||||||
 | 
					    android:id="@+id/separator"
 | 
				
			||||||
 | 
					    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					    android:layout_height="1dp"
 | 
				
			||||||
 | 
					    android:background="@color/black"
 | 
				
			||||||
 | 
					    android:layout_marginTop="10dp"
 | 
				
			||||||
 | 
					    android:layout_marginStart="8dp"
 | 
				
			||||||
 | 
					    android:layout_marginEnd="8dp"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toBottomOf="@id/language_history_list" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <TextView
 | 
				
			||||||
 | 
					    android:id="@+id/all_languages"
 | 
				
			||||||
 | 
					    android:layout_width="0dp"
 | 
				
			||||||
 | 
					    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					    android:text="All Languages"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toBottomOf="@id/separator"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="@+id/language_history_list"
 | 
				
			||||||
 | 
					    android:layout_margin="8dp"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <ListView
 | 
				
			||||||
 | 
					    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					    android:layout_height="0dp"
 | 
				
			||||||
 | 
					    android:layout_marginTop="8dp"
 | 
				
			||||||
 | 
					    android:id="@+id/language_list"
 | 
				
			||||||
 | 
					    app:layout_constraintBottom_toBottomOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintEnd_toEndOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					    app:layout_constraintTop_toBottomOf="@+id/all_languages" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</androidx.constraintlayout.widget.ConstraintLayout>
 | 
				
			||||||
| 
						 | 
					@ -554,6 +554,7 @@ Upload your first media by tapping on the add button.</string>
 | 
				
			||||||
  <string name="dialog_box_text_nomination">Why should %1$s be deleted?</string>
 | 
					  <string name="dialog_box_text_nomination">Why should %1$s be deleted?</string>
 | 
				
			||||||
  <string name="review_is_uploaded_by">%1$s is uploaded by: %2$s</string>
 | 
					  <string name="review_is_uploaded_by">%1$s is uploaded by: %2$s</string>
 | 
				
			||||||
  <string name="default_description_language">Default description language</string>
 | 
					  <string name="default_description_language">Default description language</string>
 | 
				
			||||||
 | 
					  <string name="secondary_description_languages">Secondary description languages</string>
 | 
				
			||||||
  <string name="delete_helper_show_deletion_title">Nominating for deletion</string>
 | 
					  <string name="delete_helper_show_deletion_title">Nominating for deletion</string>
 | 
				
			||||||
  <string name="delete_helper_show_deletion_title_success">Success</string>
 | 
					  <string name="delete_helper_show_deletion_title_success">Success</string>
 | 
				
			||||||
  <string name="delete_helper_show_deletion_message_if">Nominated %1$s for deletion.</string>
 | 
					  <string name="delete_helper_show_deletion_message_if">Nominated %1$s for deletion.</string>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,13 @@
 | 
				
			||||||
          app:singleLineTitle="false"
 | 
					          app:singleLineTitle="false"
 | 
				
			||||||
          android:title="@string/default_description_language" />
 | 
					          android:title="@string/default_description_language" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- New Secondary Language Picker -->
 | 
				
			||||||
 | 
					        <Preference
 | 
				
			||||||
 | 
					          android:key="descriptionSecondaryLanguagesPref"
 | 
				
			||||||
 | 
					          app:useSimpleSummaryProvider="true"
 | 
				
			||||||
 | 
					          app:singleLineTitle="false"
 | 
				
			||||||
 | 
					          android:title="@string/secondary_description_languages" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <SwitchPreference
 | 
					        <SwitchPreference
 | 
				
			||||||
          android:defaultValue="true"
 | 
					          android:defaultValue="true"
 | 
				
			||||||
          android:key="displayNearbyCardView"
 | 
					          android:key="displayNearbyCardView"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,11 +21,13 @@ WHERE {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Get the label in the preferred language of the user, or any other language if no label is available in that language.
 | 
					  # Get the label in the preferred language of the user, or any other language if no label is available in that language.
 | 
				
			||||||
  OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")}
 | 
					  OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")}
 | 
				
			||||||
 | 
					  ${SECONDARYLABEL}
 | 
				
			||||||
  OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage}
 | 
					  OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage}
 | 
				
			||||||
  BIND(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage, "?") as ?label)
 | 
					  BIND(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage, "?") as ?label)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Get the description in the preferred language of the user, or any other language if no description is available in that language.
 | 
					  # Get the description in the preferred language of the user, or any other language if no description is available in that language.
 | 
				
			||||||
  OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")}
 | 
					  OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")}
 | 
				
			||||||
 | 
					  ${SECONDARYDESCRIPTION}
 | 
				
			||||||
  OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage}
 | 
					  OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage}
 | 
				
			||||||
  BIND(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?") as ?description)
 | 
					  BIND(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?") as ?description)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +35,7 @@ WHERE {
 | 
				
			||||||
  OPTIONAL {
 | 
					  OPTIONAL {
 | 
				
			||||||
  ?item p:P31/ps:P31 ?class.
 | 
					  ?item p:P31/ps:P31 ?class.
 | 
				
			||||||
    OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "${LANG}")}
 | 
					    OPTIONAL {?class rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "${LANG}")}
 | 
				
			||||||
 | 
					    ${SECONDARYCLASSLABEL}
 | 
				
			||||||
    OPTIONAL {?class rdfs:label ?classLabelAnyLanguage}
 | 
					    OPTIONAL {?class rdfs:label ?classLabelAnyLanguage}
 | 
				
			||||||
    BIND(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?") as ?classLabel)
 | 
					    BIND(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?") as ?classLabel)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue