mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Merge branch 'main' into media_migration
This commit is contained in:
commit
53c7fd8507
59 changed files with 1265 additions and 1112 deletions
80
.github/workflows/android.yml
vendored
80
.github/workflows/android.yml
vendored
|
|
@ -2,11 +2,6 @@ name: Android CI
|
||||||
|
|
||||||
on: [push, pull_request, workflow_dispatch]
|
on: [push, pull_request, workflow_dispatch]
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
contents: read
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: build-${{ github.event.pull_request.number || github.ref }}
|
group: build-${{ github.event.pull_request.number || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
@ -17,17 +12,17 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
||||||
- name: Cache packages
|
- name: Cache packages
|
||||||
id: cache-packages
|
id: cache-packages
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
|
|
@ -42,7 +37,7 @@ jobs:
|
||||||
|
|
||||||
- name: AVD cache
|
- name: AVD cache
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: avd-cache
|
id: avd-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
|
|
@ -108,63 +103,12 @@ jobs:
|
||||||
name: prodDebugAPK
|
name: prodDebugAPK
|
||||||
path: app/build/outputs/apk/prod/debug/app-*.apk
|
path: app/build/outputs/apk/prod/debug/app-*.apk
|
||||||
|
|
||||||
- name: Comment on PR with APK download links
|
- name: Create and PR number artifact
|
||||||
if: github.event_name == 'pull_request'
|
run: |
|
||||||
uses: actions/github-script@v6
|
echo "{\"pr_number\": ${{ github.event.pull_request.number || 'null' }}}" > pr_number.json
|
||||||
|
|
||||||
|
- name: Upload PR number artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
name: pr_number
|
||||||
script: |
|
path: ./pr_number.json
|
||||||
try {
|
|
||||||
const token = process.env.GITHUB_TOKEN;
|
|
||||||
if (!token) {
|
|
||||||
throw new Error('GITHUB_TOKEN is not set. Please check workflow permissions.');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
run_id: context.runId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!artifacts || artifacts.length === 0) {
|
|
||||||
console.log('No artifacts found for this workflow run.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const betaArtifact = artifacts.find(artifact => artifact.name === "betaDebugAPK");
|
|
||||||
const prodArtifact = artifacts.find(artifact => artifact.name === "prodDebugAPK");
|
|
||||||
|
|
||||||
if (!betaArtifact || !prodArtifact) {
|
|
||||||
console.log('Could not find both Beta and Prod APK artifacts.');
|
|
||||||
console.log('Available artifacts:', artifacts.map(a => a.name).join(', '));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const betaDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${context.runId}/artifacts/${betaArtifact.id}`;
|
|
||||||
const prodDownloadUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/suites/${context.runId}/artifacts/${prodArtifact.id}`;
|
|
||||||
|
|
||||||
const commentBody = `
|
|
||||||
📱 **APK for pull request is ready to see the changes** 📱
|
|
||||||
- [Download Beta APK](${betaDownloadUrl})
|
|
||||||
- [Download Prod APK](${prodDownloadUrl})
|
|
||||||
`;
|
|
||||||
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: commentBody
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Successfully posted comment with APK download links');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in PR comment creation:', error);
|
|
||||||
if (error.message.includes('GITHUB_TOKEN')) {
|
|
||||||
core.setFailed('Missing or invalid GITHUB_TOKEN. Please check repository secrets configuration.');
|
|
||||||
} else if (error.status === 403) {
|
|
||||||
core.setFailed('Permission denied. Please check workflow permissions in repository settings.');
|
|
||||||
} else {
|
|
||||||
core.setFailed(`Workflow failed: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
4
.github/workflows/build-beta.yml
vendored
4
.github/workflows/build-beta.yml
vendored
|
|
@ -8,9 +8,9 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: set up JDK 17
|
- name: set up JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
|
||||||
96
.github/workflows/comment_artifacts_on_PR.yml
vendored
Normal file
96
.github/workflows/comment_artifacts_on_PR.yml
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
name: Comment Artifacts on PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: [ "Android CI" ]
|
||||||
|
types: [ completed ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: comment-${{ github.event.workflow_run.id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }}
|
||||||
|
steps:
|
||||||
|
- name: Download and process artifacts
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const runId = context.payload.workflow_run.id;
|
||||||
|
|
||||||
|
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
run_id: runId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const prNumberArtifact = allArtifacts.data.artifacts.find(artifact => artifact.name === "pr_number");
|
||||||
|
if (!prNumberArtifact) {
|
||||||
|
console.log("pr_number artifact not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const download = await github.rest.actions.downloadArtifact({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
artifact_id: prNumberArtifact.id,
|
||||||
|
archive_format: 'zip',
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_number.zip`, Buffer.from(download.data));
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
execSync('unzip -q pr_number.zip -d ./pr_number/');
|
||||||
|
fs.unlinkSync('pr_number.zip');
|
||||||
|
|
||||||
|
const prData = JSON.parse(fs.readFileSync('./pr_number/pr_number.json', 'utf8'));
|
||||||
|
const prNumber = prData.pr_number;
|
||||||
|
|
||||||
|
if (!prNumber || prNumber === 'null') {
|
||||||
|
console.log("No valid PR number found in pr_number.json. Skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const artifactsToLink = allArtifacts.data.artifacts.filter(artifact => artifact.name !== "pr_number");
|
||||||
|
if (artifactsToLink.length === 0) {
|
||||||
|
console.log("No artifacts to link found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const comments = await github.rest.issues.listComments({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: Number(prNumber),
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldComments = comments.data.filter(comment =>
|
||||||
|
comment.body.startsWith("✅ Generated APK variants!")
|
||||||
|
);
|
||||||
|
for (const comment of oldComments) {
|
||||||
|
await github.rest.issues.deleteComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: comment.id,
|
||||||
|
});
|
||||||
|
console.log(`Deleted old comment ID: ${comment.id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const commentBody = `✅ Generated APK variants!\n` +
|
||||||
|
artifactsToLink.map(artifact => {
|
||||||
|
const artifactUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}`;
|
||||||
|
return `- 🤖 [Download ${artifact.name}](${artifactUrl})`;
|
||||||
|
}).join('\n');
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: Number(prNumber),
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Wikimedia Commons Android app
|
# Wikimedia Commons Android app
|
||||||

|

|
||||||
[](https://github.com/commons-app/apps-android-commons/actions?query=branch%3Amaster)
|
[](https://github.com/commons-app/apps-android-commons/actions?query=branch%3Amain)
|
||||||
[](https://appetize.io/app/8ywtpe9f8tb8h6bey11c92vkcw)
|
[](https://appetize.io/app/8ywtpe9f8tb8h6bey11c92vkcw)
|
||||||
[](https://codecov.io/gh/commons-app/apps-android-commons)
|
[](https://codecov.io/gh/commons-app/apps-android-commons)
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ This software is open source, licensed under the [Apache License 2.0][10].
|
||||||
|
|
||||||
[1]: https://play.google.com/store/apps/details?id=fr.free.nrw.commons
|
[1]: https://play.google.com/store/apps/details?id=fr.free.nrw.commons
|
||||||
[2]: https://commons-app.github.io/
|
[2]: https://commons-app.github.io/
|
||||||
[3]: https://github.com/commons-app/apps-android-commons/issues
|
[3]: https://github.com/commons-app/apps-android-commons/issues?q=is%3Aopen+is%3Aissue+no%3Aassignee+-label%3Adebated+label%3Abug+-label%3A%22low+priority%22+-label%3Aupstream
|
||||||
|
|
||||||
[4]: https://github.com/commons-app/commons-app-documentation/blob/master/android/README.md#-android-documentation
|
[4]: https://github.com/commons-app/commons-app-documentation/blob/master/android/README.md#-android-documentation
|
||||||
[5]: https://github.com/commons-app/commons-app-documentation/blob/master/android/README.md#-user-documentation
|
[5]: https://github.com/commons-app/commons-app-documentation/blob/master/android/README.md#-user-documentation
|
||||||
|
|
|
||||||
|
|
@ -175,8 +175,8 @@ dependencies {
|
||||||
testImplementation "androidx.work:work-testing:$work_version"
|
testImplementation "androidx.work:work-testing:$work_version"
|
||||||
|
|
||||||
//Glide
|
//Glide
|
||||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||||
kaptTest "androidx.databinding:databinding-compiler:8.0.2"
|
kaptTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||||
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
|
kaptAndroidTest "androidx.databinding:databinding-compiler:8.0.2"
|
||||||
|
|
||||||
|
|
@ -212,8 +212,8 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
//applicationId 'fr.free.nrw.commons'
|
//applicationId 'fr.free.nrw.commons'
|
||||||
|
|
||||||
versionCode 1043
|
versionCode 1046
|
||||||
versionName '5.1.2'
|
versionName '5.1.3'
|
||||||
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
|
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
|
||||||
|
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
|
|
|
||||||
|
|
@ -232,12 +232,6 @@
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/provider_bookmarks"
|
android:label="@string/provider_bookmarks"
|
||||||
android:syncable="false" />
|
android:syncable="false" />
|
||||||
<provider
|
|
||||||
android:name=".bookmarks.locations.BookmarkLocationsContentProvider"
|
|
||||||
android:authorities="${applicationId}.bookmarks.locations.contentprovider"
|
|
||||||
android:exported="false"
|
|
||||||
android:label="@string/provider_bookmarks_location"
|
|
||||||
android:syncable="false" />
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".bookmarks.items.BookmarkItemsContentProvider"
|
android:name=".bookmarks.items.BookmarkItemsContentProvider"
|
||||||
android:authorities="${applicationId}.bookmarks.items.contentprovider"
|
android:authorities="${applicationId}.bookmarks.items.contentprovider"
|
||||||
|
|
|
||||||
|
|
@ -247,13 +247,17 @@ class CommonsApplication : MultiDexApplication() {
|
||||||
DBOpenHelper.CONTRIBUTIONS_TABLE
|
DBOpenHelper.CONTRIBUTIONS_TABLE
|
||||||
) //Delete the contributions table in the existing db on older versions
|
) //Delete the contributions table in the existing db on older versions
|
||||||
|
|
||||||
|
dbOpenHelper.deleteTable(
|
||||||
|
db,
|
||||||
|
DBOpenHelper.BOOKMARKS_LOCATIONS
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
contributionDao.deleteAll()
|
contributionDao.deleteAll()
|
||||||
} catch (e: SQLiteException) {
|
} catch (e: SQLiteException) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
BookmarkPicturesDao.Table.onDelete(db)
|
BookmarkPicturesDao.Table.onDelete(db)
|
||||||
BookmarkLocationsDao.Table.onDelete(db)
|
|
||||||
BookmarkItemsDao.Table.onDelete(db)
|
BookmarkItemsDao.Table.onDelete(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,54 @@ class Media constructor(
|
||||||
captions = captions,
|
captions = captions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
captions: Map<String, String>,
|
||||||
|
categories: List<String>?,
|
||||||
|
filename: String?,
|
||||||
|
fallbackDescription: String?,
|
||||||
|
author: String?,
|
||||||
|
user: String?,
|
||||||
|
dateUploaded: Date? = Date(),
|
||||||
|
license: String? = null,
|
||||||
|
licenseUrl: String? = null,
|
||||||
|
imageUrl: String? = null,
|
||||||
|
thumbUrl: String? = null,
|
||||||
|
coordinates: LatLng? = null,
|
||||||
|
descriptions: Map<String, String> = emptyMap(),
|
||||||
|
depictionIds: List<String> = emptyList(),
|
||||||
|
categoriesHiddenStatus: Map<String, Boolean> = emptyMap()
|
||||||
|
) : this(
|
||||||
|
pageId = UUID.randomUUID().toString(),
|
||||||
|
filename = filename,
|
||||||
|
fallbackDescription = fallbackDescription,
|
||||||
|
dateUploaded = dateUploaded,
|
||||||
|
author = author,
|
||||||
|
user = user,
|
||||||
|
categories = categories,
|
||||||
|
captions = captions,
|
||||||
|
license = license,
|
||||||
|
licenseUrl = licenseUrl,
|
||||||
|
imageUrl = imageUrl,
|
||||||
|
thumbUrl = thumbUrl,
|
||||||
|
coordinates = coordinates,
|
||||||
|
descriptions = descriptions,
|
||||||
|
depictionIds = depictionIds,
|
||||||
|
categoriesHiddenStatus = categoriesHiddenStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Author if it's not null or empty, otherwise
|
||||||
|
* returns user
|
||||||
|
* @return Author or User
|
||||||
|
*/
|
||||||
|
fun getAuthorOrUser(): String? {
|
||||||
|
return if (!author.isNullOrEmpty()) {
|
||||||
|
author
|
||||||
|
} else{
|
||||||
|
user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets media display title
|
* Gets media display title
|
||||||
* @return Media title
|
* @return Media title
|
||||||
|
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
|
||||||
// We can get uri using java.Net.Uri, but andoid implimentation is faster (but it's forgiving with handling exceptions though)
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
||||||
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_NAME;
|
|
||||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.TABLE_NAME;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles private storage for Bookmark locations
|
|
||||||
*/
|
|
||||||
public class BookmarkLocationsContentProvider extends CommonsDaggerContentProvider {
|
|
||||||
|
|
||||||
private static final String BASE_PATH = "bookmarksLocations";
|
|
||||||
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.BOOKMARK_LOCATIONS_AUTHORITY + "/" + BASE_PATH);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append bookmark locations name to the base uri
|
|
||||||
*/
|
|
||||||
public static Uri uriForName(String name) {
|
|
||||||
return Uri.parse(BASE_URI.toString() + "/" + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject DBOpenHelper dbOpenHelper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType(@NonNull Uri uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries the SQLite database for the bookmark locations
|
|
||||||
* @param uri : contains the uri for bookmark locations
|
|
||||||
* @param projection
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
* @param sortOrder : ascending or descending
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
|
||||||
String[] selectionArgs, String sortOrder) {
|
|
||||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
|
||||||
queryBuilder.setTables(TABLE_NAME);
|
|
||||||
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
|
|
||||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
|
||||||
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the update query of local SQLite Database
|
|
||||||
* @param uri : contains the uri for bookmark locations
|
|
||||||
* @param contentValues : new values to be entered to db
|
|
||||||
* @param selection : handles Where
|
|
||||||
* @param selectionArgs : the condition of Where clause
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int update(@NonNull Uri uri, ContentValues contentValues, String selection,
|
|
||||||
String[] selectionArgs) {
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
int rowsUpdated;
|
|
||||||
if (TextUtils.isEmpty(selection)) {
|
|
||||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
|
||||||
rowsUpdated = sqlDB.update(TABLE_NAME,
|
|
||||||
contentValues,
|
|
||||||
COLUMN_NAME + " = ?",
|
|
||||||
new String[]{String.valueOf(id)});
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Parameter `selection` should be empty when updating an ID");
|
|
||||||
}
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rowsUpdated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the insertion of new bookmark locations record to local SQLite Database
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public Uri insert(@NonNull Uri uri, ContentValues contentValues) {
|
|
||||||
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase();
|
|
||||||
long id = sqlDB.insert(BookmarkLocationsDao.Table.TABLE_NAME, null, contentValues);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return Uri.parse(BASE_URI + "/" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
public int delete(@NonNull Uri uri, String s, String[] strings) {
|
|
||||||
int rows;
|
|
||||||
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
|
|
||||||
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment());
|
|
||||||
rows = db.delete(TABLE_NAME,
|
|
||||||
"location_name = ?",
|
|
||||||
new String[]{uri.getLastPathSegment()}
|
|
||||||
);
|
|
||||||
getContext().getContentResolver().notifyChange(uri, null);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class BookmarkLocationsController {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
BookmarkLocationsDao bookmarkLocationDao;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public BookmarkLocationsController() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load from DB the bookmarked locations
|
|
||||||
* @return a list of Place objects.
|
|
||||||
*/
|
|
||||||
public List<Place> loadFavoritesLocations() {
|
|
||||||
return bookmarkLocationDao.getAllBookmarksLocations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class BookmarkLocationsController @Inject constructor(
|
||||||
|
private val bookmarkLocationDao: BookmarkLocationsDao
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load bookmarked locations from the database.
|
||||||
|
* @return a list of Place objects.
|
||||||
|
*/
|
||||||
|
suspend fun loadFavoritesLocations(): List<Place> =
|
||||||
|
bookmarkLocationDao.getAllBookmarksLocationsPlace()
|
||||||
|
}
|
||||||
|
|
@ -1,313 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteException;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.nearby.NearbyController;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Provider;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import fr.free.nrw.commons.nearby.Label;
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
|
||||||
import fr.free.nrw.commons.nearby.Sitelinks;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider.BASE_URI;
|
|
||||||
|
|
||||||
public class BookmarkLocationsDao {
|
|
||||||
|
|
||||||
private final Provider<ContentProviderClient> clientProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public BookmarkLocationsDao(@Named("bookmarksLocation") Provider<ContentProviderClient> clientProvider) {
|
|
||||||
this.clientProvider = clientProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all persisted locations bookmarks on database
|
|
||||||
*
|
|
||||||
* @return list of Place
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public List<Place> getAllBookmarksLocations() {
|
|
||||||
List<Place> items = new ArrayList<>();
|
|
||||||
Cursor cursor = null;
|
|
||||||
ContentProviderClient db = clientProvider.get();
|
|
||||||
try {
|
|
||||||
cursor = db.query(
|
|
||||||
BookmarkLocationsContentProvider.BASE_URI,
|
|
||||||
Table.ALL_FIELDS,
|
|
||||||
null,
|
|
||||||
new String[]{},
|
|
||||||
null);
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
|
||||||
items.add(fromCursor(cursor));
|
|
||||||
}
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
db.release();
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look for a place in bookmarks table in order to insert or delete it
|
|
||||||
*
|
|
||||||
* @param bookmarkLocation : Place object
|
|
||||||
* @return is Place now fav ?
|
|
||||||
*/
|
|
||||||
public boolean updateBookmarkLocation(Place bookmarkLocation) {
|
|
||||||
boolean bookmarkExists = findBookmarkLocation(bookmarkLocation);
|
|
||||||
if (bookmarkExists) {
|
|
||||||
deleteBookmarkLocation(bookmarkLocation);
|
|
||||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, false);
|
|
||||||
} else {
|
|
||||||
addBookmarkLocation(bookmarkLocation);
|
|
||||||
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, true);
|
|
||||||
}
|
|
||||||
return !bookmarkExists;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a Place to bookmarks table
|
|
||||||
*
|
|
||||||
* @param bookmarkLocation : Place to add
|
|
||||||
*/
|
|
||||||
private void addBookmarkLocation(Place bookmarkLocation) {
|
|
||||||
ContentProviderClient db = clientProvider.get();
|
|
||||||
try {
|
|
||||||
db.insert(BASE_URI, toContentValues(bookmarkLocation));
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
db.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a Place from bookmarks table
|
|
||||||
*
|
|
||||||
* @param bookmarkLocation : Place to delete
|
|
||||||
*/
|
|
||||||
private void deleteBookmarkLocation(Place bookmarkLocation) {
|
|
||||||
ContentProviderClient db = clientProvider.get();
|
|
||||||
try {
|
|
||||||
db.delete(BookmarkLocationsContentProvider.uriForName(bookmarkLocation.name), null, null);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
db.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a Place from database based on its name
|
|
||||||
*
|
|
||||||
* @param bookmarkLocation : Place to find
|
|
||||||
* @return boolean : is Place in database ?
|
|
||||||
*/
|
|
||||||
public boolean findBookmarkLocation(Place bookmarkLocation) {
|
|
||||||
Cursor cursor = null;
|
|
||||||
ContentProviderClient db = clientProvider.get();
|
|
||||||
try {
|
|
||||||
cursor = db.query(
|
|
||||||
BookmarkLocationsContentProvider.BASE_URI,
|
|
||||||
Table.ALL_FIELDS,
|
|
||||||
Table.COLUMN_NAME + "=?",
|
|
||||||
new String[]{bookmarkLocation.name},
|
|
||||||
null);
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
// This feels lazy, but to hell with checked exceptions. :)
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
db.release();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("Range")
|
|
||||||
@NonNull
|
|
||||||
Place fromCursor(final Cursor cursor) {
|
|
||||||
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
|
|
||||||
cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LONG)), 1F);
|
|
||||||
|
|
||||||
final Sitelinks.Builder builder = new Sitelinks.Builder();
|
|
||||||
builder.setWikipediaLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIPEDIA_LINK)));
|
|
||||||
builder.setWikidataLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIDATA_LINK)));
|
|
||||||
builder.setCommonsLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_COMMONS_LINK)));
|
|
||||||
|
|
||||||
return new Place(
|
|
||||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_LANGUAGE)),
|
|
||||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)),
|
|
||||||
Label.fromText((cursor.getString(cursor.getColumnIndex(Table.COLUMN_LABEL_TEXT)))),
|
|
||||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)),
|
|
||||||
location,
|
|
||||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_CATEGORY)),
|
|
||||||
builder.build(),
|
|
||||||
cursor.getString(cursor.getColumnIndex(Table.COLUMN_PIC)),
|
|
||||||
Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(Table.COLUMN_EXISTS)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ContentValues toContentValues(Place bookmarkLocation) {
|
|
||||||
ContentValues cv = new ContentValues();
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_NAME, bookmarkLocation.getName());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LANGUAGE, bookmarkLocation.getLanguage());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_DESCRIPTION, bookmarkLocation.getLongDescription());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_CATEGORY, bookmarkLocation.getCategory());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LABEL_TEXT, bookmarkLocation.getLabel()!=null ? bookmarkLocation.getLabel().getText() : "");
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LABEL_ICON, bookmarkLocation.getLabel()!=null ? bookmarkLocation.getLabel().getIcon() : null);
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_WIKIPEDIA_LINK, bookmarkLocation.siteLinks.getWikipediaLink().toString());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_WIKIDATA_LINK, bookmarkLocation.siteLinks.getWikidataLink().toString());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK, bookmarkLocation.siteLinks.getCommonsLink().toString());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LAT, bookmarkLocation.location.getLatitude());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_LONG, bookmarkLocation.location.getLongitude());
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_PIC, bookmarkLocation.pic);
|
|
||||||
cv.put(BookmarkLocationsDao.Table.COLUMN_EXISTS, bookmarkLocation.exists.toString());
|
|
||||||
return cv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Table {
|
|
||||||
public static final String TABLE_NAME = "bookmarksLocations";
|
|
||||||
|
|
||||||
static final String COLUMN_NAME = "location_name";
|
|
||||||
static final String COLUMN_LANGUAGE = "location_language";
|
|
||||||
static final String COLUMN_DESCRIPTION = "location_description";
|
|
||||||
static final String COLUMN_LAT = "location_lat";
|
|
||||||
static final String COLUMN_LONG = "location_long";
|
|
||||||
static final String COLUMN_CATEGORY = "location_category";
|
|
||||||
static final String COLUMN_LABEL_TEXT = "location_label_text";
|
|
||||||
static final String COLUMN_LABEL_ICON = "location_label_icon";
|
|
||||||
static final String COLUMN_IMAGE_URL = "location_image_url";
|
|
||||||
static final String COLUMN_WIKIPEDIA_LINK = "location_wikipedia_link";
|
|
||||||
static final String COLUMN_WIKIDATA_LINK = "location_wikidata_link";
|
|
||||||
static final String COLUMN_COMMONS_LINK = "location_commons_link";
|
|
||||||
static final String COLUMN_PIC = "location_pic";
|
|
||||||
static final String COLUMN_EXISTS = "location_exists";
|
|
||||||
|
|
||||||
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
|
|
||||||
public static final String[] ALL_FIELDS = {
|
|
||||||
COLUMN_NAME,
|
|
||||||
COLUMN_LANGUAGE,
|
|
||||||
COLUMN_DESCRIPTION,
|
|
||||||
COLUMN_CATEGORY,
|
|
||||||
COLUMN_LABEL_TEXT,
|
|
||||||
COLUMN_LABEL_ICON,
|
|
||||||
COLUMN_LAT,
|
|
||||||
COLUMN_LONG,
|
|
||||||
COLUMN_IMAGE_URL,
|
|
||||||
COLUMN_WIKIPEDIA_LINK,
|
|
||||||
COLUMN_WIKIDATA_LINK,
|
|
||||||
COLUMN_COMMONS_LINK,
|
|
||||||
COLUMN_PIC,
|
|
||||||
COLUMN_EXISTS,
|
|
||||||
};
|
|
||||||
|
|
||||||
static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
|
||||||
|
|
||||||
static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
|
|
||||||
+ COLUMN_NAME + " STRING PRIMARY KEY,"
|
|
||||||
+ COLUMN_LANGUAGE + " STRING,"
|
|
||||||
+ COLUMN_DESCRIPTION + " STRING,"
|
|
||||||
+ COLUMN_CATEGORY + " STRING,"
|
|
||||||
+ COLUMN_LABEL_TEXT + " STRING,"
|
|
||||||
+ COLUMN_LABEL_ICON + " INTEGER,"
|
|
||||||
+ COLUMN_LAT + " DOUBLE,"
|
|
||||||
+ COLUMN_LONG + " DOUBLE,"
|
|
||||||
+ COLUMN_IMAGE_URL + " STRING,"
|
|
||||||
+ COLUMN_WIKIPEDIA_LINK + " STRING,"
|
|
||||||
+ COLUMN_WIKIDATA_LINK + " STRING,"
|
|
||||||
+ COLUMN_COMMONS_LINK + " STRING,"
|
|
||||||
+ COLUMN_PIC + " STRING,"
|
|
||||||
+ COLUMN_EXISTS + " STRING"
|
|
||||||
+ ");";
|
|
||||||
|
|
||||||
public static void onCreate(SQLiteDatabase db) {
|
|
||||||
db.execSQL(CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onDelete(SQLiteDatabase db) {
|
|
||||||
db.execSQL(DROP_TABLE_STATEMENT);
|
|
||||||
onCreate(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onUpdate(final SQLiteDatabase db, int from, final int to) {
|
|
||||||
Timber.d("bookmarksLocations db is updated from:"+from+", to:"+to);
|
|
||||||
if (from == to) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (from < 7) {
|
|
||||||
// doesn't exist yet
|
|
||||||
from++;
|
|
||||||
onUpdate(db, from, to);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (from == 7) {
|
|
||||||
// table added in version 8
|
|
||||||
onCreate(db);
|
|
||||||
from++;
|
|
||||||
onUpdate(db, from, to);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (from < 10) {
|
|
||||||
from++;
|
|
||||||
onUpdate(db, from, to);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (from == 10) {
|
|
||||||
//This is safe, and can be called clean, as we/I do not remember the appropriate version for this
|
|
||||||
//We are anyways switching to room, these things won't be necessary then
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;");
|
|
||||||
}catch (SQLiteException exception){
|
|
||||||
Timber.e(exception);//
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (from >= 12) {
|
|
||||||
try {
|
|
||||||
db.execSQL(
|
|
||||||
"ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;");
|
|
||||||
} catch (SQLiteException exception) {
|
|
||||||
Timber.e(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (from >= 13){
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_language STRING;");
|
|
||||||
} catch (SQLiteException exception){
|
|
||||||
Timber.e(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (from >= 14){
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;");
|
|
||||||
} catch (SQLiteException exception){
|
|
||||||
Timber.e(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import androidx.room.Query
|
||||||
|
import fr.free.nrw.commons.nearby.NearbyController
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO for managing bookmark locations in the database.
|
||||||
|
*/
|
||||||
|
@Dao
|
||||||
|
abstract class BookmarkLocationsDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or updates a bookmark location in the database.
|
||||||
|
*/
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
abstract suspend fun addBookmarkLocation(bookmarkLocation: BookmarksLocations)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all bookmark locations from the database.
|
||||||
|
*/
|
||||||
|
@Query("SELECT * FROM bookmarks_locations")
|
||||||
|
abstract suspend fun getAllBookmarksLocations(): List<BookmarksLocations>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a bookmark location exists by name.
|
||||||
|
*/
|
||||||
|
@Query("SELECT EXISTS (SELECT 1 FROM bookmarks_locations WHERE location_name = :name)")
|
||||||
|
abstract suspend fun findBookmarkLocation(name: String): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a bookmark location from the database.
|
||||||
|
*/
|
||||||
|
@Delete
|
||||||
|
abstract suspend fun deleteBookmarkLocation(bookmarkLocation: BookmarksLocations)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or removes a bookmark location and updates markers.
|
||||||
|
* @return `true` if added, `false` if removed.
|
||||||
|
*/
|
||||||
|
suspend fun updateBookmarkLocation(bookmarkLocation: Place): Boolean {
|
||||||
|
val exists = findBookmarkLocation(bookmarkLocation.name)
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
deleteBookmarkLocation(bookmarkLocation.toBookmarksLocations())
|
||||||
|
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, false)
|
||||||
|
} else {
|
||||||
|
addBookmarkLocation(bookmarkLocation.toBookmarksLocations())
|
||||||
|
NearbyController.updateMarkerLabelListBookmark(bookmarkLocation, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return !exists
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all bookmark locations as `Place` objects.
|
||||||
|
*/
|
||||||
|
suspend fun getAllBookmarksLocationsPlace(): List<Place> {
|
||||||
|
return getAllBookmarksLocations().map { it.toPlace() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
package fr.free.nrw.commons.bookmarks.locations;
|
|
||||||
|
|
||||||
import android.Manifest.permission;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import dagger.android.support.DaggerFragment;
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
import fr.free.nrw.commons.contributions.ContributionController;
|
|
||||||
import fr.free.nrw.commons.databinding.FragmentBookmarksLocationsBinding;
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
|
||||||
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions;
|
|
||||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import kotlin.Unit;
|
|
||||||
|
|
||||||
public class BookmarkLocationsFragment extends DaggerFragment {
|
|
||||||
|
|
||||||
public FragmentBookmarksLocationsBinding binding;
|
|
||||||
|
|
||||||
@Inject BookmarkLocationsController controller;
|
|
||||||
@Inject ContributionController contributionController;
|
|
||||||
@Inject BookmarkLocationsDao bookmarkLocationDao;
|
|
||||||
@Inject CommonPlaceClickActions commonPlaceClickActions;
|
|
||||||
private PlaceAdapter adapter;
|
|
||||||
|
|
||||||
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
|
||||||
registerForActivityResult(new StartActivityForResult(),
|
|
||||||
result -> {
|
|
||||||
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
|
||||||
contributionController.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
|
||||||
registerForActivityResult(new StartActivityForResult(),
|
|
||||||
result -> {
|
|
||||||
contributionController.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
|
||||||
contributionController.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(Map<String, Boolean> result) {
|
|
||||||
boolean areAllGranted = true;
|
|
||||||
for(final boolean b : result.values()) {
|
|
||||||
areAllGranted = areAllGranted && b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (areAllGranted) {
|
|
||||||
contributionController.locationPermissionCallback.onLocationPermissionGranted();
|
|
||||||
} else {
|
|
||||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
|
||||||
contributionController.handleShowRationaleFlowCameraLocation(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
|
||||||
} else {
|
|
||||||
contributionController.locationPermissionCallback.onLocationPermissionDenied(getActivity().getString(R.string.in_app_camera_location_permission_denied));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of the fragment with the right bundle parameters
|
|
||||||
* @return an instance of the fragment
|
|
||||||
*/
|
|
||||||
public static BookmarkLocationsFragment newInstance() {
|
|
||||||
return new BookmarkLocationsFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(
|
|
||||||
@NonNull LayoutInflater inflater,
|
|
||||||
ViewGroup container,
|
|
||||||
Bundle savedInstanceState
|
|
||||||
) {
|
|
||||||
binding = FragmentBookmarksLocationsBinding.inflate(inflater, container, false);
|
|
||||||
return binding.getRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
super.onViewCreated(view, savedInstanceState);
|
|
||||||
binding.loadingImagesProgressBar.setVisibility(View.VISIBLE);
|
|
||||||
binding.listView.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
adapter = new PlaceAdapter(bookmarkLocationDao,
|
|
||||||
place -> Unit.INSTANCE,
|
|
||||||
(place, isBookmarked) -> {
|
|
||||||
adapter.remove(place);
|
|
||||||
return Unit.INSTANCE;
|
|
||||||
},
|
|
||||||
commonPlaceClickActions,
|
|
||||||
inAppCameraLocationPermissionLauncher,
|
|
||||||
galleryPickLauncherForResult,
|
|
||||||
cameraPickLauncherForResult
|
|
||||||
);
|
|
||||||
binding.listView.setAdapter(adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
initList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the recycler view with bookmarked locations
|
|
||||||
*/
|
|
||||||
private void initList() {
|
|
||||||
List<Place> places = controller.loadFavoritesLocations();
|
|
||||||
adapter.setItems(places);
|
|
||||||
binding.loadingImagesProgressBar.setVisibility(View.GONE);
|
|
||||||
if (places.size() <= 0) {
|
|
||||||
binding.statusMessage.setText(R.string.bookmark_empty);
|
|
||||||
binding.statusMessage.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
binding.statusMessage.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
binding = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
|
import android.Manifest.permission
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import dagger.android.support.DaggerFragment
|
||||||
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionController
|
||||||
|
import fr.free.nrw.commons.databinding.FragmentBookmarksLocationsBinding
|
||||||
|
import fr.free.nrw.commons.filepicker.FilePicker
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
|
||||||
|
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
|
class BookmarkLocationsFragment : DaggerFragment() {
|
||||||
|
|
||||||
|
private var binding: FragmentBookmarksLocationsBinding? = null
|
||||||
|
|
||||||
|
@Inject lateinit var controller: BookmarkLocationsController
|
||||||
|
@Inject lateinit var contributionController: ContributionController
|
||||||
|
@Inject lateinit var bookmarkLocationDao: BookmarkLocationsDao
|
||||||
|
@Inject lateinit var commonPlaceClickActions: CommonPlaceClickActions
|
||||||
|
|
||||||
|
private lateinit var inAppCameraLocationPermissionLauncher:
|
||||||
|
ActivityResultLauncher<Array<String>>
|
||||||
|
private lateinit var adapter: PlaceAdapter
|
||||||
|
|
||||||
|
private val cameraPickLauncherForResult =
|
||||||
|
registerForActivityResult(StartActivityForResult()) { result ->
|
||||||
|
contributionController.handleActivityResultWithCallback(
|
||||||
|
requireActivity(),
|
||||||
|
object: FilePicker.HandleActivityResult {
|
||||||
|
override fun onHandleActivityResult(callbacks: FilePicker.Callbacks) {
|
||||||
|
contributionController.onPictureReturnedFromCamera(
|
||||||
|
result,
|
||||||
|
requireActivity(),
|
||||||
|
callbacks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val galleryPickLauncherForResult =
|
||||||
|
registerForActivityResult(StartActivityForResult()) { result ->
|
||||||
|
contributionController.handleActivityResultWithCallback(
|
||||||
|
requireActivity(),
|
||||||
|
object: FilePicker.HandleActivityResult {
|
||||||
|
override fun onHandleActivityResult(callbacks: FilePicker.Callbacks) {
|
||||||
|
contributionController.onPictureReturnedFromGallery(
|
||||||
|
result,
|
||||||
|
requireActivity(),
|
||||||
|
callbacks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(): BookmarkLocationsFragment {
|
||||||
|
return BookmarkLocationsFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
binding = FragmentBookmarksLocationsBinding.inflate(inflater, container, false)
|
||||||
|
return binding?.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding?.loadingImagesProgressBar?.visibility = View.VISIBLE
|
||||||
|
binding?.listView?.layoutManager = LinearLayoutManager(context)
|
||||||
|
|
||||||
|
inAppCameraLocationPermissionLauncher =
|
||||||
|
registerForActivityResult(RequestMultiplePermissions()) { result ->
|
||||||
|
val areAllGranted = result.values.all { it }
|
||||||
|
|
||||||
|
if (areAllGranted) {
|
||||||
|
contributionController.locationPermissionCallback?.onLocationPermissionGranted()
|
||||||
|
} else {
|
||||||
|
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
contributionController.handleShowRationaleFlowCameraLocation(
|
||||||
|
requireActivity(),
|
||||||
|
inAppCameraLocationPermissionLauncher,
|
||||||
|
cameraPickLauncherForResult
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
contributionController.locationPermissionCallback
|
||||||
|
?.onLocationPermissionDenied(
|
||||||
|
getString(R.string.in_app_camera_location_permission_denied)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter = PlaceAdapter(
|
||||||
|
bookmarkLocationDao,
|
||||||
|
lifecycleScope,
|
||||||
|
{ },
|
||||||
|
{ place, _ ->
|
||||||
|
adapter.remove(place)
|
||||||
|
},
|
||||||
|
commonPlaceClickActions,
|
||||||
|
inAppCameraLocationPermissionLauncher,
|
||||||
|
galleryPickLauncherForResult,
|
||||||
|
cameraPickLauncherForResult
|
||||||
|
)
|
||||||
|
binding?.listView?.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
initList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initList() {
|
||||||
|
var places: List<Place>
|
||||||
|
if(view != null) {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
places = controller.loadFavoritesLocations()
|
||||||
|
updateUIList(places)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateUIList(places: List<Place>) {
|
||||||
|
adapter.items = places
|
||||||
|
binding?.loadingImagesProgressBar?.visibility = View.GONE
|
||||||
|
if (places.isEmpty()) {
|
||||||
|
binding?.statusMessage?.text = getString(R.string.bookmark_empty)
|
||||||
|
binding?.statusMessage?.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding?.statusMessage?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
// Make sure to null out the binding to avoid memory leaks
|
||||||
|
binding = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
class BookmarkLocationsViewModel(
|
||||||
|
private val bookmarkLocationsDao: BookmarkLocationsDao
|
||||||
|
): ViewModel() {
|
||||||
|
|
||||||
|
// fun getAllBookmarkLocations(): List<Place> {
|
||||||
|
// return bookmarkLocationsDao.getAllBookmarksLocationsPlace()
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import fr.free.nrw.commons.location.LatLng
|
||||||
|
import fr.free.nrw.commons.nearby.Label
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import fr.free.nrw.commons.nearby.Sitelinks
|
||||||
|
|
||||||
|
@Entity(tableName = "bookmarks_locations")
|
||||||
|
data class BookmarksLocations(
|
||||||
|
@PrimaryKey @ColumnInfo(name = "location_name") val locationName: String,
|
||||||
|
@ColumnInfo(name = "location_language") val locationLanguage: String,
|
||||||
|
@ColumnInfo(name = "location_description") val locationDescription: String,
|
||||||
|
@ColumnInfo(name = "location_lat") val locationLat: Double,
|
||||||
|
@ColumnInfo(name = "location_long") val locationLong: Double,
|
||||||
|
@ColumnInfo(name = "location_category") val locationCategory: String,
|
||||||
|
@ColumnInfo(name = "location_label_text") val locationLabelText: String,
|
||||||
|
@ColumnInfo(name = "location_label_icon") val locationLabelIcon: Int?,
|
||||||
|
@ColumnInfo(name = "location_image_url") val locationImageUrl: String,
|
||||||
|
@ColumnInfo(name = "location_wikipedia_link") val locationWikipediaLink: String,
|
||||||
|
@ColumnInfo(name = "location_wikidata_link") val locationWikidataLink: String,
|
||||||
|
@ColumnInfo(name = "location_commons_link") val locationCommonsLink: String,
|
||||||
|
@ColumnInfo(name = "location_pic") val locationPic: String,
|
||||||
|
@ColumnInfo(name = "location_exists") val locationExists: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
fun BookmarksLocations.toPlace(): Place {
|
||||||
|
val location = LatLng(
|
||||||
|
locationLat,
|
||||||
|
locationLong,
|
||||||
|
1F
|
||||||
|
)
|
||||||
|
|
||||||
|
val builder = Sitelinks.Builder().apply {
|
||||||
|
setWikipediaLink(locationWikipediaLink)
|
||||||
|
setWikidataLink(locationWikidataLink)
|
||||||
|
setCommonsLink(locationCommonsLink)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Place(
|
||||||
|
locationLanguage,
|
||||||
|
locationName,
|
||||||
|
Label.fromText(locationLabelText),
|
||||||
|
locationDescription,
|
||||||
|
location,
|
||||||
|
locationCategory,
|
||||||
|
builder.build(),
|
||||||
|
locationPic,
|
||||||
|
locationExists
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Place.toBookmarksLocations(): BookmarksLocations {
|
||||||
|
return BookmarksLocations(
|
||||||
|
locationName = name,
|
||||||
|
locationLanguage = language,
|
||||||
|
locationDescription = longDescription,
|
||||||
|
locationCategory = category,
|
||||||
|
locationLat = location.latitude,
|
||||||
|
locationLong = location.longitude,
|
||||||
|
locationLabelText = label?.text ?: "",
|
||||||
|
locationLabelIcon = label?.icon,
|
||||||
|
locationImageUrl = pic,
|
||||||
|
locationWikipediaLink = siteLinks.wikipediaLink.toString(),
|
||||||
|
locationWikidataLink = siteLinks.wikidataLink.toString(),
|
||||||
|
locationCommonsLink = siteLinks.commonsLink.toString(),
|
||||||
|
locationPic = pic,
|
||||||
|
locationExists = exists
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -98,14 +98,9 @@ class GridViewAdapter(
|
||||||
*/
|
*/
|
||||||
@SuppressLint("StringFormatInvalid")
|
@SuppressLint("StringFormatInvalid")
|
||||||
private fun setUploaderView(item: Media, uploader: TextView) {
|
private fun setUploaderView(item: Media, uploader: TextView) {
|
||||||
if (!item.author.isNullOrEmpty()) {
|
|
||||||
uploader.visibility = View.VISIBLE
|
|
||||||
uploader.text = context.getString(
|
uploader.text = context.getString(
|
||||||
R.string.image_uploaded_by,
|
R.string.image_uploaded_by,
|
||||||
item.user
|
item.getAuthorOrUser()
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
uploader.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ an upload might take a dozen seconds. */
|
||||||
this.contribution = contribution
|
this.contribution = contribution
|
||||||
this.position = position
|
this.position = position
|
||||||
binding.contributionTitle.text = contribution.media.mostRelevantCaption
|
binding.contributionTitle.text = contribution.media.mostRelevantCaption
|
||||||
binding.authorView.text = contribution.media.author
|
binding.authorView.text = contribution.media.getAuthorOrUser()
|
||||||
|
|
||||||
//Removes flicker of loading image.
|
//Removes flicker of loading image.
|
||||||
binding.contributionImage.hierarchy.fadeDuration = 0
|
binding.contributionImage.hierarchy.fadeDuration = 0
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ interface ContributionsContract {
|
||||||
|
|
||||||
interface View {
|
interface View {
|
||||||
fun showMessage(localizedMessage: String)
|
fun showMessage(localizedMessage: String)
|
||||||
fun getContext(): Context
|
fun getContext(): Context?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserActionListener : BasePresenter<View> {
|
interface UserActionListener : BasePresenter<View> {
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,9 @@ import java.util.Date
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
|
|
||||||
class ContributionsFragment
|
class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.OnBackStackChangedListener,
|
||||||
|
|
||||||
: CommonsDaggerSupportFragment(), FragmentManager.OnBackStackChangedListener,
|
|
||||||
LocationUpdateListener, MediaDetailProvider, SensorEventListener, ICampaignsView,
|
LocationUpdateListener, MediaDetailProvider, SensorEventListener, ICampaignsView,
|
||||||
ContributionsContract.View,
|
ContributionsContract.View, ContributionsListFragment.Callback {
|
||||||
ContributionsListFragment.Callback {
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@Inject
|
@Inject
|
||||||
@Named("default_preferences")
|
@Named("default_preferences")
|
||||||
|
|
@ -307,11 +304,13 @@ class ContributionsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notification.setOnClickListener { view: View? ->
|
notification.setOnClickListener { view: View? ->
|
||||||
|
context?.let {
|
||||||
startYourself(
|
startYourself(
|
||||||
context, "unread"
|
it, "unread"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
fun setNotificationCount() {
|
fun setNotificationCount() {
|
||||||
|
|
@ -500,7 +499,7 @@ class ContributionsFragment
|
||||||
|
|
||||||
private fun setUploadCount() {
|
private fun setUploadCount() {
|
||||||
okHttpJsonApiClient
|
okHttpJsonApiClient
|
||||||
?.getUploadCount((activity as MainActivity).sessionManager?.currentAccount!!.name)
|
?.getUploadCount(sessionManager?.currentAccount!!.name)
|
||||||
?.subscribeOn(Schedulers.io())
|
?.subscribeOn(Schedulers.io())
|
||||||
?.observeOn(AndroidSchedulers.mainThread())?.let {
|
?.observeOn(AndroidSchedulers.mainThread())?.let {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
|
@ -889,7 +888,8 @@ class ContributionsFragment
|
||||||
* this function updates the number of contributions
|
* this function updates the number of contributions
|
||||||
*/
|
*/
|
||||||
fun upDateUploadCount() {
|
fun upDateUploadCount() {
|
||||||
WorkManager.getInstance(context)
|
context?.let {
|
||||||
|
WorkManager.getInstance(it)
|
||||||
.getWorkInfosForUniqueWorkLiveData(UploadWorker::class.java.simpleName).observe(
|
.getWorkInfosForUniqueWorkLiveData(UploadWorker::class.java.simpleName).observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) { workInfos: List<WorkInfo?> ->
|
) { workInfos: List<WorkInfo?> ->
|
||||||
|
|
@ -898,6 +898,7 @@ class ContributionsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -953,7 +954,7 @@ class ContributionsFragment
|
||||||
Timber.d("Skipping re-upload for non-failed %s", contribution.toString())
|
Timber.d("Skipping re-upload for non-failed %s", contribution.toString())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showLongToast(context, R.string.this_function_needs_network_connection)
|
context?.let { showLongToast(it, R.string.this_function_needs_network_connection) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,11 @@ class ContributionsPresenter @Inject internal constructor(
|
||||||
.save(contribution)
|
.save(contribution)
|
||||||
.subscribeOn(ioThreadScheduler)
|
.subscribeOn(ioThreadScheduler)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
|
view!!.getContext()?.applicationContext?.let {
|
||||||
makeOneTimeWorkRequest(
|
makeOneTimeWorkRequest(
|
||||||
view!!.getContext().applicationContext, ExistingWorkPolicy.KEEP
|
it, ExistingWorkPolicy.KEEP
|
||||||
)
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ class DBOpenHelper(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DATABASE_NAME = "commons.db"
|
private const val DATABASE_NAME = "commons.db"
|
||||||
private const val DATABASE_VERSION = 21
|
private const val DATABASE_VERSION = 22
|
||||||
const val CONTRIBUTIONS_TABLE = "contributions"
|
const val CONTRIBUTIONS_TABLE = "contributions"
|
||||||
|
const val BOOKMARKS_LOCATIONS = "bookmarksLocations"
|
||||||
private const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS %s"
|
private const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS %s"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +31,6 @@ class DBOpenHelper(
|
||||||
override fun onCreate(db: SQLiteDatabase) {
|
override fun onCreate(db: SQLiteDatabase) {
|
||||||
CategoryDao.Table.onCreate(db)
|
CategoryDao.Table.onCreate(db)
|
||||||
BookmarkPicturesDao.Table.onCreate(db)
|
BookmarkPicturesDao.Table.onCreate(db)
|
||||||
BookmarkLocationsDao.Table.onCreate(db)
|
|
||||||
BookmarkItemsDao.Table.onCreate(db)
|
BookmarkItemsDao.Table.onCreate(db)
|
||||||
RecentSearchesDao.Table.onCreate(db)
|
RecentSearchesDao.Table.onCreate(db)
|
||||||
RecentLanguagesDao.Table.onCreate(db)
|
RecentLanguagesDao.Table.onCreate(db)
|
||||||
|
|
@ -39,11 +39,11 @@ class DBOpenHelper(
|
||||||
override fun onUpgrade(db: SQLiteDatabase, from: Int, to: Int) {
|
override fun onUpgrade(db: SQLiteDatabase, from: Int, to: Int) {
|
||||||
CategoryDao.Table.onUpdate(db, from, to)
|
CategoryDao.Table.onUpdate(db, from, to)
|
||||||
BookmarkPicturesDao.Table.onUpdate(db, from, to)
|
BookmarkPicturesDao.Table.onUpdate(db, from, to)
|
||||||
BookmarkLocationsDao.Table.onUpdate(db, from, to)
|
|
||||||
BookmarkItemsDao.Table.onUpdate(db, from, to)
|
BookmarkItemsDao.Table.onUpdate(db, from, to)
|
||||||
RecentSearchesDao.Table.onUpdate(db, from, to)
|
RecentSearchesDao.Table.onUpdate(db, from, to)
|
||||||
RecentLanguagesDao.Table.onUpdate(db, from, to)
|
RecentLanguagesDao.Table.onUpdate(db, from, to)
|
||||||
deleteTable(db, CONTRIBUTIONS_TABLE)
|
deleteTable(db, CONTRIBUTIONS_TABLE)
|
||||||
|
deleteTable(db, BOOKMARKS_LOCATIONS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
package fr.free.nrw.commons.db
|
package fr.free.nrw.commons.db
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.TypeConverters
|
import androidx.room.TypeConverters
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||||
import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
|
import fr.free.nrw.commons.bookmarks.category.BookmarksCategoryModal
|
||||||
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
|
import fr.free.nrw.commons.bookmarks.locations.BookmarksLocations
|
||||||
import fr.free.nrw.commons.contributions.Contribution
|
import fr.free.nrw.commons.contributions.Contribution
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao
|
import fr.free.nrw.commons.contributions.ContributionDao
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||||
|
|
@ -23,8 +29,8 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Database(
|
@Database(
|
||||||
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class],
|
entities = [Contribution::class, Depicts::class, UploadedStatus::class, NotForUploadStatus::class, ReviewEntity::class, Place::class, BookmarksCategoryModal::class, BookmarksLocations::class],
|
||||||
version = 19,
|
version = 20,
|
||||||
exportSchema = false,
|
exportSchema = false,
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
|
|
@ -42,4 +48,6 @@ abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun ReviewDao(): ReviewDao
|
abstract fun ReviewDao(): ReviewDao
|
||||||
|
|
||||||
abstract fun bookmarkCategoriesDao(): BookmarkCategoriesDao
|
abstract fun bookmarkCategoriesDao(): BookmarkCategoriesDao
|
||||||
|
|
||||||
|
abstract fun bookmarkLocationsDao(): BookmarkLocationsDao
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ class DeleteHelper @Inject constructor(
|
||||||
|
|
||||||
val userPageString = "\n{{subst:idw|${media.filename}}} ~~~~"
|
val userPageString = "\n{{subst:idw|${media.filename}}} ~~~~"
|
||||||
|
|
||||||
val creator = media.author
|
val creator = media.getAuthorOrUser()
|
||||||
?: throw RuntimeException("Failed to nominate for deletion")
|
?: throw RuntimeException("Failed to nominate for deletion")
|
||||||
|
|
||||||
return pageEditClient.prependEdit(
|
return pageEditClient.prependEdit(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.app.Activity
|
||||||
import android.content.ContentProviderClient
|
import android.content.ContentProviderClient
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import androidx.collection.LruCache
|
import androidx.collection.LruCache
|
||||||
import androidx.room.Room.databaseBuilder
|
import androidx.room.Room.databaseBuilder
|
||||||
|
|
@ -16,6 +17,7 @@ import fr.free.nrw.commons.BuildConfig
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.auth.SessionManager
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesDao
|
||||||
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao
|
import fr.free.nrw.commons.contributions.ContributionDao
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||||
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
import fr.free.nrw.commons.customselector.database.UploadedStatusDao
|
||||||
|
|
@ -36,6 +38,7 @@ import fr.free.nrw.commons.wikidata.WikidataEditListenerImpl
|
||||||
import io.reactivex.Scheduler
|
import io.reactivex.Scheduler
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
@ -49,6 +52,11 @@ import javax.inject.Singleton
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
open class CommonsApplicationModule(private val applicationContext: Context) {
|
open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
appContext = applicationContext
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesImageFileLoader(context: Context): ImageFileLoader =
|
fun providesImageFileLoader(context: Context): ImageFileLoader =
|
||||||
ImageFileLoader(context)
|
ImageFileLoader(context)
|
||||||
|
|
@ -110,11 +118,6 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
fun provideBookmarkContentProviderClient(context: Context): ContentProviderClient? =
|
fun provideBookmarkContentProviderClient(context: Context): ContentProviderClient? =
|
||||||
context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_AUTHORITY)
|
context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_AUTHORITY)
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Named("bookmarksLocation")
|
|
||||||
fun provideBookmarkLocationContentProviderClient(context: Context): ContentProviderClient? =
|
|
||||||
context.contentResolver.acquireContentProviderClient(BuildConfig.BOOKMARK_LOCATIONS_AUTHORITY)
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named("bookmarksItem")
|
@Named("bookmarksItem")
|
||||||
fun provideBookmarkItemContentProviderClient(context: Context): ContentProviderClient? =
|
fun provideBookmarkItemContentProviderClient(context: Context): ContentProviderClient? =
|
||||||
|
|
@ -196,7 +199,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
applicationContext,
|
applicationContext,
|
||||||
AppDatabase::class.java,
|
AppDatabase::class.java,
|
||||||
"commons_room.db"
|
"commons_room.db"
|
||||||
).addMigrations(MIGRATION_1_2).fallbackToDestructiveMigration().build()
|
).addMigrations(
|
||||||
|
MIGRATION_1_2,
|
||||||
|
MIGRATION_19_TO_20
|
||||||
|
).fallbackToDestructiveMigration().build()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesContributionsDao(appDatabase: AppDatabase): ContributionDao =
|
fun providesContributionsDao(appDatabase: AppDatabase): ContributionDao =
|
||||||
|
|
@ -206,6 +212,10 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
fun providesPlaceDao(appDatabase: AppDatabase): PlaceDao =
|
fun providesPlaceDao(appDatabase: AppDatabase): PlaceDao =
|
||||||
appDatabase.PlaceDao()
|
appDatabase.PlaceDao()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesBookmarkLocationsDao(appDatabase: AppDatabase): BookmarkLocationsDao =
|
||||||
|
appDatabase.bookmarkLocationsDao()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun providesDepictDao(appDatabase: AppDatabase): DepictsDao =
|
fun providesDepictDao(appDatabase: AppDatabase): DepictsDao =
|
||||||
appDatabase.DepictsDao()
|
appDatabase.DepictsDao()
|
||||||
|
|
@ -239,6 +249,9 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
const val IO_THREAD: String = "io_thread"
|
const val IO_THREAD: String = "io_thread"
|
||||||
const val MAIN_THREAD: String = "main_thread"
|
const val MAIN_THREAD: String = "main_thread"
|
||||||
|
|
||||||
|
lateinit var appContext: Context
|
||||||
|
private set
|
||||||
|
|
||||||
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
|
val MIGRATION_1_2: Migration = object : Migration(1, 2) {
|
||||||
override fun migrate(db: SupportSQLiteDatabase) {
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
|
|
@ -246,5 +259,101 @@ open class CommonsApplicationModule(private val applicationContext: Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val MIGRATION_19_TO_20 = object : Migration(19, 20) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.execSQL(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS bookmarks_locations (
|
||||||
|
location_name TEXT NOT NULL PRIMARY KEY,
|
||||||
|
location_language TEXT NOT NULL,
|
||||||
|
location_description TEXT NOT NULL,
|
||||||
|
location_lat REAL NOT NULL,
|
||||||
|
location_long REAL NOT NULL,
|
||||||
|
location_category TEXT NOT NULL,
|
||||||
|
location_label_text TEXT NOT NULL,
|
||||||
|
location_label_icon INTEGER,
|
||||||
|
location_image_url TEXT NOT NULL DEFAULT '',
|
||||||
|
location_wikipedia_link TEXT NOT NULL,
|
||||||
|
location_wikidata_link TEXT NOT NULL,
|
||||||
|
location_commons_link TEXT NOT NULL,
|
||||||
|
location_pic TEXT NOT NULL,
|
||||||
|
location_exists INTEGER NOT NULL CHECK(location_exists IN (0, 1))
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
val oldDbPath = appContext.getDatabasePath("commons.db").path
|
||||||
|
val oldDb = SQLiteDatabase
|
||||||
|
.openDatabase(oldDbPath, null, SQLiteDatabase.OPEN_READONLY)
|
||||||
|
|
||||||
|
val cursor = oldDb.rawQuery("SELECT * FROM bookmarksLocations", null)
|
||||||
|
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
val locationName =
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow("location_name"))
|
||||||
|
val locationLanguage =
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow("location_language"))
|
||||||
|
val locationDescription =
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow("location_description"))
|
||||||
|
val locationCategory =
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow("location_category"))
|
||||||
|
val locationLabelText =
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow("location_label_text"))
|
||||||
|
val locationLabelIcon =
|
||||||
|
cursor.getInt(cursor.getColumnIndexOrThrow("location_label_icon"))
|
||||||
|
val locationLat =
|
||||||
|
cursor.getDouble(cursor.getColumnIndexOrThrow("location_lat"))
|
||||||
|
val locationLong =
|
||||||
|
cursor.getDouble(cursor.getColumnIndexOrThrow("location_long"))
|
||||||
|
|
||||||
|
// Handle NULL values safely
|
||||||
|
val locationImageUrl =
|
||||||
|
cursor.getString(
|
||||||
|
cursor.getColumnIndexOrThrow("location_image_url")
|
||||||
|
) ?: ""
|
||||||
|
val locationWikipediaLink =
|
||||||
|
cursor.getString(
|
||||||
|
cursor.getColumnIndexOrThrow("location_wikipedia_link")
|
||||||
|
) ?: ""
|
||||||
|
val locationWikidataLink =
|
||||||
|
cursor.getString(
|
||||||
|
cursor.getColumnIndexOrThrow("location_wikidata_link")
|
||||||
|
) ?: ""
|
||||||
|
val locationCommonsLink =
|
||||||
|
cursor.getString(
|
||||||
|
cursor.getColumnIndexOrThrow("location_commons_link")
|
||||||
|
) ?: ""
|
||||||
|
val locationPic =
|
||||||
|
cursor.getString(
|
||||||
|
cursor.getColumnIndexOrThrow("location_pic")
|
||||||
|
) ?: ""
|
||||||
|
val locationExists =
|
||||||
|
cursor.getInt(
|
||||||
|
cursor.getColumnIndexOrThrow("location_exists")
|
||||||
|
)
|
||||||
|
|
||||||
|
db.execSQL(
|
||||||
|
"""
|
||||||
|
INSERT OR REPLACE INTO bookmarks_locations (
|
||||||
|
location_name, location_language, location_description, location_category,
|
||||||
|
location_label_text, location_label_icon, location_lat, location_long,
|
||||||
|
location_image_url, location_wikipedia_link, location_wikidata_link,
|
||||||
|
location_commons_link, location_pic, location_exists
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
""",
|
||||||
|
arrayOf(
|
||||||
|
locationName, locationLanguage, locationDescription, locationCategory,
|
||||||
|
locationLabelText, locationLabelIcon, locationLat, locationLong,
|
||||||
|
locationImageUrl, locationWikipediaLink, locationWikidataLink,
|
||||||
|
locationCommonsLink, locationPic, locationExists
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
oldDb.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,4 @@ abstract class CommonsDaggerSupportFragment : Fragment(), HasSupportFragmentInje
|
||||||
|
|
||||||
return getInstance(activity.applicationContext)
|
return getInstance(activity.applicationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure getContext() returns a non-null Context
|
|
||||||
override fun getContext(): Context {
|
|
||||||
return super.getContext() ?: throw IllegalStateException("Context is null")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package fr.free.nrw.commons.di
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider
|
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsContentProvider
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider
|
|
||||||
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider
|
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider
|
||||||
import fr.free.nrw.commons.category.CategoryContentProvider
|
import fr.free.nrw.commons.category.CategoryContentProvider
|
||||||
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider
|
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesContentProvider
|
||||||
|
|
@ -26,9 +25,6 @@ abstract class ContentProviderBuilderModule {
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindBookmarkContentProvider(): BookmarkPicturesContentProvider
|
abstract fun bindBookmarkContentProvider(): BookmarkPicturesContentProvider
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
|
||||||
abstract fun bindBookmarkLocationContentProvider(): BookmarkLocationsContentProvider
|
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindBookmarkItemContentProvider(): BookmarkItemsContentProvider
|
abstract fun bindBookmarkItemContentProvider(): BookmarkItemsContentProvider
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class MediaConverter
|
||||||
metadata.licenseShortName(),
|
metadata.licenseShortName(),
|
||||||
metadata.prefixedLicenseUrl,
|
metadata.prefixedLicenseUrl,
|
||||||
getAuthor(metadata),
|
getAuthor(metadata),
|
||||||
getAuthor(metadata),
|
imageInfo.getUser(),
|
||||||
MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories()),
|
MediaDataExtractorUtil.extractCategoriesFromList(metadata.categories()),
|
||||||
metadata.latLng,
|
metadata.latLng,
|
||||||
entity.labels().mapValues { it.value.value() },
|
entity.labels().mapValues { it.value.value() },
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,7 @@ class SearchImagesViewHolder(
|
||||||
binding.categoryImageView.setOnClickListener { onImageClicked(item.second) }
|
binding.categoryImageView.setOnClickListener { onImageClicked(item.second) }
|
||||||
binding.categoryImageTitle.text = media.mostRelevantCaption
|
binding.categoryImageTitle.text = media.mostRelevantCaption
|
||||||
binding.categoryImageView.setImageURI(media.thumbUrl)
|
binding.categoryImageView.setImageURI(media.thumbUrl)
|
||||||
if (media.author?.isNotEmpty() == true) {
|
|
||||||
binding.categoryImageAuthor.visibility = View.VISIBLE
|
|
||||||
binding.categoryImageAuthor.text =
|
binding.categoryImageAuthor.text =
|
||||||
containerView.context.getString(R.string.image_uploaded_by, media.user)
|
containerView.context.getString(R.string.image_uploaded_by, media.getAuthorOrUser())
|
||||||
} else {
|
|
||||||
binding.categoryImageAuthor.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.ViewTreeObserver
|
||||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
|
@ -405,9 +406,14 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
|
||||||
* Gets the height of the frame layout as soon as the view is ready and updates aspect ratio
|
* Gets the height of the frame layout as soon as the view is ready and updates aspect ratio
|
||||||
* of the picture.
|
* of the picture.
|
||||||
*/
|
*/
|
||||||
view.post {
|
view.post{
|
||||||
|
val width = binding.mediaDetailScrollView.width
|
||||||
|
if (width > 0) {
|
||||||
frameLayoutHeight = binding.mediaDetailFrameLayout.measuredHeight
|
frameLayoutHeight = binding.mediaDetailFrameLayout.measuredHeight
|
||||||
updateAspectRatio(binding.mediaDetailScrollView.width)
|
updateAspectRatio(width)
|
||||||
|
} else {
|
||||||
|
view.postDelayed({ updateAspectRatio(binding.root.width) }, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
|
||||||
|
|
@ -185,10 +185,12 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
* or a fragment
|
* or a fragment
|
||||||
*/
|
*/
|
||||||
private void initProvider() {
|
private void initProvider() {
|
||||||
if (getParentFragment() != null) {
|
if (getParentFragment() instanceof MediaDetailProvider) {
|
||||||
provider = (MediaDetailProvider) getParentFragment();
|
provider = (MediaDetailProvider) getParentFragment();
|
||||||
} else {
|
} else if (getActivity() instanceof MediaDetailProvider) {
|
||||||
provider = (MediaDetailProvider) getActivity();
|
provider = (MediaDetailProvider) getActivity();
|
||||||
|
} else {
|
||||||
|
throw new ClassCastException("Parent must implement MediaDetailProvider");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,7 +328,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
.append("\n\n");
|
.append("\n\n");
|
||||||
|
|
||||||
builder.append("User that you want to report: ")
|
builder.append("User that you want to report: ")
|
||||||
.append(media.getAuthor())
|
.append(media.getUser())
|
||||||
.append("\n\n");
|
.append("\n\n");
|
||||||
|
|
||||||
if (sessionManager.getUserName() != null) {
|
if (sessionManager.getUserName() != null) {
|
||||||
|
|
@ -421,7 +423,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
||||||
// Initialize bookmark object
|
// Initialize bookmark object
|
||||||
bookmark = new Bookmark(
|
bookmark = new Bookmark(
|
||||||
m.getFilename(),
|
m.getFilename(),
|
||||||
m.getAuthor(),
|
m.getAuthorOrUser(),
|
||||||
BookmarkPicturesContentProvider.uriForName(m.getFilename())
|
BookmarkPicturesContentProvider.uriForName(m.getFilename())
|
||||||
);
|
);
|
||||||
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image));
|
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image));
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,21 @@ class BottomSheetAdapter(
|
||||||
item.imageResourceId == R.drawable.ic_round_star_border_24px
|
item.imageResourceId == R.drawable.ic_round_star_border_24px
|
||||||
) {
|
) {
|
||||||
item.imageResourceId = icon
|
item.imageResourceId = icon
|
||||||
this.notifyItemChanged(index)
|
notifyItemChanged(index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleBookmarkIcon() {
|
||||||
|
itemList.forEachIndexed { index, item ->
|
||||||
|
if(item.imageResourceId == R.drawable.ic_round_star_filled_24px) {
|
||||||
|
item.imageResourceId = R.drawable.ic_round_star_border_24px
|
||||||
|
notifyItemChanged(index)
|
||||||
|
return
|
||||||
|
} else if(item.imageResourceId == R.drawable.ic_round_star_border_24px){
|
||||||
|
item.imageResourceId = R.drawable.ic_round_star_filled_24px
|
||||||
|
notifyItemChanged(index)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
app/src/main/java/fr/free/nrw/commons/nearby/NearbyUtil.kt
Normal file
28
app/src/main/java/fr/free/nrw/commons/nearby/NearbyUtil.kt
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package fr.free.nrw.commons.nearby
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
object NearbyUtil {
|
||||||
|
|
||||||
|
fun getBookmarkLocationExists(
|
||||||
|
bookmarksLocationsDao: BookmarkLocationsDao,
|
||||||
|
name: String,
|
||||||
|
scope: LifecycleCoroutineScope?,
|
||||||
|
bottomSheetAdapter: BottomSheetAdapter,
|
||||||
|
) {
|
||||||
|
scope?.launch {
|
||||||
|
val isBookmarked = bookmarksLocationsDao.findBookmarkLocation(name)
|
||||||
|
Timber.i("isBookmarked: $isBookmarked")
|
||||||
|
if (isBookmarked) {
|
||||||
|
bottomSheetAdapter.updateBookmarkIcon(R.drawable.ic_round_star_filled_24px)
|
||||||
|
} else {
|
||||||
|
bottomSheetAdapter.updateBookmarkIcon(R.drawable.ic_round_star_border_24px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import android.view.View.INVISIBLE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
|
|
@ -16,9 +17,11 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
import fr.free.nrw.commons.databinding.ItemPlaceBinding
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
fun placeAdapterDelegate(
|
fun placeAdapterDelegate(
|
||||||
bookmarkLocationDao: BookmarkLocationsDao,
|
bookmarkLocationDao: BookmarkLocationsDao,
|
||||||
|
scope: LifecycleCoroutineScope?,
|
||||||
onItemClick: ((Place) -> Unit)? = null,
|
onItemClick: ((Place) -> Unit)? = null,
|
||||||
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
|
onCameraClicked: (Place, ActivityResultLauncher<Array<String>>, ActivityResultLauncher<Intent>) -> Unit,
|
||||||
onCameraLongPressed: () -> Boolean,
|
onCameraLongPressed: () -> Boolean,
|
||||||
|
|
@ -61,7 +64,10 @@ fun placeAdapterDelegate(
|
||||||
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) }
|
nearbyButtonLayout.galleryButton.setOnClickListener { onGalleryClicked(item, galleryPickLauncherForResult) }
|
||||||
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
nearbyButtonLayout.galleryButton.setOnLongClickListener { onGalleryLongPressed() }
|
||||||
bookmarkButtonImage.setOnClickListener {
|
bookmarkButtonImage.setOnClickListener {
|
||||||
val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
var isBookmarked = false
|
||||||
|
scope?.launch {
|
||||||
|
isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item)
|
||||||
|
}
|
||||||
bookmarkButtonImage.setImageResource(
|
bookmarkButtonImage.setImageResource(
|
||||||
if (isBookmarked) R.drawable.ic_round_star_filled_24px else R.drawable.ic_round_star_border_24px,
|
if (isBookmarked) R.drawable.ic_round_star_filled_24px else R.drawable.ic_round_star_border_24px,
|
||||||
)
|
)
|
||||||
|
|
@ -93,14 +99,16 @@ fun placeAdapterDelegate(
|
||||||
GONE
|
GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope?.launch {
|
||||||
bookmarkButtonImage.setImageResource(
|
bookmarkButtonImage.setImageResource(
|
||||||
if (bookmarkLocationDao.findBookmarkLocation(item)) {
|
if (bookmarkLocationDao.findBookmarkLocation(item.name)) {
|
||||||
R.drawable.ic_round_star_filled_24px
|
R.drawable.ic_round_star_filled_24px
|
||||||
} else {
|
} else {
|
||||||
R.drawable.ic_round_star_border_24px
|
R.drawable.ic_round_star_border_24px
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
nearbyButtonLayout.directionsButton.setOnLongClickListener { onDirectionsLongPressed() }
|
nearbyButtonLayout.directionsButton.setOnLongClickListener { onDirectionsLongPressed() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ public interface NearbyParentFragmentContract {
|
||||||
|
|
||||||
void setAdvancedQuery(String query);
|
void setAdvancedQuery(String query);
|
||||||
|
|
||||||
void toggleBookmarkedStatus(Place place);
|
void toggleBookmarkedStatus(Place place, LifecycleCoroutineScope scope);
|
||||||
|
|
||||||
void handleMapScrolled(LifecycleCoroutineScope scope, boolean isNetworkAvailable);
|
void handleMapScrolled(LifecycleCoroutineScope scope, boolean isNetworkAvailable);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,16 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.engine.GlideException
|
||||||
|
import com.bumptech.glide.request.RequestListener
|
||||||
|
import com.bumptech.glide.request.target.Target
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
|
@ -51,6 +56,7 @@ import com.jakewharton.rxbinding2.view.RxView
|
||||||
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||||
import fr.free.nrw.commons.CommonsApplication
|
import fr.free.nrw.commons.CommonsApplication
|
||||||
import fr.free.nrw.commons.MapController.NearbyPlacesInfo
|
import fr.free.nrw.commons.MapController.NearbyPlacesInfo
|
||||||
|
import fr.free.nrw.commons.Media
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.Utils
|
import fr.free.nrw.commons.Utils
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
|
|
@ -67,6 +73,10 @@ import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermission
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager
|
import fr.free.nrw.commons.location.LocationServiceManager
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
||||||
import fr.free.nrw.commons.location.LocationUpdateListener
|
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
|
||||||
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
|
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
|
||||||
import fr.free.nrw.commons.nearby.CheckBoxTriStates
|
import fr.free.nrw.commons.nearby.CheckBoxTriStates
|
||||||
|
|
@ -75,6 +85,7 @@ import fr.free.nrw.commons.nearby.MarkerPlaceGroup
|
||||||
import fr.free.nrw.commons.nearby.NearbyController
|
import fr.free.nrw.commons.nearby.NearbyController
|
||||||
import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter
|
import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter
|
||||||
import fr.free.nrw.commons.nearby.NearbyFilterState
|
import fr.free.nrw.commons.nearby.NearbyFilterState
|
||||||
|
import fr.free.nrw.commons.nearby.NearbyUtil
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
import fr.free.nrw.commons.nearby.PlacesRepository
|
import fr.free.nrw.commons.nearby.PlacesRepository
|
||||||
import fr.free.nrw.commons.nearby.WikidataFeedback
|
import fr.free.nrw.commons.nearby.WikidataFeedback
|
||||||
|
|
@ -118,17 +129,26 @@ import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.UUID
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
|
import javax.sql.DataSource
|
||||||
import kotlin.concurrent.Volatile
|
import kotlin.concurrent.Volatile
|
||||||
|
|
||||||
|
|
||||||
class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmentContract.View,
|
class NearbyParentFragment : CommonsDaggerSupportFragment(),
|
||||||
WikidataP18EditListener, LocationUpdateListener, LocationPermissionCallback, ItemClickListener {
|
NearbyParentFragmentContract.View,
|
||||||
|
WikidataP18EditListener,
|
||||||
|
LocationUpdateListener,
|
||||||
|
LocationPermissionCallback,
|
||||||
|
ItemClickListener,
|
||||||
|
MediaDetailPagerFragment.MediaDetailProvider {
|
||||||
var binding: FragmentNearbyParentBinding? = null
|
var binding: FragmentNearbyParentBinding? = null
|
||||||
|
|
||||||
val mapEventsOverlay: MapEventsOverlay = MapEventsOverlay(object : MapEventsReceiver {
|
val mapEventsOverlay: MapEventsOverlay = MapEventsOverlay(object : MapEventsReceiver {
|
||||||
|
|
@ -163,6 +183,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
@Named("default_preferences")
|
@Named("default_preferences")
|
||||||
lateinit var applicationKvStore: JsonKvStore
|
lateinit var applicationKvStore: JsonKvStore
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var mediaClient: MediaClient
|
||||||
|
|
||||||
|
lateinit var mediaDetails: MediaDetailPagerFragment
|
||||||
|
|
||||||
|
lateinit var media: Media
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var bookmarkLocationDao: BookmarkLocationsDao
|
lateinit var bookmarkLocationDao: BookmarkLocationsDao
|
||||||
|
|
||||||
|
|
@ -196,7 +223,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
private var view: View? = null
|
private var view: View? = null
|
||||||
private var scope: LifecycleCoroutineScope? = null
|
private var scope: LifecycleCoroutineScope? = null
|
||||||
private var presenter: NearbyParentFragmentPresenter? = null
|
private var presenter: NearbyParentFragmentPresenter? = null
|
||||||
private var isDarkTheme = false
|
private var _isDarkTheme = false
|
||||||
private var isFABsExpanded = false
|
private var isFABsExpanded = false
|
||||||
private var selectedPlace: Place? = null
|
private var selectedPlace: Place? = null
|
||||||
private var clickedMarker: Marker? = null
|
private var clickedMarker: Marker? = null
|
||||||
|
|
@ -434,7 +461,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isDarkTheme = systemThemeUtils?.isDeviceInNightMode() == true
|
_isDarkTheme = systemThemeUtils?.isDeviceInNightMode() == true
|
||||||
if (Utils.isMonumentsEnabled(Date())) {
|
if (Utils.isMonumentsEnabled(Date())) {
|
||||||
binding?.rlContainerWlmMonthMessage?.visibility = View.VISIBLE
|
binding?.rlContainerWlmMonthMessage?.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -604,7 +631,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
* another refactor
|
* another refactor
|
||||||
*/
|
*/
|
||||||
private fun initThemePreferences() {
|
private fun initThemePreferences() {
|
||||||
if (isDarkTheme) {
|
if (_isDarkTheme) {
|
||||||
binding!!.bottomSheetNearby.rvNearbyList.setBackgroundColor(
|
binding!!.bottomSheetNearby.rvNearbyList.setBackgroundColor(
|
||||||
requireContext().resources.getColor(fr.free.nrw.commons.R.color.contributionListDarkBackground)
|
requireContext().resources.getColor(fr.free.nrw.commons.R.color.contributionListDarkBackground)
|
||||||
)
|
)
|
||||||
|
|
@ -638,21 +665,23 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
private fun initRvNearbyList() {
|
private fun initRvNearbyList() {
|
||||||
binding!!.bottomSheetNearby.rvNearbyList.layoutManager = LinearLayoutManager(context)
|
binding!!.bottomSheetNearby.rvNearbyList.layoutManager = LinearLayoutManager(context)
|
||||||
adapter = PlaceAdapter(
|
adapter = PlaceAdapter(
|
||||||
bookmarkLocationDao!!,
|
bookmarkLocationsDao = bookmarkLocationDao,
|
||||||
{ place: Place ->
|
scope = scope,
|
||||||
|
onPlaceClicked = { place: Place ->
|
||||||
moveCameraToPosition(
|
moveCameraToPosition(
|
||||||
GeoPoint(place.location.latitude, place.location.longitude)
|
GeoPoint(
|
||||||
|
place.location.latitude,
|
||||||
|
place.location.longitude
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Unit
|
|
||||||
},
|
},
|
||||||
{ place: Place?, isBookmarked: Boolean? ->
|
onBookmarkClicked = { place: Place?, _: Boolean? ->
|
||||||
presenter!!.toggleBookmarkedStatus(place)
|
presenter!!.toggleBookmarkedStatus(place, scope)
|
||||||
Unit
|
|
||||||
},
|
},
|
||||||
commonPlaceClickActions!!,
|
commonPlaceClickActions = commonPlaceClickActions,
|
||||||
inAppCameraLocationPermissionLauncher,
|
inAppCameraLocationPermissionLauncher = inAppCameraLocationPermissionLauncher,
|
||||||
galleryPickLauncherForResult,
|
galleryPickLauncherForResult = galleryPickLauncherForResult,
|
||||||
cameraPickLauncherForResult
|
cameraPickLauncherForResult = cameraPickLauncherForResult
|
||||||
)
|
)
|
||||||
binding!!.bottomSheetNearby.rvNearbyList.adapter = adapter
|
binding!!.bottomSheetNearby.rvNearbyList.adapter = adapter
|
||||||
}
|
}
|
||||||
|
|
@ -716,6 +745,10 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
presenter?.attachView(this)
|
presenter?.attachView(this)
|
||||||
registerNetworkReceiver()
|
registerNetworkReceiver()
|
||||||
|
|
||||||
|
binding?.coordinatorLayout?.visibility = View.VISIBLE
|
||||||
|
binding?.map?.setMultiTouchControls(true)
|
||||||
|
binding?.map?.isClickable = true
|
||||||
|
|
||||||
if (isResumed && (activity as? MainActivity)?.activeFragment == ActiveFragment.NEARBY) {
|
if (isResumed && (activity as? MainActivity)?.activeFragment == ActiveFragment.NEARBY) {
|
||||||
if (activity?.let { locationPermissionsHelper?.checkLocationPermission(it) } == true) {
|
if (activity?.let { locationPermissionsHelper?.checkLocationPermission(it) } == true) {
|
||||||
locationPermissionGranted()
|
locationPermissionGranted()
|
||||||
|
|
@ -882,7 +915,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isDarkTheme(): Boolean {
|
override fun isDarkTheme(): Boolean {
|
||||||
return isDarkTheme
|
return _isDarkTheme
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
binding!!.nearbyFilterList.root
|
binding!!.nearbyFilterList.root
|
||||||
|
|
@ -1853,7 +1886,31 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
|
|
||||||
fun backButtonClicked(): Boolean {
|
fun backButtonClicked(): Boolean {
|
||||||
return presenter!!.backButtonClicked()
|
if (::mediaDetails.isInitialized && mediaDetails.isVisible) {
|
||||||
|
removeFragment(mediaDetails)
|
||||||
|
|
||||||
|
binding?.coordinatorLayout?.visibility = View.VISIBLE
|
||||||
|
binding?.map?.setMultiTouchControls(true)
|
||||||
|
binding?.map?.isClickable = true
|
||||||
|
|
||||||
|
val transaction = childFragmentManager.beginTransaction()
|
||||||
|
val fragmentContainer = childFragmentManager.findFragmentById(R.id.coordinator_layout)
|
||||||
|
|
||||||
|
if (fragmentContainer != null) {
|
||||||
|
transaction.show(fragmentContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.commit()
|
||||||
|
childFragmentManager.executePendingTransactions()
|
||||||
|
|
||||||
|
(activity as? MainActivity)?.showTabs()
|
||||||
|
(activity as? MainActivity)?.supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
(activity as? MainActivity)?.setSelectedItemId(NavTab.NEARBY.code())
|
||||||
|
}
|
||||||
|
|
||||||
|
return presenter?.backButtonClicked() ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLocationPermissionDenied(toastMessage: String) {
|
override fun onLocationPermissionDenied(toastMessage: String) {
|
||||||
|
|
@ -2249,34 +2306,34 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
// TODO: Decide button text for fitting in the screen
|
// TODO: Decide button text for fitting in the screen
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px,
|
R.drawable.ic_round_star_border_24px,
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp,
|
R.drawable.ic_directions_black_24dp,
|
||||||
resources.getString(fr.free.nrw.commons.R.string.nearby_directions)
|
resources.getString(fr.free.nrw.commons.R.string.nearby_directions)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (place.hasWikidataLink()) {
|
if (place.hasWikidataLink()) {
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp,
|
R.drawable.ic_wikidata_logo_24dp,
|
||||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
resources.getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp,
|
R.drawable.ic_feedback_black_24dp,
|
||||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
resources.getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (place.hasWikipediaLink()) {
|
if (place.hasWikipediaLink()) {
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp,
|
R.drawable.ic_wikipedia_logo_24dp,
|
||||||
resources.getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
resources.getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -2284,7 +2341,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
if (selectedPlace!!.hasCommonsLink()) {
|
if (selectedPlace!!.hasCommonsLink()) {
|
||||||
(dataList as ArrayList<BottomSheetItem>).add(
|
(dataList as ArrayList<BottomSheetItem>).add(
|
||||||
BottomSheetItem(
|
BottomSheetItem(
|
||||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector,
|
R.drawable.ic_commons_icon_vector,
|
||||||
resources.getString(fr.free.nrw.commons.R.string.nearby_commons)
|
resources.getString(fr.free.nrw.commons.R.string.nearby_commons)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -2299,7 +2356,61 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
bottomSheetAdapter!!.setClickListener(this)
|
bottomSheetAdapter!!.setClickListener(this)
|
||||||
binding!!.bottomSheetDetails.bottomSheetRecyclerView.adapter = bottomSheetAdapter
|
binding!!.bottomSheetDetails.bottomSheetRecyclerView.adapter = bottomSheetAdapter
|
||||||
updateBookmarkButtonImage(selectedPlace!!)
|
updateBookmarkButtonImage(selectedPlace!!)
|
||||||
|
|
||||||
|
selectedPlace?.pic?.substringAfterLast("/")?.takeIf { it.isNotEmpty() }?.let { imageName ->
|
||||||
|
Glide.with(binding!!.bottomSheetDetails.icon.context)
|
||||||
|
.clear(binding!!.bottomSheetDetails.icon)
|
||||||
|
|
||||||
|
val loadingDrawable = ContextCompat.getDrawable(
|
||||||
|
binding!!.bottomSheetDetails.icon.context,
|
||||||
|
R.drawable.loading_icon
|
||||||
|
)
|
||||||
|
val animation = AnimationUtils.loadAnimation(
|
||||||
|
binding!!.bottomSheetDetails.icon.context,
|
||||||
|
R.anim.rotate
|
||||||
|
)
|
||||||
|
|
||||||
|
Glide.with(binding!!.bottomSheetDetails.icon.context)
|
||||||
|
.load("https://commons.wikimedia.org/wiki/Special:Redirect/file/$imageName?width=25")
|
||||||
|
.placeholder(loadingDrawable)
|
||||||
|
.error(selectedPlace!!.label.icon)
|
||||||
|
.listener(object : RequestListener<Drawable> {
|
||||||
|
override fun onLoadFailed(
|
||||||
|
e: GlideException?,
|
||||||
|
model: Any?,
|
||||||
|
target: Target<Drawable>,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
binding!!.bottomSheetDetails.icon.clearAnimation()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResourceReady(
|
||||||
|
resource: Drawable,
|
||||||
|
model: Any,
|
||||||
|
target: Target<Drawable>?,
|
||||||
|
dataSource: com.bumptech.glide.load.DataSource,
|
||||||
|
isFirstResource: Boolean
|
||||||
|
): Boolean {
|
||||||
|
binding!!.bottomSheetDetails.icon.clearAnimation()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into(binding!!.bottomSheetDetails.icon)
|
||||||
|
|
||||||
|
if (binding!!.bottomSheetDetails.icon.drawable != null && binding!!.bottomSheetDetails.icon.drawable.constantState == loadingDrawable?.constantState) {
|
||||||
|
binding!!.bottomSheetDetails.icon.startAnimation(animation)
|
||||||
|
} else {
|
||||||
|
binding!!.bottomSheetDetails.icon.clearAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding!!.bottomSheetDetails.icon.setOnClickListener {
|
||||||
|
handleMediaClick(imageName)
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
binding!!.bottomSheetDetails.icon.setImageResource(selectedPlace!!.label.icon)
|
binding!!.bottomSheetDetails.icon.setImageResource(selectedPlace!!.label.icon)
|
||||||
|
}
|
||||||
|
|
||||||
binding!!.bottomSheetDetails.title.text = selectedPlace!!.name
|
binding!!.bottomSheetDetails.title.text = selectedPlace!!.name
|
||||||
binding!!.bottomSheetDetails.category.text = selectedPlace!!.distance
|
binding!!.bottomSheetDetails.category.text = selectedPlace!!.distance
|
||||||
// Remove label since it is double information
|
// Remove label since it is double information
|
||||||
|
|
@ -2354,6 +2465,101 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleMediaClick(imageName: String) {
|
||||||
|
val decodedImageName = URLDecoder.decode(imageName, StandardCharsets.UTF_8.toString())
|
||||||
|
|
||||||
|
mediaClient.getMedia("File:$decodedImageName")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ mediaResponse ->
|
||||||
|
if (mediaResponse != null) {
|
||||||
|
// Create a Media object from the response
|
||||||
|
media = Media(
|
||||||
|
pageId = mediaResponse.pageId ?: UUID.randomUUID().toString(),
|
||||||
|
thumbUrl = mediaResponse.thumbUrl,
|
||||||
|
imageUrl = mediaResponse.imageUrl,
|
||||||
|
filename = mediaResponse.filename,
|
||||||
|
fallbackDescription = mediaResponse.fallbackDescription,
|
||||||
|
dateUploaded = mediaResponse.dateUploaded,
|
||||||
|
license = mediaResponse.license,
|
||||||
|
licenseUrl = mediaResponse.licenseUrl,
|
||||||
|
author = mediaResponse.author,
|
||||||
|
user = mediaResponse.user,
|
||||||
|
categories = mediaResponse.categories,
|
||||||
|
coordinates = mediaResponse.coordinates,
|
||||||
|
captions = mediaResponse.captions ?: emptyMap(),
|
||||||
|
descriptions = mediaResponse.descriptions ?: emptyMap(),
|
||||||
|
depictionIds = mediaResponse.depictionIds ?: emptyList(),
|
||||||
|
categoriesHiddenStatus = mediaResponse.categoriesHiddenStatus ?: emptyMap()
|
||||||
|
)
|
||||||
|
// Remove existing fragment before showing new details
|
||||||
|
if (::mediaDetails.isInitialized && mediaDetails.isAdded) {
|
||||||
|
removeFragment(mediaDetails)
|
||||||
|
}
|
||||||
|
showMediaDetails()
|
||||||
|
} else {
|
||||||
|
Timber.e("Fetched media is null for image: $decodedImageName")
|
||||||
|
}
|
||||||
|
}, { throwable ->
|
||||||
|
Timber.e(throwable, "Error fetching media for image: $decodedImageName")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showMediaDetails() {
|
||||||
|
binding?.map?.setMultiTouchControls(false)
|
||||||
|
binding?.map?.isClickable = false
|
||||||
|
|
||||||
|
mediaDetails = MediaDetailPagerFragment.newInstance(false, true)
|
||||||
|
|
||||||
|
|
||||||
|
val transaction = childFragmentManager.beginTransaction()
|
||||||
|
|
||||||
|
val fragmentContainer = childFragmentManager.findFragmentById(R.id.coordinator_layout)
|
||||||
|
if (fragmentContainer != null) {
|
||||||
|
transaction.hide(fragmentContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace instead of add to ensure new fragment is used
|
||||||
|
transaction.replace(R.id.coordinator_layout, mediaDetails, "MediaDetailFragmentTag")
|
||||||
|
transaction.addToBackStack("Nearby_Parent_Fragment_Tag").commit()
|
||||||
|
childFragmentManager.executePendingTransactions()
|
||||||
|
|
||||||
|
(activity as? MainActivity)?.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
if (mediaDetails.isAdded) {
|
||||||
|
mediaDetails.showImage(0)
|
||||||
|
} else {
|
||||||
|
Timber.e("Error: MediaDetailPagerFragment is NOT added")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMediaAtPosition(i: Int): Media? {
|
||||||
|
return media
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTotalMediaCount(): Int {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getContributionStateAt(position: Int): Int? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun refreshNominatedMedia(index: Int) {
|
||||||
|
if (this::mediaDetails.isInitialized && !binding?.map?.isClickable!! == true) {
|
||||||
|
removeFragment(mediaDetails)
|
||||||
|
showMediaDetails()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeFragment(fragment: Fragment) {
|
||||||
|
childFragmentManager
|
||||||
|
.beginTransaction()
|
||||||
|
.remove(fragment)
|
||||||
|
.commit()
|
||||||
|
childFragmentManager.executePendingTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
private fun storeSharedPrefs(selectedPlace: Place) {
|
private fun storeSharedPrefs(selectedPlace: Place) {
|
||||||
applicationKvStore!!.putJson<Place>(WikidataConstants.PLACE_OBJECT, selectedPlace)
|
applicationKvStore!!.putJson<Place>(WikidataConstants.PLACE_OBJECT, selectedPlace)
|
||||||
val place =
|
val place =
|
||||||
|
|
@ -2363,12 +2569,16 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBookmarkButtonImage(place: Place) {
|
private fun updateBookmarkButtonImage(place: Place) {
|
||||||
val bookmarkIcon = if (bookmarkLocationDao!!.findBookmarkLocation(place)) {
|
NearbyUtil.getBookmarkLocationExists(
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px
|
bookmarkLocationDao,
|
||||||
} else {
|
place.getName(),
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px
|
scope,
|
||||||
|
bottomSheetAdapter!!
|
||||||
|
)
|
||||||
}
|
}
|
||||||
bottomSheetAdapter!!.updateBookmarkIcon(bookmarkIcon)
|
|
||||||
|
private fun toggleBookmarkButtonImage() {
|
||||||
|
bottomSheetAdapter?.toggleBookmarkIcon()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
|
|
@ -2546,26 +2756,31 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
override fun onBottomSheetItemClick(view: View?, position: Int) {
|
override fun onBottomSheetItemClick(view: View?, position: Int) {
|
||||||
val item = dataList?.get(position) ?: return // Null check for dataList
|
val item = dataList?.get(position) ?: return // Null check for dataList
|
||||||
when (item.imageResourceId) {
|
when (item.imageResourceId) {
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px,
|
R.drawable.ic_round_star_border_24px -> {
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px -> {
|
presenter?.toggleBookmarkedStatus(selectedPlace, scope)
|
||||||
presenter?.toggleBookmarkedStatus(selectedPlace)
|
toggleBookmarkButtonImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
R.drawable.ic_round_star_filled_24px -> {
|
||||||
|
presenter?.toggleBookmarkedStatus(selectedPlace, scope)
|
||||||
|
toggleBookmarkButtonImage()
|
||||||
selectedPlace?.let { updateBookmarkButtonImage(it) }
|
selectedPlace?.let { updateBookmarkButtonImage(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp -> {
|
R.drawable.ic_directions_black_24dp -> {
|
||||||
selectedPlace?.let {
|
selectedPlace?.let {
|
||||||
Utils.handleGeoCoordinates(this.context, it.getLocation())
|
Utils.handleGeoCoordinates(this.context, it.getLocation())
|
||||||
binding?.map?.zoomLevelDouble ?: 0.0
|
binding?.map?.zoomLevelDouble ?: 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp -> {
|
R.drawable.ic_wikidata_logo_24dp -> {
|
||||||
selectedPlace?.siteLinks?.wikidataLink?.let {
|
selectedPlace?.siteLinks?.wikidataLink?.let {
|
||||||
Utils.handleWebUrl(this.context, it)
|
Utils.handleWebUrl(this.context, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp -> {
|
R.drawable.ic_feedback_black_24dp -> {
|
||||||
selectedPlace?.let {
|
selectedPlace?.let {
|
||||||
val intent = Intent(this.context, WikidataFeedback::class.java).apply {
|
val intent = Intent(this.context, WikidataFeedback::class.java).apply {
|
||||||
putExtra("lat", it.location.latitude)
|
putExtra("lat", it.location.latitude)
|
||||||
|
|
@ -2577,13 +2792,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp -> {
|
R.drawable.ic_wikipedia_logo_24dp -> {
|
||||||
selectedPlace?.siteLinks?.wikipediaLink?.let {
|
selectedPlace?.siteLinks?.wikipediaLink?.let {
|
||||||
Utils.handleWebUrl(this.context, it)
|
Utils.handleWebUrl(this.context, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector -> {
|
R.drawable.ic_commons_icon_vector -> {
|
||||||
selectedPlace?.siteLinks?.commonsLink?.let {
|
selectedPlace?.siteLinks?.commonsLink?.let {
|
||||||
Utils.handleWebUrl(this.context, it)
|
Utils.handleWebUrl(this.context, it)
|
||||||
}
|
}
|
||||||
|
|
@ -2597,13 +2812,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(), NearbyParentFragmen
|
||||||
override fun onBottomSheetItemLongClick(view: View?, position: Int) {
|
override fun onBottomSheetItemLongClick(view: View?, position: Int) {
|
||||||
val item = dataList!![position]
|
val item = dataList!![position]
|
||||||
val message = when (item.imageResourceId) {
|
val message = when (item.imageResourceId) {
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_border_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
R.drawable.ic_round_star_border_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||||
fr.free.nrw.commons.R.drawable.ic_round_star_filled_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
R.drawable.ic_round_star_filled_24px -> getString(fr.free.nrw.commons.R.string.menu_bookmark)
|
||||||
fr.free.nrw.commons.R.drawable.ic_directions_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_directions)
|
R.drawable.ic_directions_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_directions)
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikidata_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
R.drawable.ic_wikidata_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikidata)
|
||||||
fr.free.nrw.commons.R.drawable.ic_feedback_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
R.drawable.ic_feedback_black_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikitalk)
|
||||||
fr.free.nrw.commons.R.drawable.ic_wikipedia_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
R.drawable.ic_wikipedia_logo_24dp -> getString(fr.free.nrw.commons.R.string.nearby_wikipedia)
|
||||||
fr.free.nrw.commons.R.drawable.ic_commons_icon_vector -> getString(fr.free.nrw.commons.R.string.nearby_commons)
|
R.drawable.ic_commons_icon_vector -> getString(fr.free.nrw.commons.R.string.nearby_commons)
|
||||||
else -> "Long click"
|
else -> "Long click"
|
||||||
}
|
}
|
||||||
Toast.makeText(this.context, message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this.context, message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.nearby.fragments
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
import fr.free.nrw.commons.nearby.placeAdapterDelegate
|
import fr.free.nrw.commons.nearby.placeAdapterDelegate
|
||||||
|
|
@ -9,6 +10,7 @@ import fr.free.nrw.commons.upload.categories.BaseDelegateAdapter
|
||||||
|
|
||||||
class PlaceAdapter(
|
class PlaceAdapter(
|
||||||
bookmarkLocationsDao: BookmarkLocationsDao,
|
bookmarkLocationsDao: BookmarkLocationsDao,
|
||||||
|
scope: LifecycleCoroutineScope? = null,
|
||||||
onPlaceClicked: ((Place) -> Unit)? = null,
|
onPlaceClicked: ((Place) -> Unit)? = null,
|
||||||
onBookmarkClicked: (Place, Boolean) -> Unit,
|
onBookmarkClicked: (Place, Boolean) -> Unit,
|
||||||
commonPlaceClickActions: CommonPlaceClickActions,
|
commonPlaceClickActions: CommonPlaceClickActions,
|
||||||
|
|
@ -18,6 +20,7 @@ class PlaceAdapter(
|
||||||
) : BaseDelegateAdapter<Place>(
|
) : BaseDelegateAdapter<Place>(
|
||||||
placeAdapterDelegate(
|
placeAdapterDelegate(
|
||||||
bookmarkLocationsDao,
|
bookmarkLocationsDao,
|
||||||
|
scope,
|
||||||
onPlaceClicked,
|
onPlaceClicked,
|
||||||
commonPlaceClickActions.onCameraClicked(),
|
commonPlaceClickActions.onCameraClicked(),
|
||||||
commonPlaceClickActions.onCameraLongPressed(),
|
commonPlaceClickActions.onCameraLongPressed(),
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import kotlinx.coroutines.job
|
import kotlinx.coroutines.job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.internal.wait
|
import okhttp3.internal.wait
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -136,9 +137,14 @@ class NearbyParentFragmentPresenter
|
||||||
* @param place The place whose bookmarked status is to be toggled. If the place is `null`,
|
* @param place The place whose bookmarked status is to be toggled. If the place is `null`,
|
||||||
* the operation is skipped.
|
* the operation is skipped.
|
||||||
*/
|
*/
|
||||||
override fun toggleBookmarkedStatus(place: Place?) {
|
override fun toggleBookmarkedStatus(
|
||||||
|
place: Place?,
|
||||||
|
scope: LifecycleCoroutineScope?
|
||||||
|
) {
|
||||||
if (place == null) return
|
if (place == null) return
|
||||||
val nowBookmarked = bookmarkLocationDao.updateBookmarkLocation(place)
|
var nowBookmarked: Boolean
|
||||||
|
scope?.launch {
|
||||||
|
nowBookmarked = bookmarkLocationDao.updateBookmarkLocation(place)
|
||||||
bookmarkChangedPlaces.add(place)
|
bookmarkChangedPlaces.add(place)
|
||||||
val placeIndex =
|
val placeIndex =
|
||||||
NearbyController.markerLabelList.indexOfFirst { it.place.location == place.location }
|
NearbyController.markerLabelList.indexOfFirst { it.place.location == place.location }
|
||||||
|
|
@ -148,13 +154,14 @@ class NearbyParentFragmentPresenter
|
||||||
)
|
)
|
||||||
nearbyParentFragmentView.setFilterState()
|
nearbyParentFragmentView.setFilterState()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun attachView(view: NearbyParentFragmentContract.View) {
|
override fun attachView(view: NearbyParentFragmentContract.View) {
|
||||||
this.nearbyParentFragmentView = view
|
nearbyParentFragmentView = view
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun detachView() {
|
override fun detachView() {
|
||||||
this.nearbyParentFragmentView = DUMMY
|
nearbyParentFragmentView = DUMMY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeNearbyPreferences(applicationKvStore: JsonKvStore) {
|
override fun removeNearbyPreferences(applicationKvStore: JsonKvStore) {
|
||||||
|
|
@ -337,7 +344,7 @@ class NearbyParentFragmentPresenter
|
||||||
for (i in 0..updatedGroups.lastIndex) {
|
for (i in 0..updatedGroups.lastIndex) {
|
||||||
val repoPlace = placesRepository.fetchPlace(updatedGroups[i].place.entityID)
|
val repoPlace = placesRepository.fetchPlace(updatedGroups[i].place.entityID)
|
||||||
if (repoPlace != null && repoPlace.name != null && repoPlace.name != ""){
|
if (repoPlace != null && repoPlace.name != null && repoPlace.name != ""){
|
||||||
updatedGroups[i].isBookmarked = bookmarkLocationDao.findBookmarkLocation(repoPlace)
|
updatedGroups[i].isBookmarked = bookmarkLocationDao.findBookmarkLocation(repoPlace.name)
|
||||||
updatedGroups[i].place.apply {
|
updatedGroups[i].place.apply {
|
||||||
name = repoPlace.name
|
name = repoPlace.name
|
||||||
isMonument = repoPlace.isMonument
|
isMonument = repoPlace.isMonument
|
||||||
|
|
@ -375,7 +382,7 @@ class NearbyParentFragmentPresenter
|
||||||
collectResults.send(
|
collectResults.send(
|
||||||
fetchedPlaces.mapIndexed { index, place ->
|
fetchedPlaces.mapIndexed { index, place ->
|
||||||
Pair(indices[index], MarkerPlaceGroup(
|
Pair(indices[index], MarkerPlaceGroup(
|
||||||
bookmarkLocationDao.findBookmarkLocation(place),
|
bookmarkLocationDao.findBookmarkLocation(place.name),
|
||||||
place
|
place
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
@ -393,7 +400,10 @@ class NearbyParentFragmentPresenter
|
||||||
|
|
||||||
onePlaceBatch.add(Pair(i, MarkerPlaceGroup(
|
onePlaceBatch.add(Pair(i, MarkerPlaceGroup(
|
||||||
bookmarkLocationDao.findBookmarkLocation(
|
bookmarkLocationDao.findBookmarkLocation(
|
||||||
fetchedPlace[0]),fetchedPlace[0])))
|
fetchedPlace[0].name
|
||||||
|
),
|
||||||
|
fetchedPlace[0]
|
||||||
|
)))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.tag("NearbyPinDetails").e(e)
|
Timber.tag("NearbyPinDetails").e(e)
|
||||||
onePlaceBatch.add(Pair(i, updatedGroups[i]))
|
onePlaceBatch.add(Pair(i, updatedGroups[i]))
|
||||||
|
|
@ -457,7 +467,7 @@ class NearbyParentFragmentPresenter
|
||||||
if (bookmarkChangedPlacesBacklog.containsKey(group.place.location)) {
|
if (bookmarkChangedPlacesBacklog.containsKey(group.place.location)) {
|
||||||
updatedGroups[index] = MarkerPlaceGroup(
|
updatedGroups[index] = MarkerPlaceGroup(
|
||||||
bookmarkLocationDao
|
bookmarkLocationDao
|
||||||
.findBookmarkLocation(updatedGroups[index].place),
|
.findBookmarkLocation(updatedGroups[index].place.name),
|
||||||
updatedGroups[index].place
|
updatedGroups[index].place
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -565,7 +575,7 @@ class NearbyParentFragmentPresenter
|
||||||
).sortedBy { it.getDistanceInDouble(mapFocus) }.take(NearbyController.MAX_RESULTS)
|
).sortedBy { it.getDistanceInDouble(mapFocus) }.take(NearbyController.MAX_RESULTS)
|
||||||
.map {
|
.map {
|
||||||
MarkerPlaceGroup(
|
MarkerPlaceGroup(
|
||||||
bookmarkLocationDao.findBookmarkLocation(it), it
|
bookmarkLocationDao.findBookmarkLocation(it.name), it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ensureActive()
|
ensureActive()
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.AdapterView.OnItemClickListener
|
import android.widget.AdapterView.OnItemClickListener
|
||||||
|
import android.widget.Button
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
|
@ -330,6 +331,9 @@ class UploadMediaDetailAdapter : RecyclerView.Adapter<UploadMediaDetailAdapter.V
|
||||||
|
|
||||||
listView.adapter = languagesAdapter
|
listView.adapter = languagesAdapter
|
||||||
|
|
||||||
|
dialog.findViewById<Button>(R.id.cancel_button)
|
||||||
|
.setOnClickListener { v: View? -> dialog.dismiss() }
|
||||||
|
|
||||||
editText.addTextChangedListener(object : TextWatcher {
|
editText.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) =
|
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) =
|
||||||
hideRecentLanguagesSection()
|
hideRecentLanguagesSection()
|
||||||
|
|
|
||||||
10
app/src/main/res/anim/rotate.xml
Normal file
10
app/src/main/res/anim/rotate.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rotate
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fromDegrees="0"
|
||||||
|
android:toDegrees="360"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:duration="500"
|
||||||
|
android:repeatCount="infinite"
|
||||||
|
android:interpolator="@android:anim/linear_interpolator"/>
|
||||||
49
app/src/main/res/drawable/loading_icon.xml
Normal file
49
app/src/main/res/drawable/loading_icon.xml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<vector
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,4 A8,8 0 1,1 4,12 A8,8 0 1,5 19.42 ,15"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="#2196F3"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:trimPathStart="0.2"
|
||||||
|
android:trimPathEnd="1.0"/>
|
||||||
|
</vector>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<vector
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,4 A8,8 0 1,1 4,12 A8,8 0 1,1 12,4"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="#FFFFFF"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:trimPathStart="0.0"
|
||||||
|
android:trimPathEnd="0.2"/>
|
||||||
|
</vector>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:right="12dp">
|
||||||
|
<rotate
|
||||||
|
android:fromDegrees="0"
|
||||||
|
android:toDegrees="360"
|
||||||
|
android:pivotX="50%"
|
||||||
|
android:pivotY="50%">
|
||||||
|
<shape android:shape="ring">
|
||||||
|
<size
|
||||||
|
android:width="12dp"
|
||||||
|
android:height="2dp"/>
|
||||||
|
<solid android:color="#2196F3"/>
|
||||||
|
</shape>
|
||||||
|
</rotate>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
* 1917 Ekim Devrimi
|
* 1917 Ekim Devrimi
|
||||||
* Envlh
|
* Envlh
|
||||||
* Gambollar
|
* Gambollar
|
||||||
|
* GolyatGeri
|
||||||
* Gorizon
|
* Gorizon
|
||||||
* Gırd
|
* Gırd
|
||||||
* Marmase
|
* Marmase
|
||||||
|
|
@ -199,7 +200,7 @@
|
||||||
<string name="navigation_item_review">Çım berze cı</string>
|
<string name="navigation_item_review">Çım berze cı</string>
|
||||||
<string name="no_description_found">İzahat nêvineya</string>
|
<string name="no_description_found">İzahat nêvineya</string>
|
||||||
<string name="nearby_info_menu_commons_article">Pela dosyay commonsi</string>
|
<string name="nearby_info_menu_commons_article">Pela dosyay commonsi</string>
|
||||||
<string name="nearby_info_menu_wikidata_article">Pbcey Wikidata</string>
|
<string name="nearby_info_menu_wikidata_article">Pbcey Wikidayıt</string>
|
||||||
<string name="nearby_info_menu_wikipedia_article">Meqaley Wikipedia</string>
|
<string name="nearby_info_menu_wikipedia_article">Meqaley Wikipedia</string>
|
||||||
<string name="upload_problem_exist">Muhtemel problemê nê resımi</string>
|
<string name="upload_problem_exist">Muhtemel problemê nê resımi</string>
|
||||||
<string name="upload_problem_image_dark">Resım zehf tariyo.</string>
|
<string name="upload_problem_image_dark">Resım zehf tariyo.</string>
|
||||||
|
|
@ -216,7 +217,7 @@
|
||||||
<string name="skip_login">Ravêre</string>
|
<string name="skip_login">Ravêre</string>
|
||||||
<string name="navigation_item_login">Cı kewe</string>
|
<string name="navigation_item_login">Cı kewe</string>
|
||||||
<string name="nearby_directions">Telimati</string>
|
<string name="nearby_directions">Telimati</string>
|
||||||
<string name="nearby_wikidata">Wikidata</string>
|
<string name="nearby_wikidata">Wikidayıt</string>
|
||||||
<string name="nearby_wikipedia">Wikipediya</string>
|
<string name="nearby_wikipedia">Wikipediya</string>
|
||||||
<string name="nearby_commons">Commons</string>
|
<string name="nearby_commons">Commons</string>
|
||||||
<string name="about_rate_us">Rey bıdê</string>
|
<string name="about_rate_us">Rey bıdê</string>
|
||||||
|
|
@ -246,7 +247,7 @@
|
||||||
<string name="explore_tab_title_featured">Weçinaye</string>
|
<string name="explore_tab_title_featured">Weçinaye</string>
|
||||||
<string name="explore_tab_title_mobile">Raya mobiliya biyo bar</string>
|
<string name="explore_tab_title_mobile">Raya mobiliya biyo bar</string>
|
||||||
<string name="explore_tab_title_map">Xerita</string>
|
<string name="explore_tab_title_map">Xerita</string>
|
||||||
<string name="successful_wikidata_edit">Resım , Wikidata dê biyo obcey %1$s miyan!</string>
|
<string name="successful_wikidata_edit">Resım , Wikidayıt dê biyo obcey %1$s miyan!</string>
|
||||||
<string name="menu_set_wallpaper">Wallpaper eyar kerê</string>
|
<string name="menu_set_wallpaper">Wallpaper eyar kerê</string>
|
||||||
<string name="wallpaper_set_successfully">Wallpaper eyar biyo!</string>
|
<string name="wallpaper_set_successfully">Wallpaper eyar biyo!</string>
|
||||||
<string name="quiz">Quiz</string>
|
<string name="quiz">Quiz</string>
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@
|
||||||
<string name="menu_about">परिचय</string>
|
<string name="menu_about">परिचय</string>
|
||||||
<string name="about_license">विकिमीडिया कॉमन्स एप्प एक मुक्त स्रोत एप्प है जो कि विकिमीडिया समुदाय के अनुदानप्राप्तकर्ताओं व स्वयंसेवकों द्वारा निर्मित एवं प्रबंधित है। विकिमीडिया फॉऊण्डेशन इस एप्प के निर्माण, विकास व प्रबंधन में किसी प्रकार से भी संलग्न नहीं है।</string>
|
<string name="about_license">विकिमीडिया कॉमन्स एप्प एक मुक्त स्रोत एप्प है जो कि विकिमीडिया समुदाय के अनुदानप्राप्तकर्ताओं व स्वयंसेवकों द्वारा निर्मित एवं प्रबंधित है। विकिमीडिया फॉऊण्डेशन इस एप्प के निर्माण, विकास व प्रबंधन में किसी प्रकार से भी संलग्न नहीं है।</string>
|
||||||
<string name="about_improve">त्रुटि की सूचना और सुझावों के लिए <a href=\"%1$s\"> GitHub समस्या </a> बनाएं</string>
|
<string name="about_improve">त्रुटि की सूचना और सुझावों के लिए <a href=\"%1$s\"> GitHub समस्या </a> बनाएं</string>
|
||||||
<string name="about_privacy_policy" fuzzy="true"><u>गोपनीयता नीति</u></string>
|
<string name="about_privacy_policy">गोपनीयता नीति</string>
|
||||||
<string name="about_credits" fuzzy="true"><u>श्रेय</u></string>
|
<string name="about_credits">श्रेय</string>
|
||||||
<string name="title_activity_about">परिचय</string>
|
<string name="title_activity_about">परिचय</string>
|
||||||
<string name="menu_feedback">प्रतिक्रिया दें (ईमेल द्वारा)</string>
|
<string name="menu_feedback">प्रतिक्रिया दें (ईमेल द्वारा)</string>
|
||||||
<string name="no_email_client">कोई ईमेल साधन स्थापित नहीं</string>
|
<string name="no_email_client">कोई ईमेल साधन स्थापित नहीं</string>
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
<string name="menu_download">डाउनलोड</string>
|
<string name="menu_download">डाउनलोड</string>
|
||||||
<string name="preference_license">डिफॉल्ट लाइसेन्स</string>
|
<string name="preference_license">डिफॉल्ट लाइसेन्स</string>
|
||||||
<string name="use_previous" fuzzy="true">पिछले शीर्षक/विवरण का उपयोग करें</string>
|
<string name="use_previous" fuzzy="true">पिछले शीर्षक/विवरण का उपयोग करें</string>
|
||||||
<string name="preference_theme" fuzzy="true">रात्रि मोड</string>
|
<string name="preference_theme">थीम</string>
|
||||||
<string name="license_name_cc_by_sa_four">एट्रीब्यूशन-शेयरअलाइक 4.0</string>
|
<string name="license_name_cc_by_sa_four">एट्रीब्यूशन-शेयरअलाइक 4.0</string>
|
||||||
<string name="license_name_cc_by_four">एट्रिब्यूशन 4.0</string>
|
<string name="license_name_cc_by_four">एट्रिब्यूशन 4.0</string>
|
||||||
<string name="license_name_cc_by_sa">एट्रीब्यूशन-शेयरअलाइक 3.0</string>
|
<string name="license_name_cc_by_sa">एट्रीब्यूशन-शेयरअलाइक 3.0</string>
|
||||||
|
|
@ -263,12 +263,12 @@
|
||||||
<string name="nearby_wikipedia" fuzzy="true">विकीपीडिया</string>
|
<string name="nearby_wikipedia" fuzzy="true">विकीपीडिया</string>
|
||||||
<string name="nearby_commons">कॉमन्स</string>
|
<string name="nearby_commons">कॉमन्स</string>
|
||||||
<string name="about_rate_us" fuzzy="true"><u>हमें रेट करें</u></string>
|
<string name="about_rate_us" fuzzy="true"><u>हमें रेट करें</u></string>
|
||||||
<string name="about_faq" fuzzy="true"><u>अक्सर पूछे जाने वाले प्रश्न</u></string>
|
<string name="about_faq">अक्सर पूछे जाने वाले प्रश्न</string>
|
||||||
<string name="welcome_skip_button">प्रशिक्षण छोड़ें</string>
|
<string name="welcome_skip_button">प्रशिक्षण छोड़ें</string>
|
||||||
<string name="no_internet">इंटरनेट उपलब्ध नहीं</string>
|
<string name="no_internet">इंटरनेट उपलब्ध नहीं</string>
|
||||||
<string name="error_notifications">सूचनाएं लाने में त्रुटि</string>
|
<string name="error_notifications">सूचनाएं लाने में त्रुटि</string>
|
||||||
<string name="no_notifications">कोई सूचनाएँ नहीं मिलीं</string>
|
<string name="no_notifications">कोई सूचनाएँ नहीं मिलीं</string>
|
||||||
<string name="about_translate" fuzzy="true"><u>अनुवाद</u></string>
|
<string name="about_translate">अनुवाद</string>
|
||||||
<string name="about_translate_title">भाषाएँ</string>
|
<string name="about_translate_title">भाषाएँ</string>
|
||||||
<string name="about_translate_proceed">आगे बढ़ें</string>
|
<string name="about_translate_proceed">आगे बढ़ें</string>
|
||||||
<string name="about_translate_cancel">रद्द करें</string>
|
<string name="about_translate_cancel">रद्द करें</string>
|
||||||
|
|
@ -284,7 +284,7 @@
|
||||||
<string name="search_recent_header">हाल की खोजें</string>
|
<string name="search_recent_header">हाल की खोजें</string>
|
||||||
<string name="provider_searches">हाल में खोजे गये प्रश्न</string>
|
<string name="provider_searches">हाल में खोजे गये प्रश्न</string>
|
||||||
<string name="error_loading_categories">श्रेणी लोड करते समय त्रुटि उत्पन्न हुई।</string>
|
<string name="error_loading_categories">श्रेणी लोड करते समय त्रुटि उत्पन्न हुई।</string>
|
||||||
<string name="search_tab_title_media" fuzzy="true">मीडिया</string>
|
<string name="search_tab_title_media">मीडिया</string>
|
||||||
<string name="search_tab_title_categories">श्रेणियाँ</string>
|
<string name="search_tab_title_categories">श्रेणियाँ</string>
|
||||||
<string name="explore_tab_title_featured">निर्वाचित</string>
|
<string name="explore_tab_title_featured">निर्वाचित</string>
|
||||||
<string name="explore_tab_title_map">नक्शा</string>
|
<string name="explore_tab_title_map">नक्शा</string>
|
||||||
|
|
@ -315,7 +315,7 @@
|
||||||
<string name="statistics">सांख्यिकी</string>
|
<string name="statistics">सांख्यिकी</string>
|
||||||
<string name="statistics_thanks">धन्यवाद प्राप्त किया</string>
|
<string name="statistics_thanks">धन्यवाद प्राप्त किया</string>
|
||||||
<string name="statistics_featured">निर्वाचित चित्र</string>
|
<string name="statistics_featured">निर्वाचित चित्र</string>
|
||||||
<string name="level" fuzzy="true">स्तर</string>
|
<string name="level">स्तर %d</string>
|
||||||
<string name="images_uploaded">चित्र अपलोड हुआ</string>
|
<string name="images_uploaded">चित्र अपलोड हुआ</string>
|
||||||
<string name="image_reverts">चित्रों को वापस नहीं किया गया</string>
|
<string name="image_reverts">चित्रों को वापस नहीं किया गया</string>
|
||||||
<string name="images_used_by_wiki">उपयोग हुए चित्र</string>
|
<string name="images_used_by_wiki">उपयोग हुए चित्र</string>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* Akmaie Ajam
|
* Akmaie Ajam
|
||||||
* Arifin.wijaya
|
* Arifin.wijaya
|
||||||
* Birusian
|
* Birusian
|
||||||
|
* Boesenbergia
|
||||||
* DARMAS BUDI SANTOSO
|
* DARMAS BUDI SANTOSO
|
||||||
* Daud I.F. Argana
|
* Daud I.F. Argana
|
||||||
* Fafau06
|
* Fafau06
|
||||||
|
|
@ -295,7 +296,7 @@
|
||||||
<string name="error_notifications">Galat penyampaian pemberitahuan</string>
|
<string name="error_notifications">Galat penyampaian pemberitahuan</string>
|
||||||
<string name="error_review">Galat mengambil gambar untuk ditinjau. Tekan segarkan untuk coba lagi.</string>
|
<string name="error_review">Galat mengambil gambar untuk ditinjau. Tekan segarkan untuk coba lagi.</string>
|
||||||
<string name="no_notifications">Pemberitahuan tidak ditemukan</string>
|
<string name="no_notifications">Pemberitahuan tidak ditemukan</string>
|
||||||
<string name="about_translate">Terjemahkan</string>
|
<string name="about_translate">Pertalaghi</string>
|
||||||
<string name="about_translate_title">Bahasa</string>
|
<string name="about_translate_title">Bahasa</string>
|
||||||
<string name="about_translate_message">Pilih bahasa untuk terjemahan yang ingin Anda kirimkan</string>
|
<string name="about_translate_message">Pilih bahasa untuk terjemahan yang ingin Anda kirimkan</string>
|
||||||
<string name="about_translate_proceed">Lanjutkan</string>
|
<string name="about_translate_proceed">Lanjutkan</string>
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@
|
||||||
<string name="no">Neen</string>
|
<string name="no">Neen</string>
|
||||||
<string name="media_detail_caption">Beschrëftung</string>
|
<string name="media_detail_caption">Beschrëftung</string>
|
||||||
<string name="media_detail_title">Titel</string>
|
<string name="media_detail_title">Titel</string>
|
||||||
|
<string name="media_detail_depiction">Motiven</string>
|
||||||
<string name="media_detail_description">Beschreiwung</string>
|
<string name="media_detail_description">Beschreiwung</string>
|
||||||
<string name="media_detail_discussion">Diskussioun</string>
|
<string name="media_detail_discussion">Diskussioun</string>
|
||||||
<string name="media_detail_author">Auteur</string>
|
<string name="media_detail_author">Auteur</string>
|
||||||
|
|
|
||||||
|
|
@ -406,10 +406,10 @@
|
||||||
<string name="preference_author_name_toggle_summary">Gebruik een aangepaste auteursnaam in plaats van uw gebruikersnaam tijdens het uploaden van foto\'s</string>
|
<string name="preference_author_name_toggle_summary">Gebruik een aangepaste auteursnaam in plaats van uw gebruikersnaam tijdens het uploaden van foto\'s</string>
|
||||||
<string name="preference_author_name">Aangepaste auteursnaam</string>
|
<string name="preference_author_name">Aangepaste auteursnaam</string>
|
||||||
<string name="contributions_fragment">Bijdragen</string>
|
<string name="contributions_fragment">Bijdragen</string>
|
||||||
<string name="nearby_fragment">Dichtbij</string>
|
<string name="nearby_fragment">In de buurt</string>
|
||||||
<string name="notifications">Meldingen</string>
|
<string name="notifications">Meldingen</string>
|
||||||
<string name="read_notifications">Meldingen (gelezen)</string>
|
<string name="read_notifications">Meldingen (gelezen)</string>
|
||||||
<string name="display_nearby_notification">Meldingen dichtbij weergeven</string>
|
<string name="display_nearby_notification">Melding in de buurt weergeven</string>
|
||||||
<string name="display_nearby_notification_summary">Toon in-app-melding voor de dichtstbijzijnde plaats die foto\'s nodig heeft</string>
|
<string name="display_nearby_notification_summary">Toon in-app-melding voor de dichtstbijzijnde plaats die foto\'s nodig heeft</string>
|
||||||
<string name="list_sheet">Lijst</string>
|
<string name="list_sheet">Lijst</string>
|
||||||
<string name="storage_permission">Toestemming om op te slaan</string>
|
<string name="storage_permission">Toestemming om op te slaan</string>
|
||||||
|
|
@ -615,7 +615,7 @@
|
||||||
<string name="recommend_high_accuracy_mode">Kies voor de beste resultaten de modus van hoge nauwkeurigheid.</string>
|
<string name="recommend_high_accuracy_mode">Kies voor de beste resultaten de modus van hoge nauwkeurigheid.</string>
|
||||||
<string name="ask_to_turn_location_on">Locatie inschakelen?</string>
|
<string name="ask_to_turn_location_on">Locatie inschakelen?</string>
|
||||||
<string name="ask_to_turn_location_on_text">Schakel locatiediensten in zodat de app uw huidige locatie toont</string>
|
<string name="ask_to_turn_location_on_text">Schakel locatiediensten in zodat de app uw huidige locatie toont</string>
|
||||||
<string name="nearby_needs_location">In de Buurt heeft locatie nodig om correct te werken</string>
|
<string name="nearby_needs_location">‘In de buurt’ heeft locatietoegang nodig om correct te werken</string>
|
||||||
<string name="explore_map_needs_location">Voor de verkenningskaart is locatietoestemming nodig om afbeeldingen in de buurt weer te geven</string>
|
<string name="explore_map_needs_location">Voor de verkenningskaart is locatietoestemming nodig om afbeeldingen in de buurt weer te geven</string>
|
||||||
<string name="upload_map_location_access">U moet locatietoestemming geven om de locatie automatisch in te stellen.</string>
|
<string name="upload_map_location_access">U moet locatietoestemming geven om de locatie automatisch in te stellen.</string>
|
||||||
<string name="use_location_from_similar_image">Heeft u deze twee foto\'s op dezelfde plek gemaakt? Wilt u de breedtegraad/lengtegraad van de afbeelding rechts gebruiken?</string>
|
<string name="use_location_from_similar_image">Heeft u deze twee foto\'s op dezelfde plek gemaakt? Wilt u de breedtegraad/lengtegraad van de afbeelding rechts gebruiken?</string>
|
||||||
|
|
@ -657,7 +657,7 @@
|
||||||
<string name="leaderboard_weekly">Wekelijks</string>
|
<string name="leaderboard_weekly">Wekelijks</string>
|
||||||
<string name="leaderboard_all_time">Alle tijden</string>
|
<string name="leaderboard_all_time">Alle tijden</string>
|
||||||
<string name="leaderboard_upload">Uploaden</string>
|
<string name="leaderboard_upload">Uploaden</string>
|
||||||
<string name="leaderboard_nearby">In de Buurt</string>
|
<string name="leaderboard_nearby">In de buurt</string>
|
||||||
<string name="leaderboard_used">Gebruikt</string>
|
<string name="leaderboard_used">Gebruikt</string>
|
||||||
<string name="leaderboard_my_rank_button_text">Mijn ranking</string>
|
<string name="leaderboard_my_rank_button_text">Mijn ranking</string>
|
||||||
<string name="limited_connection_enabled">Beperkte verbindingsmodus ingeschakeld!</string>
|
<string name="limited_connection_enabled">Beperkte verbindingsmodus ingeschakeld!</string>
|
||||||
|
|
@ -724,7 +724,7 @@
|
||||||
<string name="edit_depictions">Wijzig items</string>
|
<string name="edit_depictions">Wijzig items</string>
|
||||||
<string name="edit_categories">Categorieën bewerken</string>
|
<string name="edit_categories">Categorieën bewerken</string>
|
||||||
<string name="advanced_options">Geavanceerde opties</string>
|
<string name="advanced_options">Geavanceerde opties</string>
|
||||||
<string name="advanced_query_info_text">U kunt de zoekopdracht Dichtbij aanpassen. Als u fouten krijgt, kunt u opnieuw instellen en toepassen.</string>
|
<string name="advanced_query_info_text">U kunt de zoekopdracht ‘In de buurt’ aanpassen. Als u fouten krijgt, kunt u opnieuw instellen en toepassen.</string>
|
||||||
<string name="apply">Toepassen</string>
|
<string name="apply">Toepassen</string>
|
||||||
<string name="reset">Opnieuw instellen</string>
|
<string name="reset">Opnieuw instellen</string>
|
||||||
<string name="location_message">Locatiegegevens helpen wiki-bewerkers om uw foto te vinden, waardoor deze veel nuttiger wordt.\nUw recente uploads hebben geen locatie.\nWe raden u aan om de locatie in de instellingen van uw camera-app in te schakelen.\nBedankt voor het uploaden!</string>
|
<string name="location_message">Locatiegegevens helpen wiki-bewerkers om uw foto te vinden, waardoor deze veel nuttiger wordt.\nUw recente uploads hebben geen locatie.\nWe raden u aan om de locatie in de instellingen van uw camera-app in te schakelen.\nBedankt voor het uploaden!</string>
|
||||||
|
|
@ -835,4 +835,10 @@
|
||||||
<string name="account">Account</string>
|
<string name="account">Account</string>
|
||||||
<string name="vanish_account">Account laten verdwijnen</string>
|
<string name="vanish_account">Account laten verdwijnen</string>
|
||||||
<string name="account_vanish_request_confirm_title">Waarschuwing verwijdering account</string>
|
<string name="account_vanish_request_confirm_title">Waarschuwing verwijdering account</string>
|
||||||
|
<string name="account_vanish_request_confirm">Verdwijnen is een <b>laatste redmiddel</b> en moet <b>alleen worden gebruikt als u voor altijd wilt stoppen met bewerken</b> en om zoveel mogelijk van uw voorgaande relaties te verbergen.<br/><br/>Accountverwijdering op Wikipedia gebeurt door uw accountnaam te wijzigen opdat anderen uw bijdragen niet meer kunnen herkennen. De procedure wordt accountverdwijning genoemd. <b>Door verdwijnen wordt geen volledige anonimiteit gegarandeerd en worden geen bijdragen aan de projecten verwijderd.</b></string>
|
||||||
|
<string name="caption">Bijschrift</string>
|
||||||
|
<string name="caption_copied_to_clipboard">Bijschrift gekopieerd naar klembord</string>
|
||||||
|
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Gefeliciteerd, alle foto’s in dit album zijn ofwel geüpload ofwel gemarkeerd als ‘niet om te uploaden’.</string>
|
||||||
|
<string name="show_in_explore">Weergeven in Verkennen</string>
|
||||||
|
<string name="show_in_nearby">Weergeven in ‘In de buurt’</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,14 @@
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<string name="commons_logo">ਕਾਮਨਜ਼ ਮਾਰਕਾ</string>
|
<string name="commons_logo">ਕਾਮਨਜ਼ ਮਾਰਕਾ</string>
|
||||||
|
<string name="submit">ਹਵਾਲੇ ਕਰੋ</string>
|
||||||
<string name="add_another_description">ਇੱਕ ਹੋਰ ਵੇਰਵਾ ਸ਼ਾਮਲ ਕਰੋ</string>
|
<string name="add_another_description">ਇੱਕ ਹੋਰ ਵੇਰਵਾ ਸ਼ਾਮਲ ਕਰੋ</string>
|
||||||
<string name="add_new_contribution">ਨਵਾਂ ਯੋਗਦਾਨ ਸ਼ਾਮਲ ਕਰੋ</string>
|
<string name="add_new_contribution">ਨਵਾਂ ਯੋਗਦਾਨ ਸ਼ਾਮਲ ਕਰੋ</string>
|
||||||
|
<string name="add_contribution_from_camera">ਕੈਮਰੇ ਰਾਹੀਂ ਯੋਗਦਾਨ ਸ਼ਾਮਲ ਕਰੋ</string>
|
||||||
|
<string name="add_contribution_from_photos">ਤਸਵੀਰਾਂ ਰਾਹੀਂ ਯੋਗਦਾਨ ਸ਼ਾਮਲ ਕਰੋ</string>
|
||||||
|
<string name="show_captions">ਸੁਰਖੀ</string>
|
||||||
|
<string name="row_item_language_description">ਭਾਸ਼ਾ ਦਾ ਵੇਰਵਾ</string>
|
||||||
|
<string name="row_item_caption">ਸੁਰਖੀ</string>
|
||||||
<string name="show_captions_description">ਵੇਰਵਾ</string>
|
<string name="show_captions_description">ਵੇਰਵਾ</string>
|
||||||
<string name="nearby_row_image">ਤਸਵੀਰ</string>
|
<string name="nearby_row_image">ਤਸਵੀਰ</string>
|
||||||
<string name="nearby_all">ਸਾਰੇ</string>
|
<string name="nearby_all">ਸਾਰੇ</string>
|
||||||
|
|
@ -37,14 +43,19 @@
|
||||||
<string name="navigation_item_explore">ਪੜਚੋਲ ਕਰੋ</string>
|
<string name="navigation_item_explore">ਪੜਚੋਲ ਕਰੋ</string>
|
||||||
<string name="preference_category_appearance">ਦਿੱਖ</string>
|
<string name="preference_category_appearance">ਦਿੱਖ</string>
|
||||||
<string name="preference_category_general">ਆਮ</string>
|
<string name="preference_category_general">ਆਮ</string>
|
||||||
|
<string name="preference_category_feedback">ਸੁਝਾਅ</string>
|
||||||
|
<string name="preference_category_privacy">ਪਰਦੇਦਾਰੀ</string>
|
||||||
<string name="app_name" fuzzy="true">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼</string>
|
<string name="app_name" fuzzy="true">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼</string>
|
||||||
<string name="menu_settings">ਪਸੰਦਾਂ</string>
|
<string name="menu_settings">ਪਸੰਦਾਂ</string>
|
||||||
|
<string name="upload_in_progress">ਚੜ੍ਹਾਉਣਾ ਜਾਰੀ ਐ</string>
|
||||||
<string name="username">ਵਰਤੋਂਕਾਰ ਨਾਂ</string>
|
<string name="username">ਵਰਤੋਂਕਾਰ ਨਾਂ</string>
|
||||||
<string name="password">ਲੰਘ-ਸ਼ਬਦ</string>
|
<string name="password">ਲੰਘ-ਸ਼ਬਦ</string>
|
||||||
<string name="login">ਦਾਖ਼ਲ ਹੋਵੋ</string>
|
<string name="login">ਦਾਖ਼ਲ ਹੋਵੋ</string>
|
||||||
<string name="forgot_password">ਪਾਰਸ਼ਬਦ ਭੁੱਲ ਗਏ?</string>
|
<string name="forgot_password">ਪਾਰਸ਼ਬਦ ਭੁੱਲ ਗਏ?</string>
|
||||||
|
<string name="signup">ਖਾਤਾ ਬਣਾਓ</string>
|
||||||
<string name="logging_in_title">ਦਾਖ਼ਲਾ ਹੋ ਰਿਹਾ ਹੈ</string>
|
<string name="logging_in_title">ਦਾਖ਼ਲਾ ਹੋ ਰਿਹਾ ਹੈ</string>
|
||||||
<string name="logging_in_message">ਉਡੀਕੋ ਜੀ…</string>
|
<string name="logging_in_message">ਉਡੀਕੋ ਜੀ…</string>
|
||||||
|
<string name="updating_caption_title">ਸੁਰਖੀਆਂ ਅਤੇ ਵੇਰਵੇ ਨਵਿਆਏ ਜਾ ਰਹੇ ਹਨ</string>
|
||||||
<string name="updating_caption_message">ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕੋ...</string>
|
<string name="updating_caption_message">ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕੋ...</string>
|
||||||
<string name="login_success">ਦਾਖ਼ਲ ਹੋਣਾ ਸਫ਼ਲ!</string>
|
<string name="login_success">ਦਾਖ਼ਲ ਹੋਣਾ ਸਫ਼ਲ!</string>
|
||||||
<string name="login_failed">ਦਾਖ਼ਲ ਹੋਣਾ ਅਸਫ਼ਲ!</string>
|
<string name="login_failed">ਦਾਖ਼ਲ ਹੋਣਾ ਅਸਫ਼ਲ!</string>
|
||||||
|
|
@ -53,11 +64,13 @@
|
||||||
<string name="uploading_started">ਅੱਪਲੋਡ ਸ਼ੁਰੂ ਹੋਇਆ!</string>
|
<string name="uploading_started">ਅੱਪਲੋਡ ਸ਼ੁਰੂ ਹੋਇਆ!</string>
|
||||||
<string name="upload_completed_notification_title">%1$s ਅੱਪਲੋਡ ਹੋ ਗਏ!</string>
|
<string name="upload_completed_notification_title">%1$s ਅੱਪਲੋਡ ਹੋ ਗਏ!</string>
|
||||||
<string name="upload_completed_notification_text">ਆਪਣਾ ਅੱਪਲੋਡ ਵੇਖਣ ਲਈ ਥਪੇੜੋ</string>
|
<string name="upload_completed_notification_text">ਆਪਣਾ ਅੱਪਲੋਡ ਵੇਖਣ ਲਈ ਥਪੇੜੋ</string>
|
||||||
<string name="upload_progress_notification_title_start" fuzzy="true">%1$s ਅੱਪਲੋਡ ਸ਼ੁਰੂ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ</string>
|
<string name="upload_progress_notification_title_start">ਫਾਈਲ ਚੜ੍ਹਾਈ ਜਾ ਰਹੀ ਐ: %s</string>
|
||||||
<string name="upload_progress_notification_title_in_progress">%1$s ਅੱਪਲੋਡ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ</string>
|
<string name="upload_progress_notification_title_in_progress">%1$s ਅੱਪਲੋਡ ਕੀਤੇ ਜਾ ਰਹੇ ਹਨ</string>
|
||||||
<string name="upload_progress_notification_title_finishing">%1$s ਦਾ ਅੱਪਲੋਡ ਖ਼ਤਮ ਹੋ ਰਿਹਾ ਹੈ</string>
|
<string name="upload_progress_notification_title_finishing">%1$s ਦਾ ਅੱਪਲੋਡ ਖ਼ਤਮ ਹੋ ਰਿਹਾ ਹੈ</string>
|
||||||
<string name="upload_failed_notification_title" fuzzy="true">%1$s ਦਾ ਅੱਪਲੋਡ ਫੇਲ੍ਹ ਹੋਇਆ</string>
|
<string name="upload_failed_notification_title">%1$s ਨੂੰ ਚੜ੍ਹਾਉਣ ਵਿੱਚ ਨਾਕਾਮ</string>
|
||||||
|
<string name="upload_paused_notification_title">%1$s ਚੜ੍ਹਾਉਣਾ ਰੋਕਿਆ ਗਿਆ</string>
|
||||||
<string name="upload_failed_notification_subtitle">ਵੇਖਣ ਲਈ ਥਪੇੜੋ</string>
|
<string name="upload_failed_notification_subtitle">ਵੇਖਣ ਲਈ ਥਪੇੜੋ</string>
|
||||||
|
<string name="upload_paused_notification_subtitle">ਵੇਖਣ ਲਈ ਥਪੇੜੋ</string>
|
||||||
<string name="title_activity_contributions" fuzzy="true">ਮੇਰੇ ਅੱਪਲੋਡ</string>
|
<string name="title_activity_contributions" fuzzy="true">ਮੇਰੇ ਅੱਪਲੋਡ</string>
|
||||||
<string name="contribution_state_queued">ਕਤਾਰ ਵਿਚ</string>
|
<string name="contribution_state_queued">ਕਤਾਰ ਵਿਚ</string>
|
||||||
<string name="contribution_state_failed">ਫੇਲ੍ਹ ਹੋਇਆ</string>
|
<string name="contribution_state_failed">ਫੇਲ੍ਹ ਹੋਇਆ</string>
|
||||||
|
|
@ -68,12 +81,17 @@
|
||||||
<string name="menu_nearby">ਨੇੜੇ-ਤੇੜੇ</string>
|
<string name="menu_nearby">ਨੇੜੇ-ਤੇੜੇ</string>
|
||||||
<string name="provider_contributions">ਮੇਰੇ ਅੱਪਲੋਡ</string>
|
<string name="provider_contributions">ਮੇਰੇ ਅੱਪਲੋਡ</string>
|
||||||
<string name="menu_copy_link">ਕੜੀ ਦੀ ਨਕਲ ਕਰੋ</string>
|
<string name="menu_copy_link">ਕੜੀ ਦੀ ਨਕਲ ਕਰੋ</string>
|
||||||
|
<string name="menu_link_copied">ਕੜੀ ਨੂੰ ਚੂੰਢੀ-ਤਖਤੀ ਉੱਤੇ ਨਕਲ ਕੀਤਾ ਗਿਆ ਐ</string>
|
||||||
<string name="menu_share">ਸਾਂਝਾ ਕਰੋ</string>
|
<string name="menu_share">ਸਾਂਝਾ ਕਰੋ</string>
|
||||||
|
<string name="menu_view_file_page">ਫਾਇਲ ਸਫ਼ਾ ਵੇਖੋ</string>
|
||||||
<string name="share_title_hint">ਸੁਰਖੀ (ਲੋੜੀਂਦੀ)</string>
|
<string name="share_title_hint">ਸੁਰਖੀ (ਲੋੜੀਂਦੀ)</string>
|
||||||
|
<string name="add_caption_toast">ਕਿਰਪਾ ਕਰਕੇ ਇਸ ਫਾਈਲ ਲਈ ਇੱਕ ਸੁਰਖੀ ਦਿਓ</string>
|
||||||
<string name="share_description_hint">ਵੇਰਵਾ</string>
|
<string name="share_description_hint">ਵੇਰਵਾ</string>
|
||||||
|
<string name="share_caption_hint">ਸੁਰਖੀ</string>
|
||||||
<string name="login_failed_network">ਦਾਖ਼ਲ ਹੋਣ ਵਿੱਚ ਅਸਮਰੱਥ - ਨੈੱਟਵਰਕ ਫੇਲ੍ਹ ਹੋਇਆ ਹੈ</string>
|
<string name="login_failed_network">ਦਾਖ਼ਲ ਹੋਣ ਵਿੱਚ ਅਸਮਰੱਥ - ਨੈੱਟਵਰਕ ਫੇਲ੍ਹ ਹੋਇਆ ਹੈ</string>
|
||||||
<string name="login_failed_throttled">ਬਹੁਤ ਸਾਰੀਆਂ ਅਸਫ਼ਲ ਕੋਸ਼ਿਸ਼ਾਂ। ਥੋੜ੍ਹੀ ਦੇਰ ਬਾਅਦ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।</string>
|
<string name="login_failed_throttled">ਬਹੁਤ ਸਾਰੀਆਂ ਅਸਫ਼ਲ ਕੋਸ਼ਿਸ਼ਾਂ। ਥੋੜ੍ਹੀ ਦੇਰ ਬਾਅਦ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।</string>
|
||||||
<string name="login_failed_blocked">ਅਫ਼ਸੋਸ, ਇਹ ਵਰਤੋਂਕਾਰ ਨੂੰ ਕਾਮਨਜ਼ ਤੇ ਰੋਕ ਲਾਈ ਗਈ ਹੈ।</string>
|
<string name="login_failed_blocked">ਅਫ਼ਸੋਸ, ਇਹ ਵਰਤੋਂਕਾਰ ਨੂੰ ਕਾਮਨਜ਼ ਤੇ ਰੋਕ ਲਾਈ ਗਈ ਹੈ।</string>
|
||||||
|
<string name="login_failed_2fa_needed">ਤੁਹਾਨੂੰ ਆਪਣਾ ਦੋ-ਕਾਰਕ ਪ੍ਰਮਾਣੀਕਰਨ ਕੋਡ ਦੇਣਾ ਪਵੇਗਾ।</string>
|
||||||
<string name="login_failed_generic">ਦਾਖ਼ਲ ਹੋਣਾ ਅਸਫ਼ਲ!</string>
|
<string name="login_failed_generic">ਦਾਖ਼ਲ ਹੋਣਾ ਅਸਫ਼ਲ!</string>
|
||||||
<string name="share_upload_button">ਚੜ੍ਹਾਉ</string>
|
<string name="share_upload_button">ਚੜ੍ਹਾਉ</string>
|
||||||
<string name="multiple_share_base_title">ਇਸ ਸੈੱਟ ਨੂੰ ਨਾਂ ਦਿਓ</string>
|
<string name="multiple_share_base_title">ਇਸ ਸੈੱਟ ਨੂੰ ਨਾਂ ਦਿਓ</string>
|
||||||
|
|
@ -85,10 +103,12 @@
|
||||||
<string name="display_list_button">ਸੂਚੀ</string>
|
<string name="display_list_button">ਸੂਚੀ</string>
|
||||||
<string name="contributions_subtitle_zero" fuzzy="true">ਫ਼ਿਲਹਾਲ ਕੋਈ ਅੱਪਲੋਡ ਨਹੀਂ</string>
|
<string name="contributions_subtitle_zero" fuzzy="true">ਫ਼ਿਲਹਾਲ ਕੋਈ ਅੱਪਲੋਡ ਨਹੀਂ</string>
|
||||||
<string name="categories_not_found">%1$s ਨਾਲ਼ ਮੇਲ ਖਾਂਦੀ ਕੋਈ ਸ਼੍ਰੇਣੀ ਨਹੀਂ ਲੱਭੀ</string>
|
<string name="categories_not_found">%1$s ਨਾਲ਼ ਮੇਲ ਖਾਂਦੀ ਕੋਈ ਸ਼੍ਰੇਣੀ ਨਹੀਂ ਲੱਭੀ</string>
|
||||||
|
<string name="depictions_not_found">%1$s ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਵਿਕੀਡਾਟਾ ਚੀਜ਼ਾਂ ਨਹੀਂ ਲੱਭਿਆਂ।</string>
|
||||||
<string name="categories_skip_explanation" fuzzy="true">ਆਪਣੀਆਂ ਤਸਵੀਰਾਂ ਨੂੰ ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਵਿਚ ਜ਼ਿਆਦਾ ਲੱਭਣਯੋਗ ਬਣਾਉਣ ਲਈ ਸ਼੍ਰੇਣੀਆਂ ਜੋੜੋ।\n\nਸ਼੍ਰੇਣੀਆਂ ਜੋੜਨ ਲਈ ਟਾਈਪ ਕਰਨ ਅਰੰਭ ਕਰੋ।\nਇਸ ਕਾਰਜ ਨੂੰ ਅਣਡਿੱਠਾ ਕਰਨ ਲਈ ਇਹ ਸੁਨੇਹਾ ਥਪੇੜੋ (ਜਾਂ ਵਾਪਸੀ ਬਟਨ ਦਬਾਓ)।</string>
|
<string name="categories_skip_explanation" fuzzy="true">ਆਪਣੀਆਂ ਤਸਵੀਰਾਂ ਨੂੰ ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਵਿਚ ਜ਼ਿਆਦਾ ਲੱਭਣਯੋਗ ਬਣਾਉਣ ਲਈ ਸ਼੍ਰੇਣੀਆਂ ਜੋੜੋ।\n\nਸ਼੍ਰੇਣੀਆਂ ਜੋੜਨ ਲਈ ਟਾਈਪ ਕਰਨ ਅਰੰਭ ਕਰੋ।\nਇਸ ਕਾਰਜ ਨੂੰ ਅਣਡਿੱਠਾ ਕਰਨ ਲਈ ਇਹ ਸੁਨੇਹਾ ਥਪੇੜੋ (ਜਾਂ ਵਾਪਸੀ ਬਟਨ ਦਬਾਓ)।</string>
|
||||||
<string name="categories_activity_title">ਸ਼੍ਰੇਣੀਆਂ</string>
|
<string name="categories_activity_title">ਸ਼੍ਰੇਣੀਆਂ</string>
|
||||||
<string name="title_activity_settings">ਪਸੰਦਾਂ</string>
|
<string name="title_activity_settings">ਪਸੰਦਾਂ</string>
|
||||||
<string name="title_activity_signup">ਖਾਤਾ ਬਣਾਓ</string>
|
<string name="title_activity_signup">ਖਾਤਾ ਬਣਾਓ</string>
|
||||||
|
<string name="title_activity_featured_images">ਵਿਸ਼ੇਸ਼ ਤਸਵੀਰ</string>
|
||||||
<string name="title_activity_category_details">ਸ਼੍ਰੇਣੀ</string>
|
<string name="title_activity_category_details">ਸ਼੍ਰੇਣੀ</string>
|
||||||
<string name="menu_about">ਇਸ ਬਾਰੇ</string>
|
<string name="menu_about">ਇਸ ਬਾਰੇ</string>
|
||||||
<string name="about_license" fuzzy="true">ਅਜ਼ਾਦ ਸਰੋਤ ਸਾਫ਼ਟਵੇਅਰ ਨੂੰ <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a> ਅਧੀਨ ਜਾਰੀ ਕੀਤਾ ਗਿਆ ਹੈ</string>
|
<string name="about_license" fuzzy="true">ਅਜ਼ਾਦ ਸਰੋਤ ਸਾਫ਼ਟਵੇਅਰ ਨੂੰ <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a> ਅਧੀਨ ਜਾਰੀ ਕੀਤਾ ਗਿਆ ਹੈ</string>
|
||||||
|
|
@ -105,9 +125,9 @@
|
||||||
<string name="menu_cancel_upload">ਰੱਦ ਕਰੋ</string>
|
<string name="menu_cancel_upload">ਰੱਦ ਕਰੋ</string>
|
||||||
<string name="media_upload_policy">ਇਹ ਤਸਵੀਰ ਅੱਪਲੋਡ ਕਰਨ ਨਾਲ ਹੀ ਮੈਂ ਦਾਅਵਾ ਕਰਦਾ ਹਾਂ/ਕਰਦੀ ਹਾਂ ਕਿ ਇਹ ਮੇਰਾ ਆਪਣਾ ਕਾਰਜ ਹੈ, ਕਿ ਇਸ ਤਹਿਤ ਕੋਈ ਕਾਪੀਰਾਈਟ ਉਲੰਘਣਾ ਨਹੀਂ ਕੀਤੀ ਗਈ ਅਤੇ <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਨੀਤੀਆਂ</a> ਮੁਤਾਬਿਕ ਇਹ ਠੀਕ ਹੈ।</string>
|
<string name="media_upload_policy">ਇਹ ਤਸਵੀਰ ਅੱਪਲੋਡ ਕਰਨ ਨਾਲ ਹੀ ਮੈਂ ਦਾਅਵਾ ਕਰਦਾ ਹਾਂ/ਕਰਦੀ ਹਾਂ ਕਿ ਇਹ ਮੇਰਾ ਆਪਣਾ ਕਾਰਜ ਹੈ, ਕਿ ਇਸ ਤਹਿਤ ਕੋਈ ਕਾਪੀਰਾਈਟ ਉਲੰਘਣਾ ਨਹੀਂ ਕੀਤੀ ਗਈ ਅਤੇ <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਨੀਤੀਆਂ</a> ਮੁਤਾਬਿਕ ਇਹ ਠੀਕ ਹੈ।</string>
|
||||||
<string name="menu_download">ਡਾਊਨਲੋਡ</string>
|
<string name="menu_download">ਡਾਊਨਲੋਡ</string>
|
||||||
<string name="preference_license" fuzzy="true">ਲਸੰਸ</string>
|
<string name="preference_license">ਮੂਲ ਲਸੰਸ</string>
|
||||||
<string name="use_previous" fuzzy="true">ਪਹਿਲਾਂ ਵਾਲਾ ਸਿਰਲੇਖ/ਜਾਣਕਾਰੀ ਵਰਤੋ</string>
|
<string name="use_previous">ਪਿਛਲੇ ਸਿਰਲੇਖ ਅਤੇ ਵੇਰਵੇ ਦੀ ਵਰਤੋਂ ਕਰੋ</string>
|
||||||
<string name="preference_theme" fuzzy="true">ਰਾਤ ਦਾ ਅੰਦਾਜ਼</string>
|
<string name="preference_theme">ਵਿਸ਼ਾ-ਵਸਤੂ</string>
|
||||||
<string name="license_name_cc_by_sa_four"> Attribution-ShareAlike 4.0</string>
|
<string name="license_name_cc_by_sa_four"> Attribution-ShareAlike 4.0</string>
|
||||||
<string name="license_name_cc_by_four"> Attribution 4.0</string>
|
<string name="license_name_cc_by_four"> Attribution 4.0</string>
|
||||||
<string name="license_name_cc_by_sa">CC Attribution-ShareAlike 3.0</string>
|
<string name="license_name_cc_by_sa">CC Attribution-ShareAlike 3.0</string>
|
||||||
|
|
@ -120,8 +140,14 @@
|
||||||
<string name="tutorial_1_text">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਜ਼ਿਆਦਾਤਰ ਉਹ ਤਸਵੀਰਾਂ ਦਾ ਭੰਡਾਰ ਹੈ ਜੋ ਵਿਕੀਪੀਡੀਆ \'ਤੇ ਵਰਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।</string>
|
<string name="tutorial_1_text">ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਜ਼ਿਆਦਾਤਰ ਉਹ ਤਸਵੀਰਾਂ ਦਾ ਭੰਡਾਰ ਹੈ ਜੋ ਵਿਕੀਪੀਡੀਆ \'ਤੇ ਵਰਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।</string>
|
||||||
<string name="tutorial_1_subtext">ਤੁਹਾਡੀਆਂ ਤਸਵੀਰਾਂ ਵਿਸ਼ਵ ਦੇ ਬਾਕੀ ਲੋਕਾਂ ਨੂੰ ਸਿੱਖਿਅਤ ਕਰਨ ਲਈ ਸਹਾਈ ਹਨ!</string>
|
<string name="tutorial_1_subtext">ਤੁਹਾਡੀਆਂ ਤਸਵੀਰਾਂ ਵਿਸ਼ਵ ਦੇ ਬਾਕੀ ਲੋਕਾਂ ਨੂੰ ਸਿੱਖਿਅਤ ਕਰਨ ਲਈ ਸਹਾਈ ਹਨ!</string>
|
||||||
<string name="tutorial_2_text">ਕਿਰਪਾ ਕਰਕੇ ਉਹ ਤਸਵੀਰਾਂ ਨੂੰ ਚੜ੍ਹਾਉ ਜੋ ਤੁਹਾਡੇ ਵੱਲੋਂ ਲਈਆਂ ਗਈਆਂ ਹਨ ਜਾਂ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ:</string>
|
<string name="tutorial_2_text">ਕਿਰਪਾ ਕਰਕੇ ਉਹ ਤਸਵੀਰਾਂ ਨੂੰ ਚੜ੍ਹਾਉ ਜੋ ਤੁਹਾਡੇ ਵੱਲੋਂ ਲਈਆਂ ਗਈਆਂ ਹਨ ਜਾਂ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ:</string>
|
||||||
|
<string name="tutorial_2_subtext_1">ਕੁਦਰਤੀ ਵਸਤੂਆਂ (ਫੁੱਲ, ਜਾਨਵਰ, ਪਹਾੜ)</string>
|
||||||
|
<string name="tutorial_2_subtext_2">ਲਾਹੇਵੰਦ ਵਸਤੂਆਂ (ਸੈਕਲ, ਰੇਲ ਅੱਡਾ)</string>
|
||||||
|
<string name="tutorial_2_subtext_3">ਮਸ਼ਹੂਰ ਲੋਕ (ਤੁਹਾਡੇ mayor, ਓਲੰਪਿਕ ਖਿਡਾਰੀ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਸੀਂ ਮਿਲੇ ਸੀ)</string>
|
||||||
<string name="tutorial_3_text">ਕਿਰਪਾ ਕਰਕੇ ਅਪਲੋਡ ਨਾ ਕਰੋ:</string>
|
<string name="tutorial_3_text">ਕਿਰਪਾ ਕਰਕੇ ਅਪਲੋਡ ਨਾ ਕਰੋ:</string>
|
||||||
|
<string name="tutorial_3_subtext_1">ਤੁਹਾਡੇ ਦੋਸਤਾਂ ਦੀਆਂ ਸੈਲਫ਼ੀਆਂ ਜਾਂ ਤਸਵੀਰਾਂ</string>
|
||||||
<string name="tutorial_4_text">ਉਦਾਹਰਣ ਵਜੋਂ ਇਹ ਅਪਲੋਡ:</string>
|
<string name="tutorial_4_text">ਉਦਾਹਰਣ ਵਜੋਂ ਇਹ ਅਪਲੋਡ:</string>
|
||||||
|
<string name="tutorial_4_subtext_1">ਸਿਰਲੇਖ: ਸਿਡਨੀ ਓਪੇਰਾ ਹਾਊਸ</string>
|
||||||
|
<string name="tutorial_4_subtext_2">ਵੇਰਵਾ: ਸਿਡਨੀ ਓਪੇਰਾ ਹਾਊਸ ਜਿਵੇਂ ਖਾੜੀ ਦੇ ਪਾਰ ਤੋਂ ਦਿਖਦਾ ਐ</string>
|
||||||
<string name="welcome_wikipedia_text">ਆਪਣੀਆਂ ਤਸਵੀਰਾਂ ਦਾ ਯੋਗਦਾਨ ਪਾਓ। ਵਿਕੀਪੀਡੀਆ ਲੇਖਾਂ ਨੂੰ ਸੁਰਜੀਤ ਕਰ ਦਿਓ!</string>
|
<string name="welcome_wikipedia_text">ਆਪਣੀਆਂ ਤਸਵੀਰਾਂ ਦਾ ਯੋਗਦਾਨ ਪਾਓ। ਵਿਕੀਪੀਡੀਆ ਲੇਖਾਂ ਨੂੰ ਸੁਰਜੀਤ ਕਰ ਦਿਓ!</string>
|
||||||
<string name="welcome_wikipedia_subtext">ਵਿਕੀਪੀਡੀਆ ਉਤਲੀਆਂ ਤਸਵੀਰਾਂ ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਤੋਂ ਆਉਂਦੀਆਂ ਹਨ</string>
|
<string name="welcome_wikipedia_subtext">ਵਿਕੀਪੀਡੀਆ ਉਤਲੀਆਂ ਤਸਵੀਰਾਂ ਵਿਕੀਮੀਡੀਆ ਕਾਮਨਜ਼ ਤੋਂ ਆਉਂਦੀਆਂ ਹਨ</string>
|
||||||
<string name="welcome_copyright_text">ਤੁਹਾਡੀਆਂ ਤਸਵੀਰਾਂ ਦੁਨੀਆਂ ਭਰ ਦੇ ਲੋਕਾਂ ਨੂੰ ਪੜ੍ਹਨ ਵਿਚ ਮਦਦ ਕਰਦੀਆਂ ਹਨ।</string>
|
<string name="welcome_copyright_text">ਤੁਹਾਡੀਆਂ ਤਸਵੀਰਾਂ ਦੁਨੀਆਂ ਭਰ ਦੇ ਲੋਕਾਂ ਨੂੰ ਪੜ੍ਹਨ ਵਿਚ ਮਦਦ ਕਰਦੀਆਂ ਹਨ।</string>
|
||||||
|
|
@ -132,6 +158,7 @@
|
||||||
<string name="detail_panel_cats_label">ਸ਼੍ਰੇਣੀਆਂ</string>
|
<string name="detail_panel_cats_label">ਸ਼੍ਰੇਣੀਆਂ</string>
|
||||||
<string name="detail_panel_cats_loading">ਲੱਦ ਰਿਹਾ ਹੈ...</string>
|
<string name="detail_panel_cats_loading">ਲੱਦ ਰਿਹਾ ਹੈ...</string>
|
||||||
<string name="detail_panel_cats_none">ਕੋਈ ਵੀ ਨਹੀਂ ਚੁਣਿਆ</string>
|
<string name="detail_panel_cats_none">ਕੋਈ ਵੀ ਨਹੀਂ ਚੁਣਿਆ</string>
|
||||||
|
<string name="detail_caption_empty">ਕੋਈ ਸੁਰਖੀ ਨਹੀਂ</string>
|
||||||
<string name="detail_description_empty">ਕੋਈ ਵੇਰਵਾ ਨਹੀਂ</string>
|
<string name="detail_description_empty">ਕੋਈ ਵੇਰਵਾ ਨਹੀਂ</string>
|
||||||
<string name="detail_discussion_empty">ਕੋਈ ਗੱਲਬਾਤ ਨਹੀਂ</string>
|
<string name="detail_discussion_empty">ਕੋਈ ਗੱਲਬਾਤ ਨਹੀਂ</string>
|
||||||
<string name="detail_license_empty">ਅਣਜਾਣ ਲਸੰਸ</string>
|
<string name="detail_license_empty">ਅਣਜਾਣ ਲਸੰਸ</string>
|
||||||
|
|
@ -139,8 +166,10 @@
|
||||||
<string name="read_storage_permission_rationale" fuzzy="true">ਆਗਿਆ ਚਾਹੀਦੀ ਹੈ: ਬਾਹਰੀ ਸਟੋਰੇਜ ਬਾਰੇ। ਇਸ ਤੋਂ ਬਿਨਾਂ ਐਪ ਕਾਰਜ ਨਹੀਂ ਕਰ ਸਕੇਗੀ।</string>
|
<string name="read_storage_permission_rationale" fuzzy="true">ਆਗਿਆ ਚਾਹੀਦੀ ਹੈ: ਬਾਹਰੀ ਸਟੋਰੇਜ ਬਾਰੇ। ਇਸ ਤੋਂ ਬਿਨਾਂ ਐਪ ਕਾਰਜ ਨਹੀਂ ਕਰ ਸਕੇਗੀ।</string>
|
||||||
<string name="ok">ਠੀਕ ਹੈ</string>
|
<string name="ok">ਠੀਕ ਹੈ</string>
|
||||||
<string name="warning">ਖ਼ਬਰਦਾਰ</string>
|
<string name="warning">ਖ਼ਬਰਦਾਰ</string>
|
||||||
|
<string name="upload">ਚੜ੍ਹਾਉ</string>
|
||||||
<string name="yes">ਹਾਂ</string>
|
<string name="yes">ਹਾਂ</string>
|
||||||
<string name="no">ਨਹੀਂ</string>
|
<string name="no">ਨਹੀਂ</string>
|
||||||
|
<string name="media_detail_caption">ਸੁਰਖੀ</string>
|
||||||
<string name="media_detail_title">ਸਿਰਲੇਖ</string>
|
<string name="media_detail_title">ਸਿਰਲੇਖ</string>
|
||||||
<string name="media_detail_description">ਵੇਰਵਾ</string>
|
<string name="media_detail_description">ਵੇਰਵਾ</string>
|
||||||
<string name="media_detail_discussion">ਗੱਲਬਾਤ</string>
|
<string name="media_detail_discussion">ਗੱਲਬਾਤ</string>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
<string name="menu_settings">امستنې</string>
|
<string name="menu_settings">امستنې</string>
|
||||||
<string name="intent_share_upload_label">خونديځ ته راپورته کول</string>
|
<string name="intent_share_upload_label">خونديځ ته راپورته کول</string>
|
||||||
<string name="upload_in_progress">راپورته کول جريان لري</string>
|
<string name="upload_in_progress">راپورته کول جريان لري</string>
|
||||||
<string name="username">کارننوم</string>
|
<string name="username">کارننوم</string>
|
||||||
<string name="password">پټنوم</string>
|
<string name="password">پټنوم</string>
|
||||||
<string name="login_credential">خپل خونديځ بېټا ګڼون ته ورننوځئ</string>
|
<string name="login_credential">خپل خونديځ بېټا ګڼون ته ورننوځئ</string>
|
||||||
<string name="login">ننوتل</string>
|
<string name="login">ننوتل</string>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
* A100Star
|
* A100Star
|
||||||
* Ajeje Brazorf
|
* Ajeje Brazorf
|
||||||
* Amire80
|
* Amire80
|
||||||
|
* Annick green
|
||||||
* Cabal
|
* Cabal
|
||||||
* Googology
|
* Googology
|
||||||
* LeGuyanaisPure
|
* LeGuyanaisPure
|
||||||
|
|
@ -27,6 +28,7 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="all">
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="all">
|
||||||
<string name="submit">{{Identical|Submit}}</string>
|
<string name="submit">{{Identical|Submit}}</string>
|
||||||
<string name="nearby_all">{{identical|All}}</string>
|
<string name="nearby_all">{{identical|All}}</string>
|
||||||
|
<string name="nearby_filter_search">Reba ishakiro</string>
|
||||||
<string name="uploads_pending_notification_indicator">Status text about number of uploads left.\n* %1$d represents number of uploads left, including current one</string>
|
<string name="uploads_pending_notification_indicator">Status text about number of uploads left.\n* %1$d represents number of uploads left, including current one</string>
|
||||||
<string name="contributions_subtitle">See the current issue [https://phabricator.wikimedia.org/T267142 T267142] tracked in Phabricator about the <code><nowiki>|zero=</nowiki></code> option currently not supported on Translatewiki.net with the custom <code><nowiki>{{PLURAL}}</nowiki></code> rules used by this project for Android, using a non-MediaWiki syntax.</string>
|
<string name="contributions_subtitle">See the current issue [https://phabricator.wikimedia.org/T267142 T267142] tracked in Phabricator about the <code><nowiki>|zero=</nowiki></code> option currently not supported on Translatewiki.net with the custom <code><nowiki>{{PLURAL}}</nowiki></code> rules used by this project for Android, using a non-MediaWiki syntax.</string>
|
||||||
<string name="multiple_uploads_title">{{Identical|Upload}}</string>
|
<string name="multiple_uploads_title">{{Identical|Upload}}</string>
|
||||||
|
|
@ -190,6 +192,7 @@
|
||||||
<string name="depictions_edit_helper_edit_message_else">{{Doc-commons-app-depicts}}</string>
|
<string name="depictions_edit_helper_edit_message_else">{{Doc-commons-app-depicts}}</string>
|
||||||
<string name="title_app_shortcut_bookmark">{{identical|Bookmark}}</string>
|
<string name="title_app_shortcut_bookmark">{{identical|Bookmark}}</string>
|
||||||
<string name="theme_default_name">Option to make the app\'s theme follow the global system setting.</string>
|
<string name="theme_default_name">Option to make the app\'s theme follow the global system setting.</string>
|
||||||
|
<string name="nearby_needs_location">‘Nearby’ should be translated as in {{msg-wm|Commons-android-strings-navigation item nearby}}</string>
|
||||||
<string name="more">{{Identical|More}}</string>
|
<string name="more">{{Identical|More}}</string>
|
||||||
<string name="map_attribution">{{Optional}}\n<code>&amp;#169;</code> is the copyright symbol (©).</string>
|
<string name="map_attribution">{{Optional}}\n<code>&amp;#169;</code> is the copyright symbol (©).</string>
|
||||||
<string name="categories_tooltip">{{Doc-commons-app-depicts}}</string>
|
<string name="categories_tooltip">{{Doc-commons-app-depicts}}</string>
|
||||||
|
|
@ -202,9 +205,12 @@
|
||||||
<string name="done">{{identical|Done}}</string>
|
<string name="done">{{identical|Done}}</string>
|
||||||
<string name="edit_depictions">{{Doc-commons-app-depicts}}</string>
|
<string name="edit_depictions">{{Doc-commons-app-depicts}}</string>
|
||||||
<string name="advanced_options">{{Identical|Advanced options}}</string>
|
<string name="advanced_options">{{Identical|Advanced options}}</string>
|
||||||
|
<string name="advanced_query_info_text">‘Nearby’ should be translated as in {{msg-wm|Commons-android-strings-navigation item nearby}}</string>
|
||||||
<string name="explore_map_details">{{Identical|Detail}}</string>
|
<string name="explore_map_details">{{Identical|Detail}}</string>
|
||||||
<string name="set_up_avatar_toast_string">\"Set as avatar\" should be translated the same as {{msg-wm|Commons-android-strings-menu set avatar}}.</string>
|
<string name="set_up_avatar_toast_string">\"Set as avatar\" should be translated the same as {{msg-wm|Commons-android-strings-menu set avatar}}.</string>
|
||||||
<string name="multiple_files_depiction">{{Doc-commons-app-depicts}}</string>
|
<string name="multiple_files_depiction">{{Doc-commons-app-depicts}}</string>
|
||||||
<string name="custom_selector_delete">An answer to the question in {{msg-wm|Commons-android-strings-custom selector confirm deletion message}}.</string>
|
<string name="custom_selector_delete">An answer to the question in {{msg-wm|Commons-android-strings-custom selector confirm deletion message}}.</string>
|
||||||
<string name="bullet_point">{{optional}}</string>
|
<string name="bullet_point">{{optional}}</string>
|
||||||
|
<string name="show_in_explore">“Explore” should be translated as in {{msg-wm|Commons-android-strings-navigation item explore}}</string>
|
||||||
|
<string name="show_in_nearby">‘Nearby’ should be translated as in {{msg-wm|Commons-android-strings-navigation item nearby}}</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -876,6 +876,7 @@
|
||||||
<string name="account">Учётная запись</string>
|
<string name="account">Учётная запись</string>
|
||||||
<string name="vanish_account">Удалить учётную запись</string>
|
<string name="vanish_account">Удалить учётную запись</string>
|
||||||
<string name="account_vanish_request_confirm_title">Предупреждение об удалении учётной записи</string>
|
<string name="account_vanish_request_confirm_title">Предупреждение об удалении учётной записи</string>
|
||||||
|
<string name="account_vanish_request_confirm">Удаление — это <b>крайняя мера</b>, и её следует <b>использовать только в том случае, если вы хотите навсегда прекратить редактирование</b>, а также скрыть как можно больше связанных с вами действий.<br/><br/> Удаление вашей учётной записи на Викискладе осуществляется путём изменения её имени, чтобы другие не могли определить ваши действия. <b>Удаление не гарантирует полной анонимности или удаления вклада в проектах</b>.</string>
|
||||||
<string name="caption">Подпись</string>
|
<string name="caption">Подпись</string>
|
||||||
<string name="caption_copied_to_clipboard">Подпись скопирована в буфер обмена</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="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Поздравляем, все фотографии в этом альбоме либо загружены, либо помечены как не предназначенные для загрузки.</string>
|
||||||
|
|
|
||||||
|
|
@ -821,4 +821,6 @@
|
||||||
<string name="caption">Bildtext</string>
|
<string name="caption">Bildtext</string>
|
||||||
<string name="caption_copied_to_clipboard">Bildtext kopierades till urklipp</string>
|
<string name="caption_copied_to_clipboard">Bildtext kopierades till urklipp</string>
|
||||||
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Grattis! Alla bilder i detta album har antingen laddats upp eller markerats för att inte laddas upp.</string>
|
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Grattis! Alla bilder i detta album har antingen laddats upp eller markerats för att inte laddas upp.</string>
|
||||||
|
<string name="show_in_explore">Visa i \"Utforska\"</string>
|
||||||
|
<string name="show_in_nearby">Visa i \"I närheten\"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
<string name="upload_progress_notification_title_start">%s ಅಪ್ಲೋಡ್ ಸುರು ಆವೊಂದುಂಡು</string>
|
<string name="upload_progress_notification_title_start">%s ಅಪ್ಲೋಡ್ ಸುರು ಆವೊಂದುಂಡು</string>
|
||||||
<string name="upload_progress_notification_title_in_progress">%1$s ಅಪ್ಲೋಡ್ ಆವೊಂದುಂಡು</string>
|
<string name="upload_progress_notification_title_in_progress">%1$s ಅಪ್ಲೋಡ್ ಆವೊಂದುಂಡು</string>
|
||||||
<string name="upload_progress_notification_title_finishing">%1$s ಅಪ್ಲೋಡ್ ಕೈದ್ ಆವೊಂದುಂಡು.</string>
|
<string name="upload_progress_notification_title_finishing">%1$s ಅಪ್ಲೋಡ್ ಕೈದ್ ಆವೊಂದುಂಡು.</string>
|
||||||
<string name="upload_failed_notification_title" fuzzy="true">%1$s ಅಪ್ಲೋಡ್ ಸರಿ ಆತಿಜಿ</string>
|
<string name="upload_failed_notification_title">%1$s ಅಪ್ಲೋಡ್ ಆತಿಜಿ</string>
|
||||||
<string name="upload_failed_notification_subtitle">ತುಯಾರ ಮೆಲ್ಲ ಒತ್ತುಲೆ</string>
|
<string name="upload_failed_notification_subtitle">ತುಯಾರ ಮೆಲ್ಲ ಒತ್ತುಲೆ</string>
|
||||||
<string name="title_activity_contributions">ಎನ್ನ ದಿಂಜಯೀನಾ ವಿಚಾರೊಳು</string>
|
<string name="title_activity_contributions">ಎನ್ನ ದಿಂಜಯೀನಾ ವಿಚಾರೊಳು</string>
|
||||||
<string name="contribution_state_queued">ದಿಂಜೊಂತುಂಡು</string>
|
<string name="contribution_state_queued">ದಿಂಜೊಂತುಂಡು</string>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import android.database.MatrixCursor
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.nhaarman.mockitokotlin2.any
|
import com.nhaarman.mockitokotlin2.any
|
||||||
import com.nhaarman.mockitokotlin2.anyOrNull
|
import com.nhaarman.mockitokotlin2.anyOrNull
|
||||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||||
|
|
@ -18,36 +20,20 @@ import com.nhaarman.mockitokotlin2.mock
|
||||||
import com.nhaarman.mockitokotlin2.verify
|
import com.nhaarman.mockitokotlin2.verify
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.TestCommonsApplication
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsContentProvider.BASE_URI
|
import fr.free.nrw.commons.db.AppDatabase
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_CATEGORY
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_COMMONS_LINK
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_DESCRIPTION
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_EXISTS
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_IMAGE_URL
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_ICON
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LABEL_TEXT
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LANGUAGE
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LAT
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_LONG
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_NAME
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_PIC
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIDATA_LINK
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.COLUMN_WIKIPEDIA_LINK
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.CREATE_TABLE_STATEMENT
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.DROP_TABLE_STATEMENT
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onCreate
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onDelete
|
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao.Table.onUpdate
|
|
||||||
import fr.free.nrw.commons.location.LatLng
|
import fr.free.nrw.commons.location.LatLng
|
||||||
import fr.free.nrw.commons.nearby.Label
|
import fr.free.nrw.commons.nearby.Label
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
import fr.free.nrw.commons.nearby.Sitelinks
|
import fr.free.nrw.commons.nearby.Sitelinks
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.verifyNoInteractions
|
import org.mockito.Mockito.verifyNoInteractions
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
@ -55,28 +41,11 @@ import org.robolectric.annotation.Config
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class BookMarkLocationDaoTest {
|
class BookMarkLocationDaoTest {
|
||||||
private val columns =
|
|
||||||
arrayOf(
|
|
||||||
COLUMN_NAME,
|
|
||||||
COLUMN_LANGUAGE,
|
|
||||||
COLUMN_DESCRIPTION,
|
|
||||||
COLUMN_CATEGORY,
|
|
||||||
COLUMN_LABEL_TEXT,
|
|
||||||
COLUMN_LABEL_ICON,
|
|
||||||
COLUMN_IMAGE_URL,
|
|
||||||
COLUMN_WIKIPEDIA_LINK,
|
|
||||||
COLUMN_WIKIDATA_LINK,
|
|
||||||
COLUMN_COMMONS_LINK,
|
|
||||||
COLUMN_LAT,
|
|
||||||
COLUMN_LONG,
|
|
||||||
COLUMN_PIC,
|
|
||||||
COLUMN_EXISTS,
|
|
||||||
)
|
|
||||||
private val client: ContentProviderClient = mock()
|
|
||||||
private val database: SQLiteDatabase = mock()
|
|
||||||
private val captor = argumentCaptor<ContentValues>()
|
|
||||||
|
|
||||||
private lateinit var testObject: BookmarkLocationsDao
|
private lateinit var bookmarkLocationsDao: BookmarkLocationsDao
|
||||||
|
|
||||||
|
private lateinit var database: AppDatabase
|
||||||
|
|
||||||
private lateinit var examplePlaceBookmark: Place
|
private lateinit var examplePlaceBookmark: Place
|
||||||
private lateinit var exampleLabel: Label
|
private lateinit var exampleLabel: Label
|
||||||
private lateinit var exampleUri: Uri
|
private lateinit var exampleUri: Uri
|
||||||
|
|
@ -89,10 +58,18 @@ class BookMarkLocationDaoTest {
|
||||||
exampleUri = Uri.parse("wikimedia/uri")
|
exampleUri = Uri.parse("wikimedia/uri")
|
||||||
exampleLocation = LatLng(40.0, 51.4, 1f)
|
exampleLocation = LatLng(40.0, 51.4, 1f)
|
||||||
|
|
||||||
builder = Sitelinks.Builder()
|
database = Room.inMemoryDatabaseBuilder(
|
||||||
builder.setWikipediaLink("wikipediaLink")
|
ApplicationProvider.getApplicationContext(),
|
||||||
builder.setWikidataLink("wikidataLink")
|
AppDatabase::class.java
|
||||||
builder.setCommonsLink("commonsLink")
|
).allowMainThreadQueries().build()
|
||||||
|
|
||||||
|
bookmarkLocationsDao = database.bookmarkLocationsDao()
|
||||||
|
|
||||||
|
builder = Sitelinks.Builder().apply {
|
||||||
|
setWikipediaLink("wikipediaLink")
|
||||||
|
setWikidataLink("wikidataLink")
|
||||||
|
setCommonsLink("commonsLink")
|
||||||
|
}
|
||||||
|
|
||||||
examplePlaceBookmark =
|
examplePlaceBookmark =
|
||||||
Place(
|
Place(
|
||||||
|
|
@ -106,236 +83,75 @@ class BookMarkLocationDaoTest {
|
||||||
"picName",
|
"picName",
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
testObject = BookmarkLocationsDao { client }
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
database.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun createTable() {
|
fun testForAddAndGetAllBookmarkLocations() = runBlocking {
|
||||||
onCreate(database)
|
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
|
||||||
|
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
|
||||||
|
|
||||||
|
assertEquals(1, bookmarks.size)
|
||||||
|
val retrievedBookmark = bookmarks.first()
|
||||||
|
assertEquals(examplePlaceBookmark.name, retrievedBookmark.locationName)
|
||||||
|
assertEquals(examplePlaceBookmark.language, retrievedBookmark.locationLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun deleteTable() {
|
fun testFindBookmarkByNameForTrue() = runBlocking {
|
||||||
onDelete(database)
|
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||||
inOrder(database) {
|
|
||||||
verify(database).execSQL(DROP_TABLE_STATEMENT)
|
val exists = bookmarkLocationsDao.findBookmarkLocation(examplePlaceBookmark.name)
|
||||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
assertTrue(exists)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun createFromCursor() {
|
fun testFindBookmarkByNameForFalse() = runBlocking {
|
||||||
createCursor(1).let { cursor ->
|
bookmarkLocationsDao.addBookmarkLocation(examplePlaceBookmark.toBookmarksLocations())
|
||||||
cursor.moveToFirst()
|
|
||||||
testObject.fromCursor(cursor).let {
|
val exists = bookmarkLocationsDao.findBookmarkLocation("xyz")
|
||||||
assertEquals("en", it.language)
|
assertFalse(exists)
|
||||||
assertEquals("placeName", it.name)
|
|
||||||
assertEquals(Label.FOREST, it.label)
|
|
||||||
assertEquals("placeDescription", it.longDescription)
|
|
||||||
assertEquals(40.0, it.location.latitude, 0.001)
|
|
||||||
assertEquals(51.4, it.location.longitude, 0.001)
|
|
||||||
assertEquals("placeCategory", it.category)
|
|
||||||
assertEquals(builder.build().wikipediaLink, it.siteLinks.wikipediaLink)
|
|
||||||
assertEquals(builder.build().wikidataLink, it.siteLinks.wikidataLink)
|
|
||||||
assertEquals(builder.build().commonsLink, it.siteLinks.commonsLink)
|
|
||||||
assertEquals("picName", it.pic)
|
|
||||||
assertEquals(false, it.exists)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getAllLocationBookmarks() {
|
fun testDeleteBookmark() = runBlocking {
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(14))
|
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
|
||||||
|
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
|
||||||
|
|
||||||
var result = testObject.allBookmarksLocations
|
bookmarkLocationsDao.deleteBookmarkLocation(bookmarkLocation)
|
||||||
|
|
||||||
assertEquals(14, result.size)
|
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocations()
|
||||||
}
|
assertTrue(bookmarks.isEmpty())
|
||||||
|
|
||||||
@Test(expected = RuntimeException::class)
|
|
||||||
fun getAllLocationBookmarksTranslatesExceptions() {
|
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
|
|
||||||
testObject.allBookmarksLocations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getAllLocationBookmarksReturnsEmptyList_emptyCursor() {
|
fun testUpdateBookmarkForTrue() = runBlocking {
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(createCursor(0))
|
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
|
||||||
assertTrue(testObject.allBookmarksLocations.isEmpty())
|
|
||||||
|
assertTrue(exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getAllLocationBookmarksReturnsEmptyList_nullCursor() {
|
fun testUpdateBookmarkForFalse() = runBlocking {
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(null)
|
val newBookmark = examplePlaceBookmark.toBookmarksLocations()
|
||||||
assertTrue(testObject.allBookmarksLocations.isEmpty())
|
bookmarkLocationsDao.addBookmarkLocation(newBookmark)
|
||||||
|
|
||||||
|
val exists = bookmarkLocationsDao.updateBookmarkLocation(examplePlaceBookmark)
|
||||||
|
assertFalse(exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun cursorsAreClosedAfterGetAllLocationBookmarksQuery() {
|
fun testGetAllBookmarksLocationsPlace() = runBlocking {
|
||||||
val mockCursor: Cursor = mock()
|
val bookmarkLocation = examplePlaceBookmark.toBookmarksLocations()
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
|
bookmarkLocationsDao.addBookmarkLocation(bookmarkLocation)
|
||||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
|
||||||
|
|
||||||
testObject.allBookmarksLocations
|
val bookmarks = bookmarkLocationsDao.getAllBookmarksLocationsPlace()
|
||||||
|
assertEquals(1, bookmarks.size)
|
||||||
verify(mockCursor).close()
|
assertEquals(examplePlaceBookmark.name, bookmarks.first().name)
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun updateNewLocationBookmark() {
|
|
||||||
whenever(client.insert(any(), any())).thenReturn(Uri.EMPTY)
|
|
||||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
|
||||||
|
|
||||||
assertTrue(testObject.updateBookmarkLocation(examplePlaceBookmark))
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture())
|
|
||||||
captor.firstValue.let { cv ->
|
|
||||||
assertEquals(13, cv.size())
|
|
||||||
assertEquals(examplePlaceBookmark.name, cv.getAsString(COLUMN_NAME))
|
|
||||||
assertEquals(examplePlaceBookmark.language, cv.getAsString(COLUMN_LANGUAGE))
|
|
||||||
assertEquals(examplePlaceBookmark.longDescription, cv.getAsString(COLUMN_DESCRIPTION))
|
|
||||||
assertEquals(examplePlaceBookmark.label.text, cv.getAsString(COLUMN_LABEL_TEXT))
|
|
||||||
assertEquals(examplePlaceBookmark.category, cv.getAsString(COLUMN_CATEGORY))
|
|
||||||
assertEquals(examplePlaceBookmark.location.latitude, cv.getAsDouble(COLUMN_LAT), 0.001)
|
|
||||||
assertEquals(examplePlaceBookmark.location.longitude, cv.getAsDouble(COLUMN_LONG), 0.001)
|
|
||||||
assertEquals(examplePlaceBookmark.siteLinks.wikipediaLink.toString(), cv.getAsString(COLUMN_WIKIPEDIA_LINK))
|
|
||||||
assertEquals(examplePlaceBookmark.siteLinks.wikidataLink.toString(), cv.getAsString(COLUMN_WIKIDATA_LINK))
|
|
||||||
assertEquals(examplePlaceBookmark.siteLinks.commonsLink.toString(), cv.getAsString(COLUMN_COMMONS_LINK))
|
|
||||||
assertEquals(examplePlaceBookmark.pic, cv.getAsString(COLUMN_PIC))
|
|
||||||
assertEquals(examplePlaceBookmark.exists.toString(), cv.getAsString(COLUMN_EXISTS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun updateExistingLocationBookmark() {
|
|
||||||
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
|
|
||||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
|
||||||
|
|
||||||
assertFalse(testObject.updateBookmarkLocation(examplePlaceBookmark))
|
|
||||||
verify(client).delete(eq(BookmarkLocationsContentProvider.uriForName(examplePlaceBookmark.name)), isNull(), isNull())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun findExistingLocationBookmark() {
|
|
||||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
|
||||||
assertTrue(testObject.findBookmarkLocation(examplePlaceBookmark))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException::class)
|
|
||||||
fun findLocationBookmarkTranslatesExceptions() {
|
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenThrow(RemoteException(""))
|
|
||||||
testObject.findBookmarkLocation(examplePlaceBookmark)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun findNotExistingLocationBookmarkReturnsNull_emptyCursor() {
|
|
||||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(0))
|
|
||||||
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun findNotExistingLocationBookmarkReturnsNull_nullCursor() {
|
|
||||||
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(null)
|
|
||||||
assertFalse(testObject.findBookmarkLocation(examplePlaceBookmark))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun cursorsAreClosedAfterFindLocationBookmarkQuery() {
|
|
||||||
val mockCursor: Cursor = mock()
|
|
||||||
whenever(client.query(any(), any(), anyOrNull(), any(), anyOrNull())).thenReturn(mockCursor)
|
|
||||||
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
|
||||||
|
|
||||||
testObject.findBookmarkLocation(examplePlaceBookmark)
|
|
||||||
|
|
||||||
verify(mockCursor).close()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v1_to_v2() {
|
|
||||||
onUpdate(database, 1, 2)
|
|
||||||
// Table didn't exist before v5
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v2_to_v3() {
|
|
||||||
onUpdate(database, 2, 3)
|
|
||||||
// Table didn't exist before v5
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v3_to_v4() {
|
|
||||||
onUpdate(database, 3, 4)
|
|
||||||
// Table didnt exist before v5
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v4_to_v5() {
|
|
||||||
onUpdate(database, 4, 5)
|
|
||||||
// Table didnt change in version 5
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v5_to_v6() {
|
|
||||||
onUpdate(database, 5, 6)
|
|
||||||
// Table didnt change in version 6
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v6_to_v7() {
|
|
||||||
onUpdate(database, 6, 7)
|
|
||||||
// Table didnt change in version 7
|
|
||||||
verifyNoInteractions(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v7_to_v8() {
|
|
||||||
onUpdate(database, 7, 8)
|
|
||||||
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v12_to_v13() {
|
|
||||||
onUpdate(database, 12, 13)
|
|
||||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v13_to_v14() {
|
|
||||||
onUpdate(database, 13, 14)
|
|
||||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_language STRING;")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun migrateTableVersionFrom_v14_to_v15() {
|
|
||||||
onUpdate(database, 14, 15)
|
|
||||||
verify(database).execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_exists STRING;")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCursor(rows: Int): Cursor =
|
|
||||||
MatrixCursor(columns, rows).apply {
|
|
||||||
repeat(rows) {
|
|
||||||
newRow().apply {
|
|
||||||
add("placeName")
|
|
||||||
add("en")
|
|
||||||
add("placeDescription")
|
|
||||||
add("placeCategory")
|
|
||||||
add(Label.FOREST.text)
|
|
||||||
add(Label.FOREST.icon)
|
|
||||||
add("placeImage")
|
|
||||||
add("wikipediaLink")
|
|
||||||
add("wikidataLink")
|
|
||||||
add("commonsLink")
|
|
||||||
add(40.0)
|
|
||||||
add(51.4)
|
|
||||||
add("picName")
|
|
||||||
add(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.bookmarks.locations
|
||||||
|
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.nearby.Place
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -19,10 +20,12 @@ class BookmarkLocationControllerTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.openMocks(this)
|
||||||
whenever(bookmarkDao!!.allBookmarksLocations)
|
runBlocking {
|
||||||
|
whenever(bookmarkDao!!.getAllBookmarksLocationsPlace())
|
||||||
.thenReturn(mockBookmarkList)
|
.thenReturn(mockBookmarkList)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get mock bookmark list
|
* Get mock bookmark list
|
||||||
|
|
@ -66,7 +69,7 @@ class BookmarkLocationControllerTest {
|
||||||
* Test case where all bookmark locations are fetched and media is found against it
|
* Test case where all bookmark locations are fetched and media is found against it
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun loadBookmarkedLocations() {
|
fun loadBookmarkedLocations() = runBlocking {
|
||||||
val bookmarkedLocations =
|
val bookmarkedLocations =
|
||||||
bookmarkLocationsController.loadFavoritesLocations()
|
bookmarkLocationsController.loadFavoritesLocations()
|
||||||
Assert.assertEquals(2, bookmarkedLocations.size.toLong())
|
Assert.assertEquals(2, bookmarkedLocations.size.toLong())
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import com.nhaarman.mockitokotlin2.verify
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.OkHttpConnectionFactory
|
import fr.free.nrw.commons.OkHttpConnectionFactory
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
|
|
@ -22,11 +23,14 @@ import fr.free.nrw.commons.nearby.Place
|
||||||
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
|
import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions
|
||||||
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
|
import fr.free.nrw.commons.nearby.fragments.PlaceAdapter
|
||||||
import fr.free.nrw.commons.profile.ProfileActivity
|
import fr.free.nrw.commons.profile.ProfileActivity
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.spy
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
import org.powermock.reflect.Whitebox
|
import org.powermock.reflect.Whitebox
|
||||||
import org.robolectric.Robolectric
|
import org.robolectric.Robolectric
|
||||||
|
|
@ -129,12 +133,14 @@ class BookmarkLocationFragmentUnitTests {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun testInitNonEmpty() {
|
fun testInitNonEmpty() {
|
||||||
|
runBlocking {
|
||||||
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
||||||
val method: Method =
|
val method: Method =
|
||||||
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
|
BookmarkLocationsFragment::class.java.getDeclaredMethod("initList")
|
||||||
method.isAccessible = true
|
method.isAccessible = true
|
||||||
method.invoke(fragment)
|
method.invoke(fragment)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test onCreateView
|
* test onCreateView
|
||||||
|
|
@ -168,7 +174,11 @@ class BookmarkLocationFragmentUnitTests {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun testOnResume() {
|
fun testOnResume() = runBlocking {
|
||||||
fragment.onResume()
|
val fragmentSpy = spy(fragment)
|
||||||
|
whenever(controller.loadFavoritesLocations()).thenReturn(mockBookmarkList)
|
||||||
|
|
||||||
|
fragmentSpy.onResume()
|
||||||
|
verify(fragmentSpy).initList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ class DeleteHelperTest {
|
||||||
).thenReturn("Media successfully deleted: Test Media Title")
|
).thenReturn("Media successfully deleted: Test Media Title")
|
||||||
|
|
||||||
val creatorName = "Creator"
|
val creatorName = "Creator"
|
||||||
whenever(media.author).thenReturn("$creatorName")
|
whenever(media.getAuthorOrUser()).thenReturn("$creatorName")
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
whenever(media.filename).thenReturn("Test file.jpg")
|
||||||
val makeDeletion = deleteHelper.makeDeletion(
|
val makeDeletion = deleteHelper.makeDeletion(
|
||||||
context,
|
context,
|
||||||
|
|
@ -133,7 +133,7 @@ class DeleteHelperTest {
|
||||||
|
|
||||||
whenever(media.displayTitle).thenReturn("Test file")
|
whenever(media.displayTitle).thenReturn("Test file")
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
whenever(media.filename).thenReturn("Test file.jpg")
|
||||||
whenever(media.author).thenReturn("Creator (page does not exist)")
|
whenever(media.getAuthorOrUser()).thenReturn("Creator (page does not exist)")
|
||||||
|
|
||||||
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +148,7 @@ class DeleteHelperTest {
|
||||||
.thenReturn(Observable.just(false))
|
.thenReturn(Observable.just(false))
|
||||||
whenever(media.displayTitle).thenReturn("Test file")
|
whenever(media.displayTitle).thenReturn("Test file")
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
whenever(media.filename).thenReturn("Test file.jpg")
|
||||||
whenever(media.author).thenReturn("Creator (page does not exist)")
|
whenever(media.getAuthorOrUser()).thenReturn("Creator (page does not exist)")
|
||||||
|
|
||||||
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +163,7 @@ class DeleteHelperTest {
|
||||||
.thenReturn(Observable.just(true))
|
.thenReturn(Observable.just(true))
|
||||||
whenever(media.displayTitle).thenReturn("Test file")
|
whenever(media.displayTitle).thenReturn("Test file")
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
whenever(media.filename).thenReturn("Test file.jpg")
|
||||||
whenever(media.author).thenReturn("Creator (page does not exist)")
|
whenever(media.getAuthorOrUser()).thenReturn("Creator (page does not exist)")
|
||||||
|
|
||||||
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
@ -221,7 +221,7 @@ class DeleteHelperTest {
|
||||||
whenever(media.displayTitle).thenReturn("Test file")
|
whenever(media.displayTitle).thenReturn("Test file")
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
whenever(media.filename).thenReturn("Test file.jpg")
|
||||||
|
|
||||||
whenever(media.author).thenReturn(null)
|
whenever(media.getAuthorOrUser()).thenReturn(null)
|
||||||
|
|
||||||
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import fr.free.nrw.commons.location.LatLng
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
|
||||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract
|
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract
|
||||||
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter
|
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
|
@ -463,7 +464,9 @@ class NearbyParentFragmentPresenterTest {
|
||||||
nearbyPlacesInfo.searchLatLng = latestLocation
|
nearbyPlacesInfo.searchLatLng = latestLocation
|
||||||
nearbyPlacesInfo.placeList = emptyList<Place>()
|
nearbyPlacesInfo.placeList = emptyList<Place>()
|
||||||
|
|
||||||
whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList())
|
runBlocking {
|
||||||
|
whenever(bookmarkLocationsDao.getAllBookmarksLocations()).thenReturn(Collections.emptyList())
|
||||||
|
}
|
||||||
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo.placeList, latestLocation, null)
|
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo.placeList, latestLocation, null)
|
||||||
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
|
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue