From 48c7a0372e2f1438c221932df6015f10107ce063 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Tue, 9 Jan 2018 18:16:17 +0300 Subject: [PATCH 001/184] Prepare base for new activity --- app/src/main/AndroidManifest.xml | 4 ++ .../nrw/commons/di/ActivityBuilderModule.java | 4 ++ .../nrw/commons/di/FragmentBuilderModule.java | 4 ++ .../featured/FeaturedImagesActivity.java | 60 +++++++++++++++++++ .../featured/FeaturedImagesListFragment.java | 28 +++++++++ .../commons/theme/NavigationBaseActivity.java | 5 ++ .../res/layout/activity_featured_images.xml | 44 ++++++++++++++ .../res/layout/fragment_featured_images.xml | 39 ++++++++++++ app/src/main/res/menu/drawer.xml | 6 ++ app/src/main/res/values/strings.xml | 2 + 10 files changed, 196 insertions(+) create mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java create mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java create mode 100644 app/src/main/res/layout/activity_featured_images.xml create mode 100644 app/src/main/res/layout/fragment_featured_images.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 253bdaea8..6aab09b55 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -91,6 +91,10 @@ android:name=".notification.NotificationActivity" android:label="@string/navigation_item_notification" /> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_featured_images.xml b/app/src/main/res/layout/fragment_featured_images.xml new file mode 100644 index 000000000..17c734ef7 --- /dev/null +++ b/app/src/main/res/layout/fragment_featured_images.xml @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index 83c1bf0ad..309e14c23 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -40,4 +40,10 @@ android:icon="@drawable/ic_notifications_black_24dp" android:title="@string/navigation_item_notification"/> + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bcc8c3242..aa14ddc94 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,6 +73,7 @@ Categories Settings Sign Up + Featured Images About The Wikimedia Commons app is an open-source app created and maintained by grantees and volunteers of the Wikimedia community. The Wikimedia Foundation is not involved in the creation, development, or maintenance of the app. Wikimedia Commons @@ -195,6 +196,7 @@ Logout Tutorial Notifications + Featured Nearby places cannot be displayed without location permissions no description found Commons file page From b0cd6a9a476adf6c2c8ca2c88275bccc0004ec4f Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 01:04:27 +0300 Subject: [PATCH 002/184] Add grid view and list adapter --- .../nrw/commons/featured/FeaturedImage.java | 43 ++++++++++++ .../featured/FeaturedImagesActivity.java | 10 ++- .../featured/FeaturedImagesListFragment.java | 29 +++++++- .../commons/featured/MockGridViewAdapter.java | 50 ++++++++++++++ .../res/layout/layout_featured_images.xml | 66 +++++++++++++++++++ 5 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java create mode 100644 app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java create mode 100644 app/src/main/res/layout/layout_featured_images.xml diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java new file mode 100644 index 000000000..73721897b --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java @@ -0,0 +1,43 @@ +package fr.free.nrw.commons.featured; + +import android.graphics.Bitmap; + +/** + * Created by root on 09.01.2018. + */ + +public class FeaturedImage { + private Bitmap image; + private String author; + private String fileName; + + public FeaturedImage(Bitmap image, String author, String fileName) { + this.image = image; + this.author = author; + this.fileName = fileName; + } + + public Bitmap getImage() { + return image; + } + + public void setImage(Bitmap image) { + this.image = image; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java index 7a05a9877..cf0afde68 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java @@ -1,12 +1,16 @@ package fr.free.nrw.commons.featured; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v4.app.FragmentManager; +import android.widget.GridView; + +import java.util.ArrayList; import butterknife.ButterKnife; import fr.free.nrw.commons.R; import fr.free.nrw.commons.auth.AuthenticatedActivity; -import fr.free.nrw.commons.contributions.ContributionsListFragment; import fr.free.nrw.commons.media.MediaDetailPagerFragment; /** @@ -17,7 +21,7 @@ public class FeaturedImagesActivity extends AuthenticatedActivity implements FragmentManager.OnBackStackChangedListener { - private FeaturedImagesListFragment featuredImagesList; + private FeaturedImagesListFragment featuredImagesListFragment; private MediaDetailPagerFragment mediaDetails; @Override @@ -39,7 +43,7 @@ public class FeaturedImagesActivity // Activity can call methods in the fragment by acquiring a // reference to the Fragment from FragmentManager, using findFragmentById() FragmentManager supportFragmentManager = getSupportFragmentManager(); - featuredImagesList = (FeaturedImagesListFragment)supportFragmentManager + featuredImagesListFragment = (FeaturedImagesListFragment)supportFragmentManager .findFragmentById(R.id.featuedListFragment); supportFragmentManager.addOnBackStackChangedListener(this); diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java index 2a922e3dd..905e7aa91 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java @@ -1,10 +1,16 @@ package fr.free.nrw.commons.featured; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Bundle; +import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.GridView; + +import java.util.ArrayList; import butterknife.ButterKnife; import dagger.android.support.DaggerFragment; @@ -18,11 +24,32 @@ import static android.view.View.GONE; */ public class FeaturedImagesListFragment extends DaggerFragment { + private GridView gridView; + private MockGridViewAdapter gridAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_contributions, container, false); + View v = inflater.inflate(R.layout.fragment_featured_images, container, false); ButterKnife.bind(this, v); return v; } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + gridView = (GridView) getView().findViewById(R.id.featuredImagesList); + gridAdapter = new MockGridViewAdapter(this.getContext(), R.layout.layout_featured_images, getMockFeaturedImages()); + gridView.setAdapter(gridAdapter); + + } + + private ArrayList getMockFeaturedImages(){ + ArrayList featuredImages = new ArrayList<>(); + for (int i=0; i<10; i++){ + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.commons_logo_large); + featuredImages.add(new FeaturedImage(bitmap, "username: test", "test file name")); + } + return featuredImages; + } } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java new file mode 100644 index 000000000..081495791 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java @@ -0,0 +1,50 @@ +package fr.free.nrw.commons.featured; + +import android.app.Activity; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; + +import fr.free.nrw.commons.R; + +/** + * Created by root on 09.01.2018. + */ + +public class MockGridViewAdapter extends ArrayAdapter { + private Context context; + private int layoutResourceId; + private ArrayList data = new ArrayList(); + + public MockGridViewAdapter(Context context, int layoutResourceId, ArrayList data) { + super(context, layoutResourceId, data); + this.layoutResourceId = layoutResourceId; + this.context = context; + this.data = data; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + if (convertView == null) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + convertView = inflater.inflate(R.layout.layout_featured_images, null); + } + + FeaturedImage item = data.get(position); + ImageView imageView = (ImageView) convertView.findViewById(R.id.featuredImageView); + TextView fileName = (TextView) convertView.findViewById(R.id.featuredImageTitle); + TextView author = (TextView) convertView.findViewById(R.id.featuredImageAuthor); + fileName.setText("Test file name"); + author.setText("Uploaded by: Test user name"); + imageView.setImageBitmap(item.getImage()); + return convertView; + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/layout_featured_images.xml b/app/src/main/res/layout/layout_featured_images.xml new file mode 100644 index 000000000..cabbe629f --- /dev/null +++ b/app/src/main/res/layout/layout_featured_images.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From c1a1562c181fc9ab3b9ee999b4a6b3680f88d951 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 01:07:16 +0300 Subject: [PATCH 003/184] Add star icon for featured images --- app/src/main/res/drawable/ic_star_black_24dp.xml | 9 +++++++++ app/src/main/res/menu/drawer.xml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_star_black_24dp.xml diff --git a/app/src/main/res/drawable/ic_star_black_24dp.xml b/app/src/main/res/drawable/ic_star_black_24dp.xml new file mode 100644 index 000000000..a87ca098d --- /dev/null +++ b/app/src/main/res/drawable/ic_star_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index 309e14c23..91deb7576 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -42,7 +42,7 @@ From 5e6fb44f904f754ac6dcf7f49a17533d468e9e5a Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 15:14:04 +0300 Subject: [PATCH 004/184] Change nav item string --- app/src/main/res/menu/drawer.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml index 91deb7576..3a62183d4 100644 --- a/app/src/main/res/menu/drawer.xml +++ b/app/src/main/res/menu/drawer.xml @@ -43,7 +43,7 @@ + android:title="@string/navigation_item_featured_images"/> From 930cc3afb1d1909f070ad0d93e1f3bda909e79fa Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 15:16:31 +0300 Subject: [PATCH 005/184] Set progressbar invisible --- app/src/main/res/layout/fragment_featured_images.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/fragment_featured_images.xml b/app/src/main/res/layout/fragment_featured_images.xml index 17c734ef7..ca45f44c3 100644 --- a/app/src/main/res/layout/fragment_featured_images.xml +++ b/app/src/main/res/layout/fragment_featured_images.xml @@ -21,6 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" + android:visibility="gone" android:id="@+id/loadingFeaturedImagesProgressBar" /> From 1059ec4dff6a30717f8c1a00f15f74bea4580463 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 17:33:39 +0300 Subject: [PATCH 006/184] Use MediaWikiView instead of Bitmap --- .../fr/free/nrw/commons/featured/FeaturedImage.java | 11 +++++++---- .../commons/featured/FeaturedImagesListFragment.java | 4 +++- .../nrw/commons/featured/MockGridViewAdapter.java | 7 +++++-- app/src/main/res/layout/layout_featured_images.xml | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java index 73721897b..d291b04a3 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java @@ -2,26 +2,29 @@ package fr.free.nrw.commons.featured; import android.graphics.Bitmap; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.MediaWikiImageView; + /** * Created by root on 09.01.2018. */ public class FeaturedImage { - private Bitmap image; + private Media image; private String author; private String fileName; - public FeaturedImage(Bitmap image, String author, String fileName) { + public FeaturedImage(Media image, String author, String fileName) { this.image = image; this.author = author; this.fileName = fileName; } - public Bitmap getImage() { + public Media getImage() { return image; } - public void setImage(Bitmap image) { + public void setImage(Media image) { this.image = image; } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java index 905e7aa91..09c684587 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java @@ -14,6 +14,8 @@ import java.util.ArrayList; import butterknife.ButterKnife; import dagger.android.support.DaggerFragment; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.R; import timber.log.Timber; @@ -48,7 +50,7 @@ public class FeaturedImagesListFragment extends DaggerFragment { ArrayList featuredImages = new ArrayList<>(); for (int i=0; i<10; i++){ Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.commons_logo_large); - featuredImages.add(new FeaturedImage(bitmap, "username: test", "test file name")); + featuredImages.add(new FeaturedImage(new Media("test.jpg"), "username: test", "test file name")); } return featuredImages; } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java index 081495791..1b83517b3 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java @@ -11,6 +11,7 @@ import android.widget.TextView; import java.util.ArrayList; +import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.R; /** @@ -38,12 +39,14 @@ public class MockGridViewAdapter extends ArrayAdapter { } FeaturedImage item = data.get(position); - ImageView imageView = (ImageView) convertView.findViewById(R.id.featuredImageView); + //ImageView imageView = (ImageView) convertView.findViewById(R.id.featuredImageView); + MediaWikiImageView imageView = (MediaWikiImageView) convertView.findViewById(R.id.featuredImageView); TextView fileName = (TextView) convertView.findViewById(R.id.featuredImageTitle); TextView author = (TextView) convertView.findViewById(R.id.featuredImageAuthor); fileName.setText("Test file name"); author.setText("Uploaded by: Test user name"); - imageView.setImageBitmap(item.getImage()); + imageView.setMedia(item.getImage()); + //imageView.setImageBitmap(item.getImage().getDrawingCache()); return convertView; } diff --git a/app/src/main/res/layout/layout_featured_images.xml b/app/src/main/res/layout/layout_featured_images.xml index cabbe629f..399321719 100644 --- a/app/src/main/res/layout/layout_featured_images.xml +++ b/app/src/main/res/layout/layout_featured_images.xml @@ -18,7 +18,7 @@ android:layout_gravity="end|bottom" /> - Date: Wed, 10 Jan 2018 18:04:47 +0300 Subject: [PATCH 007/184] Add cilck listener to adapter to show Media Detail Screen --- .../featured/FeaturedImagesActivity.java | 56 ++++++++++++++++++- .../featured/FeaturedImagesListFragment.java | 8 ++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java index cf0afde68..ba13d34bd 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java @@ -1,14 +1,18 @@ package fr.free.nrw.commons.featured; +import android.database.DataSetObserver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v4.app.FragmentManager; +import android.view.View; +import android.widget.AdapterView; import android.widget.GridView; import java.util.ArrayList; import butterknife.ButterKnife; +import fr.free.nrw.commons.Media; import fr.free.nrw.commons.R; import fr.free.nrw.commons.auth.AuthenticatedActivity; import fr.free.nrw.commons.media.MediaDetailPagerFragment; @@ -19,7 +23,9 @@ import fr.free.nrw.commons.media.MediaDetailPagerFragment; public class FeaturedImagesActivity extends AuthenticatedActivity - implements FragmentManager.OnBackStackChangedListener { + implements FragmentManager.OnBackStackChangedListener, + MediaDetailPagerFragment.MediaDetailProvider, + AdapterView.OnItemClickListener{ private FeaturedImagesListFragment featuredImagesListFragment; private MediaDetailPagerFragment mediaDetails; @@ -61,4 +67,52 @@ public class FeaturedImagesActivity public void onBackStackChanged() { } + + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (mediaDetails == null || !mediaDetails.isVisible()) { + mediaDetails = new MediaDetailPagerFragment(); + FragmentManager supportFragmentManager = getSupportFragmentManager(); + supportFragmentManager + .beginTransaction() + .replace(R.id.featuredFragmentContainer, mediaDetails) + .addToBackStack(null) + .commit(); + supportFragmentManager.executePendingTransactions(); + } + mediaDetails.showImage(i); + } + + @Override + public Media getMediaAtPosition(int i) { + if (featuredImagesListFragment.getAdapter() == null) { + // not yet ready to return data + return null; + } else { + return ((FeaturedImage)featuredImagesListFragment.getAdapter().getItem(i)).getImage(); + } + } + + @Override + public int getTotalMediaCount() { + if (featuredImagesListFragment.getAdapter() == null) { + return 0; + } + return featuredImagesListFragment.getAdapter().getCount(); + } + + @Override + public void notifyDatasetChanged() { + + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + + } } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java index 09c684587..55b93030a 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java @@ -9,6 +9,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.GridView; +import android.widget.ListAdapter; import java.util.ArrayList; @@ -40,7 +41,8 @@ public class FeaturedImagesListFragment extends DaggerFragment { public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - gridView = (GridView) getView().findViewById(R.id.featuredImagesList); + gridView = getView().findViewById(R.id.featuredImagesList); + gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); gridAdapter = new MockGridViewAdapter(this.getContext(), R.layout.layout_featured_images, getMockFeaturedImages()); gridView.setAdapter(gridAdapter); @@ -54,4 +56,8 @@ public class FeaturedImagesListFragment extends DaggerFragment { } return featuredImages; } + + public ListAdapter getAdapter() { + return gridView.getAdapter(); + } } From 764e8baa053ea75faf8e5fa52f740d3b279eaafe Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 10 Jan 2018 18:29:56 +0300 Subject: [PATCH 008/184] Code cleanup --- .../fr/free/nrw/commons/featured/FeaturedImage.java | 4 +--- .../nrw/commons/featured/FeaturedImagesActivity.java | 7 +------ .../commons/featured/FeaturedImagesListFragment.java | 6 ------ .../nrw/commons/featured/MockGridViewAdapter.java | 11 ++++------- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java index d291b04a3..853fba29e 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java @@ -1,12 +1,10 @@ package fr.free.nrw.commons.featured; -import android.graphics.Bitmap; import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.MediaWikiImageView; /** - * Created by root on 09.01.2018. + * Object to hold FeaturedImage */ public class FeaturedImage { diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java index ba13d34bd..bf5d3089b 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java @@ -1,15 +1,10 @@ package fr.free.nrw.commons.featured; import android.database.DataSetObserver; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.view.View; import android.widget.AdapterView; -import android.widget.GridView; - -import java.util.ArrayList; import butterknife.ButterKnife; import fr.free.nrw.commons.Media; @@ -18,7 +13,7 @@ import fr.free.nrw.commons.auth.AuthenticatedActivity; import fr.free.nrw.commons.media.MediaDetailPagerFragment; /** - * Created by root on 09.01.2018. + * This activity displays pic of the days of last xx days */ public class FeaturedImagesActivity diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java index 55b93030a..3e5c37bd6 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.featured; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; @@ -16,11 +14,8 @@ import java.util.ArrayList; import butterknife.ButterKnife; import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.R; -import timber.log.Timber; -import static android.view.View.GONE; /** * Created by root on 09.01.2018. @@ -51,7 +46,6 @@ public class FeaturedImagesListFragment extends DaggerFragment { private ArrayList getMockFeaturedImages(){ ArrayList featuredImages = new ArrayList<>(); for (int i=0; i<10; i++){ - Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.commons_logo_large); featuredImages.add(new FeaturedImage(new Media("test.jpg"), "username: test", "test file name")); } return featuredImages; diff --git a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java index 1b83517b3..7aa2a8892 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java @@ -6,7 +6,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; @@ -15,7 +14,7 @@ import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.R; /** - * Created by root on 09.01.2018. + * This is created to only display UI implementation. Needs to be changed in real implementation */ public class MockGridViewAdapter extends ArrayAdapter { @@ -39,14 +38,12 @@ public class MockGridViewAdapter extends ArrayAdapter { } FeaturedImage item = data.get(position); - //ImageView imageView = (ImageView) convertView.findViewById(R.id.featuredImageView); - MediaWikiImageView imageView = (MediaWikiImageView) convertView.findViewById(R.id.featuredImageView); - TextView fileName = (TextView) convertView.findViewById(R.id.featuredImageTitle); - TextView author = (TextView) convertView.findViewById(R.id.featuredImageAuthor); + MediaWikiImageView imageView = convertView.findViewById(R.id.featuredImageView); + TextView fileName = convertView.findViewById(R.id.featuredImageTitle); + TextView author = convertView.findViewById(R.id.featuredImageAuthor); fileName.setText("Test file name"); author.setText("Uploaded by: Test user name"); imageView.setMedia(item.getImage()); - //imageView.setImageBitmap(item.getImage().getDrawingCache()); return convertView; } From 745a32107a00f32d582a9499fda88ccdcf568701 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 22 Jan 2018 13:44:33 +0300 Subject: [PATCH 009/184] Add author field to Media Detail Fragment layout --- .../main/res/layout/fragment_media_detail.xml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/app/src/main/res/layout/fragment_media_detail.xml b/app/src/main/res/layout/fragment_media_detail.xml index cffca14c6..392ea6bef 100644 --- a/app/src/main/res/layout/fragment_media_detail.xml +++ b/app/src/main/res/layout/fragment_media_detail.xml @@ -80,6 +80,39 @@ android:textSize="@dimen/description_text_size" /> + + + + + + + + + From 7e6f5f12b8a793fb49b5a1094cb6e124a634be0d Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 22 Jan 2018 13:45:21 +0300 Subject: [PATCH 010/184] Add related strings for author field --- app/src/main/res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa14ddc94..64dc31919 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -151,6 +151,8 @@ Title of the media Description Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though. + Author + Featured image author user name goes here. Uploaded date License Coordinates From 8d1850450acbdbf21ff98f63526f22cdef0b30ec Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 22 Jan 2018 13:46:47 +0300 Subject: [PATCH 011/184] Set visibility dependent to a boolean displays whether it is a featured image or contribution --- .../nrw/commons/media/MediaDetailFragment.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 75e366767..aeb28669b 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -40,14 +40,16 @@ import timber.log.Timber; public class MediaDetailFragment extends DaggerFragment { private boolean editable; + private boolean isFeaturedMedia; private MediaDetailPagerFragment.MediaDetailProvider detailProvider; private int index; - public static MediaDetailFragment forMedia(int index, boolean editable) { + public static MediaDetailFragment forMedia(int index, boolean editable, boolean isFeaturedMedia) { MediaDetailFragment mf = new MediaDetailFragment(); Bundle state = new Bundle(); state.putBoolean("editable", editable); + state.putBoolean("isFeaturedMedia", isFeaturedMedia); state.putInt("index", index); state.putInt("listIndex", 0); state.putInt("listTop", 0); @@ -66,10 +68,12 @@ public class MediaDetailFragment extends DaggerFragment { private TextView title; private TextView desc; + private TextView author; private TextView license; private TextView coordinates; private TextView uploadedDate; private LinearLayout categoryContainer; + private LinearLayout authorLayout; private ScrollView scrollView; private ArrayList categoryNames; private boolean categoriesLoaded = false; @@ -85,6 +89,7 @@ public class MediaDetailFragment extends DaggerFragment { super.onSaveInstanceState(outState); outState.putInt("index", index); outState.putBoolean("editable", editable); + outState.putBoolean("isFeaturedMedia", isFeaturedMedia); getScrollPosition(); outState.putInt("listTop", initialListTop); @@ -100,13 +105,16 @@ public class MediaDetailFragment extends DaggerFragment { if (savedInstanceState != null) { editable = savedInstanceState.getBoolean("editable"); + isFeaturedMedia = savedInstanceState.getBoolean("isFeaturedMedia"); index = savedInstanceState.getInt("index"); initialListTop = savedInstanceState.getInt("listTop"); } else { editable = getArguments().getBoolean("editable"); + isFeaturedMedia = getArguments().getBoolean("isFeaturedMedia"); index = getArguments().getInt("index"); initialListTop = 0; } + categoryNames = new ArrayList<>(); categoryNames.add(getString(R.string.detail_panel_cats_loading)); @@ -119,10 +127,18 @@ public class MediaDetailFragment extends DaggerFragment { spacer = (MediaDetailSpacer) view.findViewById(R.id.mediaDetailSpacer); title = (TextView) view.findViewById(R.id.mediaDetailTitle); desc = (TextView) view.findViewById(R.id.mediaDetailDesc); + author = (TextView) view.findViewById(R.id.mediaDetailAuthor); license = (TextView) view.findViewById(R.id.mediaDetailLicense); coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates); uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate); categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer); + authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); + + if (isFeaturedMedia){ + authorLayout.setVisibility(View.VISIBLE); + } else { + authorLayout.setVisibility(View.GONE); + } licenseList = new LicenseList(getActivity()); From e3fd47c2b12726d94a46f35d049be7ba65305358 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 22 Jan 2018 13:47:26 +0300 Subject: [PATCH 012/184] Pas control boolean --- .../nrw/commons/media/MediaDetailPagerFragment.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index 5d6e66faf..c067a9ce3 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -49,14 +49,16 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage private ViewPager pager; private Boolean editable; + private boolean isFeaturedImage; public MediaDetailPagerFragment() { - this(false); + this(false, false); } @SuppressLint("ValidFragment") - public MediaDetailPagerFragment(Boolean editable) { + public MediaDetailPagerFragment(Boolean editable, boolean isFeaturedImage) { this.editable = editable; + this.isFeaturedImage = isFeaturedImage; } @Override @@ -90,6 +92,7 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage super.onSaveInstanceState(outState); outState.putInt("current-page", pager.getCurrentItem()); outState.putBoolean("editable", editable); + outState.putBoolean("isFeaturedImage", isFeaturedImage); } @Override @@ -97,6 +100,7 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage super.onCreate(savedInstanceState); if (savedInstanceState != null) { editable = savedInstanceState.getBoolean("editable"); + isFeaturedImage = savedInstanceState.getBoolean("isFeaturedImage"); } setHasOptionsMenu(true); } @@ -272,7 +276,7 @@ public class MediaDetailPagerFragment extends DaggerFragment implements ViewPage // See bug https://code.google.com/p/android/issues/detail?id=27526 pager.postDelayed(() -> getActivity().supportInvalidateOptionsMenu(), 5); } - return MediaDetailFragment.forMedia(i, editable); + return MediaDetailFragment.forMedia(i, editable, isFeaturedImage); } @Override From d0f07f2fca816f02ba6ac46433704b8f4e36cb05 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 22 Jan 2018 13:48:05 +0300 Subject: [PATCH 013/184] Fix implementations according to new method parameters. --- .../fr/free/nrw/commons/featured/FeaturedImagesActivity.java | 3 ++- .../java/fr/free/nrw/commons/upload/MultipleShareActivity.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java index bf5d3089b..a2dc7b00b 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java @@ -66,7 +66,8 @@ public class FeaturedImagesActivity @Override public void onItemClick(AdapterView adapterView, View view, int i, long l) { if (mediaDetails == null || !mediaDetails.isVisible()) { - mediaDetails = new MediaDetailPagerFragment(); + // set isFeaturedImage true for featured images, to include author field on media detail + mediaDetails = new MediaDetailPagerFragment(false, true); FragmentManager supportFragmentManager = getSupportFragmentManager(); supportFragmentManager .beginTransaction() diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java index 15acdcd4a..0f0e742cc 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java @@ -219,7 +219,7 @@ public class MultipleShareActivity extends AuthenticatedActivity private void showDetail(int i) { if (mediaDetails == null || !mediaDetails.isVisible()) { - mediaDetails = new MediaDetailPagerFragment(true); + mediaDetails = new MediaDetailPagerFragment(true, false); getSupportFragmentManager() .beginTransaction() .replace(R.id.uploadsFragmentContainer, mediaDetails) From 3949dbca5c42b9d2a9b79fd4db3d0d6075fe5e90 Mon Sep 17 00:00:00 2001 From: Yiran Cao Date: Thu, 5 Apr 2018 13:27:10 -0400 Subject: [PATCH 014/184] Fixed issue #1395 (#1423) * fixed issue #1395 * moved the compass icon to bottom-left corner --- .../main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 9834f1a6c..d37e67b06 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -456,6 +456,8 @@ public class NearbyMapFragment extends DaggerFragment { private void setupMapView(Bundle savedInstanceState) { MapboxMapOptions options = new MapboxMapOptions() + .compassGravity(Gravity.BOTTOM | Gravity.LEFT) + .compassMargins(new int[]{12, 0, 0, 24}) .styleUrl(Style.OUTDOORS) .logoEnabled(false) .attributionEnabled(false) From 22772c851e935f974df2ffce436b00c9e37f023f Mon Sep 17 00:00:00 2001 From: Paul Hawke Date: Sun, 8 Apr 2018 02:59:20 -0500 Subject: [PATCH 015/184] Moved tests over to Kotlin. (#1428) --- app/build.gradle | 25 +- .../nrw/commons/category/CategoryDao.java | 1 + .../fr/free/nrw/commons/FileUtilsTest.java | 40 -- .../java/fr/free/nrw/commons/LatLngTests.java | 64 --- .../fr/free/nrw/commons/LengthUtilsTest.java | 46 --- .../java/fr/free/nrw/commons/MediaTest.java | 25 -- .../nrw/commons/NearbyControllerTest.java | 44 --- .../fr/free/nrw/commons/PageTitleTest.java | 70 ---- .../nrw/commons/TestCommonsApplication.java | 181 --------- .../nrw/commons/UtilsFixExtensionTest.java | 57 --- .../nrw/commons/category/CategoryDaoTest.java | 294 -------------- .../contributions/ContributionDaoTest.java | 370 ------------------ .../ModifierSequenceDaoTest.java | 181 --------- .../ApacheHttpClientMediaWikiApiTest.java | 248 ------------ .../commons/utils/StringSortingUtilsTest.java | 41 -- .../fr/free/nrw/commons/FileUtilsTest.kt | 33 ++ .../kotlin/fr/free/nrw/commons/LatLngTests.kt | 64 +++ .../fr/free/nrw/commons/LengthUtilsTest.kt | 46 +++ .../kotlin/fr/free/nrw/commons/MediaTest.kt | 23 ++ .../free/nrw/commons/NearbyControllerTest.kt | 35 ++ .../fr/free/nrw/commons/PageTitleTest.kt | 67 ++++ .../nrw/commons/TestCommonsApplication.kt | 72 ++++ .../free/nrw/commons/UtilsFixExtensionTest.kt | 68 ++++ .../nrw/commons/category/CategoryDaoTest.kt | 257 ++++++++++++ .../contributions/ContributionDaoTest.kt | 335 ++++++++++++++++ .../modifications/ModifierSequenceDaoTest.kt | 156 ++++++++ .../mwapi/ApacheHttpClientMediaWikiApiTest.kt | 246 ++++++++++++ .../commons/utils/StringSortingUtilsTest.kt | 41 ++ build.gradle | 2 +- 29 files changed, 1453 insertions(+), 1679 deletions(-) delete mode 100644 app/src/test/java/fr/free/nrw/commons/FileUtilsTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/LatLngTests.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/LengthUtilsTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/MediaTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/PageTitleTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/UtilsFixExtensionTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/category/CategoryDaoTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/contributions/ContributionDaoTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java delete mode 100644 app/src/test/java/fr/free/nrw/commons/utils/StringSortingUtilsTest.java create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/NearbyControllerTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionDaoTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt create mode 100644 app/src/test/kotlin/fr/free/nrw/commons/utils/StringSortingUtilsTest.kt diff --git a/app/build.gradle b/app/build.gradle index b1ee9aef9..46008d1c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,11 +18,12 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.1' implementation 'com.jakewharton.timber:timber:4.5.1' implementation 'info.debatty:java-string-similarity:0.24' + implementation 'com.borjabravo:readmoretextview:2.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){ transitive=true } - implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION" implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION" implementation "com.android.support:design:$SUPPORT_LIB_VERSION" @@ -41,8 +42,6 @@ dependencies { // explicitly depend on RxJava's latest version for bug fixes and new features. implementation 'com.android.support:multidex:1.0.3' - testImplementation "org.robolectric:multidex:3.4.2" - implementation 'io.reactivex.rxjava2:rxjava:2.1.2' implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0' implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0' @@ -54,33 +53,25 @@ dependencies { implementation "com.google.dagger:dagger:$DAGGER_VERSION" implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION" - kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION" kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" + testImplementation "org.robolectric:multidex:3.4.2" testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - + testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:3.7.1' - testImplementation 'org.mockito:mockito-all:1.10.19' - + testImplementation 'com.nhaarman:mockito-kotlin:1.5.0' testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' + + androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' androidTestImplementation "com.android.support:support-annotations:$SUPPORT_LIB_VERSION" - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2-alpha1' debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY" releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY" testImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY" - - implementation "com.google.dagger:dagger:$DAGGER_VERSION" - implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION" - kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" - kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION" - - implementation 'com.borjabravo:readmoretextview:2.1.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' } android { diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.java index a5202046b..010e97095 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryDao.java @@ -105,6 +105,7 @@ public class CategoryDao { return items; } + @NonNull Category fromCursor(Cursor cursor) { // Hardcoding column positions! return new Category( diff --git a/app/src/test/java/fr/free/nrw/commons/FileUtilsTest.java b/app/src/test/java/fr/free/nrw/commons/FileUtilsTest.java deleted file mode 100644 index c6febc1e4..000000000 --- a/app/src/test/java/fr/free/nrw/commons/FileUtilsTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Assert; -import org.junit.Test; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -import fr.free.nrw.commons.upload.FileUtils; - -import static org.hamcrest.CoreMatchers.is; - -public class FileUtilsTest { - @Test public void copiedFileIsIdenticalToSource() throws IOException { - File source = File.createTempFile("temp", ""); - File dest = File.createTempFile("temp", ""); - writeToFile(source, "Hello, World"); - FileUtils.copy(new FileInputStream(source), new FileOutputStream(dest)); - Assert.assertThat(getString(dest), is(getString(source))); - } - - private static void writeToFile(File file, String s) throws IOException { - BufferedOutputStream buf = new BufferedOutputStream(new FileOutputStream(file)); - buf.write(s.getBytes()); - buf.close(); - } - - private static String getString(File file) throws IOException { - int size = (int) file.length(); - byte[] bytes = new byte[size]; - BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file)); - buf.read(bytes, 0, bytes.length); - buf.close(); - return new String(bytes); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/LatLngTests.java b/app/src/test/java/fr/free/nrw/commons/LatLngTests.java deleted file mode 100644 index c2fb1b159..000000000 --- a/app/src/test/java/fr/free/nrw/commons/LatLngTests.java +++ /dev/null @@ -1,64 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Assert; -import org.junit.Test; - -import fr.free.nrw.commons.location.LatLng; - -import static org.hamcrest.CoreMatchers.is; - -public class LatLngTests { - @Test public void testZeroZero() { - LatLng place = new LatLng(0, 0, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("0.0 N, 0.0 E")); - } - - @Test public void testAntipode() { - LatLng place = new LatLng(0, 180, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("0.0 N, 180.0 W")); - } - - @Test public void testNorthPole() { - LatLng place = new LatLng(90, 0, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("90.0 N, 0.0 E")); - } - - @Test public void testSouthPole() { - LatLng place = new LatLng(-90, 0, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("90.0 S, 0.0 E")); - } - - @Test public void testLargerNumbers() { - LatLng place = new LatLng(120, 380, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("90.0 N, 20.0 E")); - } - - @Test public void testNegativeNumbers() { - LatLng place = new LatLng(-120, -30, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("90.0 S, 30.0 W")); - } - - @Test public void testTooBigWestValue() { - LatLng place = new LatLng(20, -190, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("20.0 N, 170.0 E")); - } - - @Test public void testRounding() { - LatLng place = new LatLng(0.1234567, -0.33333333, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("0.1235 N, 0.3333 W")); - } - - @Test public void testRoundingAgain() { - LatLng place = new LatLng(-0.000001, -0.999999, 0); - String prettyString = place.getPrettyCoordinateString(); - Assert.assertThat(prettyString, is("0.0 S, 1.0 W")); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/LengthUtilsTest.java b/app/src/test/java/fr/free/nrw/commons/LengthUtilsTest.java deleted file mode 100644 index 561f3f0e6..000000000 --- a/app/src/test/java/fr/free/nrw/commons/LengthUtilsTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Assert; -import org.junit.Test; - -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.utils.LengthUtils; - -import static org.hamcrest.CoreMatchers.is; - -public class LengthUtilsTest { - @Test public void testZeroDistance() { - LatLng pointA = new LatLng(0, 0, 0); - LatLng pointB = new LatLng(0, 0, 0); - String distance = LengthUtils.formatDistanceBetween(pointA, pointB); - Assert.assertThat(distance, is("0m")); - } - - @Test public void testOneDegreeOnEquator() { - LatLng pointA = new LatLng(0, 0, 0); - LatLng pointB = new LatLng(0, 1, 0); - String distance = LengthUtils.formatDistanceBetween(pointA, pointB); - Assert.assertThat(distance, is("111.2km")); - } - - @Test public void testOneDegreeFortyFiveDegrees() { - LatLng pointA = new LatLng(45, 0, 0); - LatLng pointB = new LatLng(45, 1, 0); - String distance = LengthUtils.formatDistanceBetween(pointA, pointB); - Assert.assertThat(distance, is("78.6km")); - } - - @Test public void testOneDegreeSouthPole() { - LatLng pointA = new LatLng(-90, 0, 0); - LatLng pointB = new LatLng(-90, 1, 0); - String distance = LengthUtils.formatDistanceBetween(pointA, pointB); - Assert.assertThat(distance, is("0m")); - } - - @Test public void testPoleToPole() { - LatLng pointA = new LatLng(90, 0, 0); - LatLng pointB = new LatLng(-90, 0, 0); - String distance = LengthUtils.formatDistanceBetween(pointA, pointB); - Assert.assertThat(distance, is("20,015.1km")); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/MediaTest.java b/app/src/test/java/fr/free/nrw/commons/MediaTest.java deleted file mode 100644 index 4f53351ad..000000000 --- a/app/src/test/java/fr/free/nrw/commons/MediaTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class MediaTest { - @Test - public void displayTitleShouldStripExtension() { - Media m = new Media("File:Example.jpg"); - assertThat(m.getDisplayTitle(), is("Example")); - } - - @Test - public void displayTitleShouldUseSpaceForUnderscore() { - Media m = new Media("File:Example 1_2.jpg"); - assertThat(m.getDisplayTitle(), is("Example 1 2")); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java b/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java deleted file mode 100644 index 752b7404d..000000000 --- a/app/src/test/java/fr/free/nrw/commons/NearbyControllerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.ArrayList; -import java.util.List; - -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.nearby.NearbyBaseMarker; -import fr.free.nrw.commons.nearby.Place; - -import static fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class NearbyControllerTest { - - @Test - public void testNullAttractions() { - LatLng location = new LatLng(0, 0, 0); - - List options = loadAttractionsFromLocationToBaseMarkerOptions( - location, null, RuntimeEnvironment.application); - - assertThat(options.size(), is(0)); - } - - @Test - public void testEmptyList() { - LatLng location = new LatLng(0, 0, 0); - List emptyList = new ArrayList<>(); - - List options = loadAttractionsFromLocationToBaseMarkerOptions( - location, emptyList, RuntimeEnvironment.application); - - assertThat(options.size(), is(0)); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java b/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java deleted file mode 100644 index 16336b1b0..000000000 --- a/app/src/test/java/fr/free/nrw/commons/PageTitleTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.net.URLEncoder; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class PageTitleTest { - @Test - public void displayTextShouldNotBeUnderscored() { - assertThat(new PageTitle("Ex_1 ").getDisplayText(), - is("Ex 1")); - } - - @Test - public void moreThanTwoColons() { - assertThat(new PageTitle("File:sample:a.jpg").getPrefixedText(), - is("File:Sample:a.jpg")); - } - - @Test - public void getTextShouldReturnWithoutNamespace() { - assertThat(new PageTitle("File:sample.jpg").getText(), - is("Sample.jpg")); - } - - - @Test - public void capitalizeNameAfterNamespace() { - assertThat(new PageTitle("File:sample.jpg").getPrefixedText(), - is("File:Sample.jpg")); - } - - @Test - public void prefixedTextShouldBeUnderscored() { - assertThat(new PageTitle("Ex 1 ").getPrefixedText(), - is("Ex_1")); - } - - @Test - public void getMobileUriForTest() { - assertThat(new PageTitle("Test").getMobileUri().toString(), - is(BuildConfig.MOBILE_HOME_URL + "Test")); - } - - @Test - public void spaceBecomesUnderscoreInUri() { - assertThat(new PageTitle("File:Ex 1.jpg").getCanonicalUri().toString(), - is(BuildConfig.HOME_URL + "File:Ex_1.jpg")); - } - - @Test - public void leaveSubpageNamesUncapitalizedInUri() { - assertThat(new PageTitle("User:Ex/subpage").getCanonicalUri().toString(), - is(BuildConfig.HOME_URL + "User:Ex/subpage")); - } - - @Test - public void unicodeUri() throws Throwable { - assertThat(new PageTitle("User:例").getCanonicalUri().toString(), - is(BuildConfig.HOME_URL + "User:" + URLEncoder.encode("例", "utf-8"))); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java b/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java deleted file mode 100644 index 9f7bc6184..000000000 --- a/app/src/test/java/fr/free/nrw/commons/TestCommonsApplication.java +++ /dev/null @@ -1,181 +0,0 @@ -package fr.free.nrw.commons; - -import android.content.Context; -import android.content.SharedPreferences; -import android.support.v4.util.LruCache; - -import com.squareup.leakcanary.RefWatcher; - -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import javax.inject.Named; - -import dagger.Provides; -import fr.free.nrw.commons.auth.AccountUtil; -import fr.free.nrw.commons.auth.SessionManager; -import fr.free.nrw.commons.caching.CacheController; -import fr.free.nrw.commons.data.DBOpenHelper; -import fr.free.nrw.commons.di.CommonsApplicationComponent; -import fr.free.nrw.commons.di.CommonsApplicationModule; -import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent; -import fr.free.nrw.commons.location.LocationServiceManager; -import fr.free.nrw.commons.mwapi.MediaWikiApi; -import fr.free.nrw.commons.nearby.NearbyPlaces; -import fr.free.nrw.commons.upload.UploadController; - -public class TestCommonsApplication extends CommonsApplication { - - CommonsApplicationComponent mockApplicationComponent; - - @Mock - CommonsApplicationModule commonsApplicationModule; - @Mock - AccountUtil accountUtil; - @Mock - SharedPreferences appSharedPreferences; - @Mock - SharedPreferences defaultSharedPreferences; - @Mock - SharedPreferences otherSharedPreferences; - @Mock - UploadController uploadController; - @Mock - SessionManager sessionManager; - @Mock - MediaWikiApi mediaWikiApi; - @Mock - LocationServiceManager locationServiceManager; - @Mock - CacheController cacheController; - @Mock - DBOpenHelper dbOpenHelper; - @Mock - NearbyPlaces nearbyPlaces; - @Mock - LruCache lruCache; - - @Override - public void onCreate() { - MockitoAnnotations.initMocks(this); - if (mockApplicationComponent == null) { - mockApplicationComponent = DaggerCommonsApplicationComponent.builder() - .appModule(new CommonsApplicationModule(this) { - @Override - public AccountUtil providesAccountUtil(Context context) { - return accountUtil; - } - - @Override - public SharedPreferences providesApplicationSharedPreferences(Context context) { - return appSharedPreferences; - } - - @Override - public SharedPreferences providesDefaultSharedPreferences(Context context) { - return defaultSharedPreferences; - } - - @Override - public SharedPreferences providesOtherSharedPreferences(Context context) { - return otherSharedPreferences; - } - - @Override - public UploadController providesUploadController(SessionManager sessionManager, SharedPreferences sharedPreferences, Context context) { - return uploadController; - } - - @Override - public SessionManager providesSessionManager(Context context, MediaWikiApi mediaWikiApi, SharedPreferences sharedPreferences) { - return sessionManager; - } - - @Override - public MediaWikiApi provideMediaWikiApi(Context context, SharedPreferences sharedPreferences) { - return mediaWikiApi; - } - - @Override - public LocationServiceManager provideLocationServiceManager(Context context) { - return locationServiceManager; - } - - @Override - public CacheController provideCacheController() { - return cacheController; - } - - @Override - public DBOpenHelper provideDBOpenHelper(Context context) { - return dbOpenHelper; - } - - @Override - public NearbyPlaces provideNearbyPlaces() { - return nearbyPlaces; - } - - @Override - public LruCache provideLruCache() { - return lruCache; - } - }).build(); - } - super.onCreate(); - } - - @Override - protected RefWatcher setupLeakCanary() { - // No leakcanary in unit tests. - return RefWatcher.DISABLED; - } - - public AccountUtil getAccountUtil() { - return accountUtil; - } - - public SharedPreferences getAppSharedPreferences() { - return appSharedPreferences; - } - - public SharedPreferences getDefaultSharedPreferences() { - return defaultSharedPreferences; - } - - public SharedPreferences getOtherSharedPreferences() { - return otherSharedPreferences; - } - - public UploadController getUploadController() { - return uploadController; - } - - public SessionManager getSessionManager() { - return sessionManager; - } - - public MediaWikiApi getMediaWikiApi() { - return mediaWikiApi; - } - - public LocationServiceManager getLocationServiceManager() { - return locationServiceManager; - } - - public CacheController getCacheController() { - return cacheController; - } - - public DBOpenHelper getDbOpenHelper() { - return dbOpenHelper; - } - - public NearbyPlaces getNearbyPlaces() { - return nearbyPlaces; - } - - public LruCache getLruCache() { - return lruCache; - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/UtilsFixExtensionTest.java b/app/src/test/java/fr/free/nrw/commons/UtilsFixExtensionTest.java deleted file mode 100644 index 186f30df9..000000000 --- a/app/src/test/java/fr/free/nrw/commons/UtilsFixExtensionTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.free.nrw.commons; - -import org.junit.Assert; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.is; - -public class UtilsFixExtensionTest { - - @Test public void jpegResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "jpeg"), is("SampleFile.jpg")); - } - - @Test public void capitalJpegWithNoHintResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.JPEG", null), is("SampleFile.jpg")); - } - - @Test public void jpegWithBogusHintResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", null), is("SampleFile.jpg")); - } - - @Test public void jpegToCapitalJpegResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "JPEG"), is("SampleFile.jpg")); - } - - @Test public void jpgToJpegResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpg", "jpeg"), is("SampleFile.jpg")); - } - - @Test public void jpegToJpgResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "jpg"), is("SampleFile.jpg")); - } - - @Test public void jpgRemainsJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile.jpg", "jpg"), is("SampleFile.jpg")); - } - - @Test public void pngRemainsPng() { - Assert.assertThat(Utils.fixExtension("SampleFile.png", "png"), is("SampleFile.png")); - } - - @Test public void jpgHintResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile", "jpg"), is("SampleFile.jpg")); - } - - @Test public void jpegHintResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SampleFile", "jpeg"), is("SampleFile.jpg")); - } - - @Test public void dotLessJpgToJpgResultsInJpg() { - Assert.assertThat(Utils.fixExtension("SAMPLEjpg", "jpg"), is("SAMPLEjpg.jpg")); - } - - @Test public void inWordJpegToJpgResultsInJpg() { - Assert.assertThat(Utils.fixExtension("X.jpeg.SAMPLE", "jpg"),is("X.jpeg.SAMPLE.jpg")); - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/category/CategoryDaoTest.java b/app/src/test/java/fr/free/nrw/commons/category/CategoryDaoTest.java deleted file mode 100644 index 1cf0c338b..000000000 --- a/app/src/test/java/fr/free/nrw/commons/category/CategoryDaoTest.java +++ /dev/null @@ -1,294 +0,0 @@ -package fr.free.nrw.commons.category; - -import android.content.ContentProviderClient; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.RemoteException; -import android.support.annotation.NonNull; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.TestCommonsApplication; -import fr.free.nrw.commons.category.CategoryDao.Table; - -import static fr.free.nrw.commons.category.CategoryContentProvider.BASE_URI; -import static fr.free.nrw.commons.category.CategoryContentProvider.uriForId; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class CategoryDaoTest { - - @Mock - private ContentProviderClient client; - @Mock - private SQLiteDatabase database; - @Captor - private ArgumentCaptor captor; - @Captor - private ArgumentCaptor queryCaptor; - - private CategoryDao testObject; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - testObject = new CategoryDao(() -> client); - } - - @Test - public void createTable() { - Table.onCreate(database); - verify(database).execSQL(Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void deleteTable() { - Table.onDelete(database); - InOrder inOrder = Mockito.inOrder(database); - inOrder.verify(database).execSQL(Table.DROP_TABLE_STATEMENT); - inOrder.verify(database).execSQL(Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void migrateTableVersionFrom_v1_to_v2() { - Table.onUpdate(database, 1, 2); - // Table didnt exist before v5 - verifyZeroInteractions(database); - } - - @Test - public void migrateTableVersionFrom_v2_to_v3() { - Table.onUpdate(database, 2, 3); - // Table didnt exist before v5 - verifyZeroInteractions(database); - } - - @Test - public void migrateTableVersionFrom_v3_to_v4() { - Table.onUpdate(database, 3, 4); - // Table didnt exist before v5 - verifyZeroInteractions(database); - } - - @Test - public void migrateTableVersionFrom_v4_to_v5() { - Table.onUpdate(database, 4, 5); - verify(database).execSQL(Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void migrateTableVersionFrom_v5_to_v6() { - Table.onUpdate(database, 5, 6); - // Table didnt change in version 6 - verifyZeroInteractions(database); - } - - @Test - public void createFromCursor() { - MatrixCursor cursor = createCursor(1); - cursor.moveToFirst(); - Category category = testObject.fromCursor(cursor); - - assertEquals(uriForId(1), category.getContentUri()); - assertEquals("foo", category.getName()); - assertEquals(123, category.getLastUsed().getTime()); - assertEquals(2, category.getTimesUsed()); - } - - @Test - public void saveExistingCategory() throws Exception { - MatrixCursor cursor = createCursor(1); - cursor.moveToFirst(); - Category category = testObject.fromCursor(cursor); - - testObject.save(category); - - verify(client).update(eq(category.getContentUri()), captor.capture(), isNull(String.class), isNull(String[].class)); - ContentValues cv = captor.getValue(); - assertEquals(3, cv.size()); - assertEquals(category.getName(), cv.getAsString(Table.COLUMN_NAME)); - assertEquals(category.getLastUsed().getTime(), cv.getAsLong(Table.COLUMN_LAST_USED).longValue()); - assertEquals(category.getTimesUsed(), cv.getAsInteger(Table.COLUMN_TIMES_USED).intValue()); - } - - @Test - public void saveNewCategory() throws Exception { - Uri contentUri = CategoryContentProvider.uriForId(111); - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Category category = new Category(null, "foo", new Date(234L), 1); - - testObject.save(category); - - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - assertEquals(3, cv.size()); - assertEquals(category.getName(), cv.getAsString(Table.COLUMN_NAME)); - assertEquals(category.getLastUsed().getTime(), cv.getAsLong(Table.COLUMN_LAST_USED).longValue()); - assertEquals(category.getTimesUsed(), cv.getAsInteger(Table.COLUMN_TIMES_USED).intValue()); - assertEquals(contentUri, category.getContentUri()); - } - - @Test(expected = RuntimeException.class) - public void testSaveTranslatesRemoteExceptions() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException("")); - testObject.save(new Category()); - } - - @Test - public void whenTheresNoDataFindReturnsNull_nullCursor() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(null); - - assertNull(testObject.find("foo")); - } - - @Test - public void whenTheresNoDataFindReturnsNull_emptyCursor() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(0)); - - assertNull(testObject.find("foo")); - } - - @Test - public void cursorsAreClosedAfterUse() throws Exception { - Cursor mockCursor = mock(Cursor.class); - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(mockCursor); - when(mockCursor.moveToFirst()).thenReturn(false); - - testObject.find("foo"); - - verify(mockCursor).close(); - } - - @Test - public void findCategory() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(1)); - - Category category = testObject.find("foo"); - - assertEquals(uriForId(1), category.getContentUri()); - assertEquals("foo", category.getName()); - assertEquals(123, category.getLastUsed().getTime()); - assertEquals(2, category.getTimesUsed()); - - verify(client).query( - eq(BASE_URI), - eq(Table.ALL_FIELDS), - eq(Table.COLUMN_NAME + "=?"), - queryCaptor.capture(), - isNull(String.class) - ); - assertEquals("foo", queryCaptor.getValue()[0]); - } - - @Test(expected = RuntimeException.class) - public void findCategoryTranslatesExceptions() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenThrow(new RemoteException("")); - testObject.find("foo"); - } - - @Test(expected = RuntimeException.class) - public void recentCategoriesTranslatesExceptions() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenThrow(new RemoteException("")); - testObject.recentCategories(1); - } - - @Test - public void recentCategoriesReturnsEmptyList_nullCursor() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(null); - - assertTrue(testObject.recentCategories(1).isEmpty()); - } - - @Test - public void recentCategoriesReturnsEmptyList_emptyCursor() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(0)); - - assertTrue(testObject.recentCategories(1).isEmpty()); - } - - @Test - public void cursorsAreClosedAfterRecentCategoriesQuery() throws Exception { - Cursor mockCursor = mock(Cursor.class); - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(mockCursor); - when(mockCursor.moveToFirst()).thenReturn(false); - - testObject.recentCategories(1); - - verify(mockCursor).close(); - } - - @Test - public void recentCategoriesReturnsLessThanLimit() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(1)); - - List result = testObject.recentCategories(10); - - assertEquals(1, result.size()); - assertEquals("foo", result.get(0)); - - verify(client).query( - eq(BASE_URI), - eq(Table.ALL_FIELDS), - isNull(String.class), - queryCaptor.capture(), - eq(Table.COLUMN_LAST_USED + " DESC") - ); - assertEquals(0, queryCaptor.getValue().length); - } - - @Test - public void recentCategoriesHomorsLimit() throws Exception { - when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(10)); - - List result = testObject.recentCategories(5); - - assertEquals(5, result.size()); - } - - @NonNull - private MatrixCursor createCursor(int rowCount) { - MatrixCursor cursor = new MatrixCursor(new String[]{ - Table.COLUMN_ID, - Table.COLUMN_NAME, - Table.COLUMN_LAST_USED, - Table.COLUMN_TIMES_USED - }, rowCount); - - for (int i = 0; i < rowCount; i++) { - cursor.addRow(Arrays.asList("1", "foo", "123", "2")); - } - - return cursor; - } - -} \ No newline at end of file diff --git a/app/src/test/java/fr/free/nrw/commons/contributions/ContributionDaoTest.java b/app/src/test/java/fr/free/nrw/commons/contributions/ContributionDaoTest.java deleted file mode 100644 index 15e37e640..000000000 --- a/app/src/test/java/fr/free/nrw/commons/contributions/ContributionDaoTest.java +++ /dev/null @@ -1,370 +0,0 @@ -package fr.free.nrw.commons.contributions; - -import android.content.ContentProviderClient; -import android.content.ContentValues; -import android.database.MatrixCursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.RemoteException; -import android.support.annotation.NonNull; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.Date; - -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.TestCommonsApplication; -import fr.free.nrw.commons.Utils; - -import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA; -import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY; -import static fr.free.nrw.commons.contributions.Contribution.STATE_COMPLETED; -import static fr.free.nrw.commons.contributions.Contribution.STATE_QUEUED; -import static fr.free.nrw.commons.contributions.ContributionDao.Table; -import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI; -import static fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class ContributionDaoTest { - - private static final String LOCAL_URI = "http://example.com/"; - @Mock - private ContentProviderClient client; - @Mock - private SQLiteDatabase database; - @Captor - private ArgumentCaptor captor; - - private Uri contentUri; - private ContributionDao testObject; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - contentUri = uriForId(111); - - testObject = new ContributionDao(() -> client); - } - - @Test - public void createTable() { - Table.onCreate(database); - verify(database).execSQL(Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void deleteTable() { - Table.onDelete(database); - - InOrder inOrder = Mockito.inOrder(database); - inOrder.verify(database).execSQL(Table.DROP_TABLE_STATEMENT); - inOrder.verify(database).execSQL(Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void upgradeDatabase_v1_to_v2() { - Table.onUpdate(database, 1, 2); - - InOrder inOrder = Mockito.inOrder(database); - inOrder.verify(database).execSQL(Table.ADD_DESCRIPTION_FIELD); - inOrder.verify(database).execSQL(Table.ADD_CREATOR_FIELD); - } - - @Test - public void upgradeDatabase_v2_to_v3() { - Table.onUpdate(database, 2, 3); - - InOrder inOrder = Mockito.inOrder(database); - inOrder.verify(database).execSQL(Table.ADD_MULTIPLE_FIELD); - inOrder.verify(database).execSQL(Table.SET_DEFAULT_MULTIPLE); - } - - @Test - public void upgradeDatabase_v3_to_v4() { - Table.onUpdate(database, 3, 4); - - // No changes - verifyZeroInteractions(database); - } - - @Test - public void upgradeDatabase_v4_to_v5() { - Table.onUpdate(database, 4, 5); - - // No changes - verifyZeroInteractions(database); - } - - @Test - public void upgradeDatabase_v5_to_v6() { - Table.onUpdate(database, 5, 6); - - InOrder inOrder = Mockito.inOrder(database); - inOrder.verify(database).execSQL(Table.ADD_WIDTH_FIELD); - inOrder.verify(database).execSQL(Table.SET_DEFAULT_WIDTH); - inOrder.verify(database).execSQL(Table.ADD_HEIGHT_FIELD); - inOrder.verify(database).execSQL(Table.SET_DEFAULT_HEIGHT); - inOrder.verify(database).execSQL(Table.ADD_LICENSE_FIELD); - inOrder.verify(database).execSQL(Table.SET_DEFAULT_LICENSE); - } - - @Test - public void saveNewContribution_nonNullFields() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(true, null, null, null, null); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - // Long fields - assertEquals(222L, cv.getAsLong(Table.COLUMN_LENGTH).longValue()); - assertEquals(321L, cv.getAsLong(Table.COLUMN_TIMESTAMP).longValue()); - assertEquals(333L, cv.getAsLong(Table.COLUMN_TRANSFERRED).longValue()); - - // Integer fields - assertEquals(STATE_COMPLETED, cv.getAsInteger(Table.COLUMN_STATE).intValue()); - assertEquals(640, cv.getAsInteger(Table.COLUMN_WIDTH).intValue()); - assertEquals(480, cv.getAsInteger(Table.COLUMN_HEIGHT).intValue()); - - // String fields - assertEquals(SOURCE_CAMERA, cv.getAsString(Table.COLUMN_SOURCE)); - assertEquals("desc", cv.getAsString(Table.COLUMN_DESCRIPTION)); - assertEquals("create", cv.getAsString(Table.COLUMN_CREATOR)); - assertEquals("007", cv.getAsString(Table.COLUMN_LICENSE)); - } - - @Test - public void saveNewContribution_nullableFieldsAreNull() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(true, null, null, null, null); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - // Nullable fields are absent if null - assertFalse(cv.containsKey(Table.COLUMN_LOCAL_URI)); - assertFalse(cv.containsKey(Table.COLUMN_IMAGE_URL)); - assertFalse(cv.containsKey(Table.COLUMN_UPLOADED)); - } - - @Test - public void saveNewContribution_nullableImageUrlUsesFileAsBackup() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(true, null, null, null, "file"); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - // Nullable fields are absent if null - assertFalse(cv.containsKey(Table.COLUMN_LOCAL_URI)); - assertFalse(cv.containsKey(Table.COLUMN_UPLOADED)); - - assertEquals(Utils.makeThumbBaseUrl("file"), cv.getAsString(Table.COLUMN_IMAGE_URL)); - } - - @Test - public void saveNewContribution_nullableFieldsAreNonNull() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(true, Uri.parse(LOCAL_URI), - "image", new Date(456L), null); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - assertEquals(LOCAL_URI, cv.getAsString(Table.COLUMN_LOCAL_URI)); - assertEquals("image", cv.getAsString(Table.COLUMN_IMAGE_URL)); - assertEquals(456L, cv.getAsLong(Table.COLUMN_UPLOADED).longValue()); - } - - @Test - public void saveNewContribution_booleanEncodesTrue() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(true, null, null, null, null); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - // Boolean true --> 1 for ths encoding scheme - assertEquals("Boolean true should be encoded as 1", 1, - cv.getAsInteger(Table.COLUMN_MULTIPLE).intValue()); - } - - @Test - public void saveNewContribution_booleanEncodesFalse() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri); - Contribution contribution = createContribution(false, null, null, null, null); - - testObject.save(contribution); - - assertEquals(contentUri, contribution.getContentUri()); - verify(client).insert(eq(BASE_URI), captor.capture()); - ContentValues cv = captor.getValue(); - - // Boolean true --> 1 for ths encoding scheme - assertEquals("Boolean false should be encoded as 0", 0, - cv.getAsInteger(Table.COLUMN_MULTIPLE).intValue()); - } - - @Test - public void saveExistingContribution() throws Exception { - Contribution contribution = createContribution(false, null, null, null, null); - contribution.setContentUri(contentUri); - - testObject.save(contribution); - - verify(client).update(eq(contentUri), isA(ContentValues.class), isNull(String.class), isNull(String[].class)); - } - - @Test(expected = RuntimeException.class) - public void saveTranslatesExceptions() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException("")); - - testObject.save(createContribution(false, null, null, null, null)); - } - - @Test(expected = RuntimeException.class) - public void deleteTranslatesExceptions() throws Exception { - when(client.delete(isA(Uri.class), any(), any())).thenThrow(new RemoteException("")); - - Contribution contribution = createContribution(false, null, null, null, null); - contribution.setContentUri(contentUri); - testObject.delete(contribution); - } - - @Test(expected = RuntimeException.class) - public void exceptionThrownWhenAttemptingToDeleteUnsavedContribution() { - testObject.delete(createContribution(false, null, null, null, null)); - } - - @Test - public void deleteExistingContribution() throws Exception { - Contribution contribution = createContribution(false, null, null, null, null); - contribution.setContentUri(contentUri); - - testObject.delete(contribution); - - verify(client).delete(eq(contentUri), isNull(String.class), isNull(String[].class)); - } - - @Test - public void createFromCursor() { - long created = 321L; - long uploaded = 456L; - MatrixCursor mc = createCursor(created, uploaded, false, LOCAL_URI); - - Contribution c = testObject.fromCursor(mc); - - assertEquals(uriForId(111), c.getContentUri()); - assertEquals("file", c.getFilename()); - assertEquals(LOCAL_URI, c.getLocalUri().toString()); - assertEquals("image", c.getImageUrl()); - assertEquals(created, c.getTimestamp().getTime()); - assertEquals(created, c.getDateCreated().getTime()); - assertEquals(STATE_QUEUED, c.getState()); - assertEquals(222L, c.getDataLength()); - assertEquals(uploaded, c.getDateUploaded().getTime()); - assertEquals(88L, c.getTransferred()); - assertEquals(SOURCE_GALLERY, c.getSource()); - assertEquals("desc", c.getDescription()); - assertEquals("create", c.getCreator()); - assertEquals(640, c.getWidth()); - assertEquals(480, c.getHeight()); - assertEquals("007", c.getLicense()); - } - - @Test - public void createFromCursor_nullableTimestamps() { - MatrixCursor mc = createCursor(0L, 0L, false, LOCAL_URI); - - Contribution c = testObject.fromCursor(mc); - - assertNull(c.getTimestamp()); - assertNull(c.getDateCreated()); - assertNull(c.getDateUploaded()); - } - - @Test - public void createFromCursor_nullableLocalUri() { - MatrixCursor mc = createCursor(0L, 0L, false, ""); - - Contribution c = testObject.fromCursor(mc); - - assertNull(c.getLocalUri()); - assertNull(c.getDateCreated()); - assertNull(c.getDateUploaded()); - } - - @Test - public void createFromCursor_booleanEncoding() { - MatrixCursor mcFalse = createCursor(0L, 0L, false, LOCAL_URI); - assertFalse(testObject.fromCursor(mcFalse).getMultiple()); - - MatrixCursor mcHammer = createCursor(0L, 0L, true, LOCAL_URI); - assertTrue(testObject.fromCursor(mcHammer).getMultiple()); - } - - @NonNull - private MatrixCursor createCursor(long created, long uploaded, boolean multiple, String localUri) { - MatrixCursor mc = new MatrixCursor(Table.ALL_FIELDS, 1); - mc.addRow(Arrays.asList("111", "file", localUri, "image", - created, STATE_QUEUED, 222L, uploaded, 88L, SOURCE_GALLERY, "desc", - "create", multiple ? 1 : 0, 640, 480, "007")); - mc.moveToFirst(); - return mc; - } - - @NonNull - private Contribution createContribution(boolean multiple, Uri localUri, - String imageUrl, Date dateUploaded, String filename) { - Contribution contribution = new Contribution(localUri, imageUrl, filename, "desc", 222L, - new Date(321L), dateUploaded, "create", "edit", "coords"); - contribution.setState(STATE_COMPLETED); - contribution.setTransferred(333L); - contribution.setSource(SOURCE_CAMERA); - contribution.setLicense("007"); - contribution.setMultiple(multiple); - contribution.setTimestamp(new Date(321L)); - contribution.setWidth(640); - contribution.setHeight(480); // VGA should be enough for anyone, right? - return contribution; - } -} \ No newline at end of file diff --git a/app/src/test/java/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.java b/app/src/test/java/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.java deleted file mode 100644 index ef290500d..000000000 --- a/app/src/test/java/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.java +++ /dev/null @@ -1,181 +0,0 @@ -package fr.free.nrw.commons.modifications; - -import android.content.ContentProviderClient; -import android.content.ContentValues; -import android.database.MatrixCursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.RemoteException; -import android.support.annotation.NonNull; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; - -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.TestCommonsApplication; - -import static fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class ModifierSequenceDaoTest { - - private static final String EXPECTED_MEDIA_URI = "http://example.com/"; - - @Mock - ContentProviderClient client; - @Mock - SQLiteDatabase database; - @Captor - ArgumentCaptor contentValuesCaptor; - - private ModifierSequenceDao testObject; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - testObject = new ModifierSequenceDao(() -> client); - } - - @Test - public void createFromCursorWithEmptyModifiers() { - MatrixCursor cursor = createCursor(""); - - ModifierSequence seq = testObject.fromCursor(cursor); - - assertEquals(EXPECTED_MEDIA_URI, seq.getMediaUri().toString()); - assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), seq.getContentUri().toString()); - assertTrue(seq.getModifiers().isEmpty()); - } - - @Test - public void createFromCursorWtihCategoryModifier() { - MatrixCursor cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}"); - - ModifierSequence seq = testObject.fromCursor(cursor); - - assertEquals(1, seq.getModifiers().size()); - assertTrue(seq.getModifiers().get(0) instanceof CategoryModifier); - } - - @Test - public void createFromCursorWithRemoveModifier() { - MatrixCursor cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}"); - - ModifierSequence seq = testObject.fromCursor(cursor); - - assertEquals(1, seq.getModifiers().size()); - assertTrue(seq.getModifiers().get(0) instanceof TemplateRemoveModifier); - } - - @Test - public void deleteSequence() throws Exception { - when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenReturn(1); - ModifierSequence seq = testObject.fromCursor(createCursor("")); - - testObject.delete(seq); - - verify(client).delete(eq(seq.getContentUri()), isNull(String.class), isNull(String[].class)); - } - - @Test(expected = RuntimeException.class) - public void deleteTranslatesRemoteExceptions() throws Exception { - when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenThrow(new RemoteException("")); - ModifierSequence seq = testObject.fromCursor(createCursor("")); - - testObject.delete(seq); - } - - @Test - public void saveExistingSequence() throws Exception { - String modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}"; - String expectedData = "{\"modifiers\":[" + modifierJson + "]}"; - MatrixCursor cursor = createCursor(modifierJson); - - testObject.save(testObject.fromCursor(cursor)); - - verify(client).update(eq(testObject.fromCursor(cursor).getContentUri()), contentValuesCaptor.capture(), isNull(String.class), isNull(String[].class)); - ContentValues cv = contentValuesCaptor.getValue(); - assertEquals(2, cv.size()); - assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI)); - assertEquals(expectedData, cv.get(ModifierSequenceDao.Table.COLUMN_DATA)); - } - - @Test - public void saveNewSequence() throws Exception { - Uri expectedContentUri = BASE_URI.buildUpon().appendPath("1").build(); - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(expectedContentUri); - - ModifierSequence seq = new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI)); - testObject.save(seq); - - verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture()); - ContentValues cv = contentValuesCaptor.getValue(); - assertEquals(2, cv.size()); - assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI)); - assertEquals("{\"modifiers\":[]}", cv.get(ModifierSequenceDao.Table.COLUMN_DATA)); - assertEquals(expectedContentUri.toString(), seq.getContentUri().toString()); - } - - @Test(expected = RuntimeException.class) - public void saveTranslatesRemoteExceptions() throws Exception { - when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException("")); - - testObject.save(new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI))); - } - - @Test - public void createTable() { - ModifierSequenceDao.Table.onCreate(database); - - verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void updateTable() { - ModifierSequenceDao.Table.onUpdate(database, 1, 2); - - InOrder inOrder = inOrder(database); - inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT); - inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT); - } - - @Test - public void deleteTable() { - ModifierSequenceDao.Table.onDelete(database); - - InOrder inOrder = inOrder(database); - inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT); - inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT); - } - - @NonNull - private MatrixCursor createCursor(String modifierJson) { - MatrixCursor cursor = new MatrixCursor(new String[]{ - ModifierSequenceDao.Table.COLUMN_ID, - ModifierSequenceDao.Table.COLUMN_MEDIA_URI, - ModifierSequenceDao.Table.COLUMN_DATA - }, 1); - cursor.addRow(Arrays.asList("1", EXPECTED_MEDIA_URI, "{\"modifiers\": [" + modifierJson + "]}")); - cursor.moveToFirst(); - return cursor; - } -} \ No newline at end of file diff --git a/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java b/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java deleted file mode 100644 index e2c8b82f6..000000000 --- a/app/src/test/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.java +++ /dev/null @@ -1,248 +0,0 @@ -package fr.free.nrw.commons.mwapi; - -import android.content.SharedPreferences; -import android.os.Build; -import android.preference.PreferenceManager; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.TestCommonsApplication; -import io.reactivex.observers.TestObserver; -import okhttp3.HttpUrl; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -@RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class) -public class ApacheHttpClientMediaWikiApiTest { - - private ApacheHttpClientMediaWikiApi testObject; - private MockWebServer server; - private SharedPreferences sharedPreferences; - - @Before - public void setUp() throws Exception { - server = new MockWebServer(); - sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application); - testObject = new ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.getHostName() + ":" + server.getPort() + "/", sharedPreferences); - testObject.setWikiMediaToolforgeUrl("http://" + server.getHostName() + ":" + server.getPort() + "/"); - } - - @After - public void teardown() throws IOException { - server.shutdown(); - } - - @Test - public void authCookiesAreHandled() { - assertEquals("", testObject.getAuthCookie()); - - testObject.setAuthCookie("cookie=chocolate-chip"); - - assertEquals("cookie=chocolate-chip", testObject.getAuthCookie()); - } - - @Test - public void simpleLoginWithWrongPassword() throws Exception { - server.enqueue(new MockResponse().setBody("")); - server.enqueue(new MockResponse().setBody("")); - - String result = testObject.login("foo", "bar"); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST"); - Map body = parseBody(loginTokenRequest.getBody().readUtf8()); - assertEquals("xml", body.get("format")); - assertEquals("query", body.get("action")); - assertEquals("login", body.get("type")); - assertEquals("tokens", body.get("meta")); - - RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST"); - body = parseBody(loginRequest.getBody().readUtf8()); - assertEquals("1", body.get("rememberMe")); - assertEquals("foo", body.get("username")); - assertEquals("bar", body.get("password")); - assertEquals("baz", body.get("logintoken")); - assertEquals("https://commons.wikimedia.org", body.get("loginreturnurl")); - assertEquals("xml", body.get("format")); - - assertEquals("wrongpassword", result); - } - - @Test - public void simpleLogin() throws Exception { - server.enqueue(new MockResponse().setBody("")); - server.enqueue(new MockResponse().setBody("")); - - String result = testObject.login("foo", "bar"); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST"); - Map body = parseBody(loginTokenRequest.getBody().readUtf8()); - assertEquals("xml", body.get("format")); - assertEquals("query", body.get("action")); - assertEquals("login", body.get("type")); - assertEquals("tokens", body.get("meta")); - - RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST"); - body = parseBody(loginRequest.getBody().readUtf8()); - assertEquals("1", body.get("rememberMe")); - assertEquals("foo", body.get("username")); - assertEquals("bar", body.get("password")); - assertEquals("baz", body.get("logintoken")); - assertEquals("https://commons.wikimedia.org", body.get("loginreturnurl")); - assertEquals("xml", body.get("format")); - - assertEquals("PASS", result); - } - - @Test - public void twoFactorLogin() throws Exception { - server.enqueue(new MockResponse().setBody("")); - server.enqueue(new MockResponse().setBody("")); - - String result = testObject.login("foo", "bar", "2fa"); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST"); - Map body = parseBody(loginTokenRequest.getBody().readUtf8()); - assertEquals("xml", body.get("format")); - assertEquals("query", body.get("action")); - assertEquals("login", body.get("type")); - assertEquals("tokens", body.get("meta")); - - RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST"); - body = parseBody(loginRequest.getBody().readUtf8()); - assertEquals("true", body.get("rememberMe")); - assertEquals("foo", body.get("username")); - assertEquals("bar", body.get("password")); - assertEquals("baz", body.get("logintoken")); - assertEquals("true", body.get("logincontinue")); - assertEquals("2fa", body.get("OATHToken")); - assertEquals("xml", body.get("format")); - - assertEquals("PASS", result); - } - - @Test - public void validateLoginForLoggedInUser() throws Exception { - server.enqueue(new MockResponse().setBody("")); - - boolean result = testObject.validateLogin(); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET"); - Map body = parseQueryParams(loginTokenRequest); - assertEquals("xml", body.get("format")); - assertEquals("query", body.get("action")); - assertEquals("userinfo", body.get("meta")); - - assertTrue(result); - } - - @Test - public void validateLoginForLoggedOutUser() throws Exception { - server.enqueue(new MockResponse().setBody("")); - - boolean result = testObject.validateLogin(); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET"); - Map params = parseQueryParams(loginTokenRequest); - assertEquals("xml", params.get("format")); - assertEquals("query", params.get("action")); - assertEquals("userinfo", params.get("meta")); - - assertFalse(result); - } - - @Test - public void editToken() throws Exception { - server.enqueue(new MockResponse().setBody("")); - - String result = testObject.getEditToken(); - - RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET"); - Map params = parseQueryParams(loginTokenRequest); - assertEquals("xml", params.get("format")); - assertEquals("tokens", params.get("action")); - assertEquals("edit", params.get("type")); - - assertEquals("baz", result); - } - - @Test - public void fileExistsWithName_FileNotFound() throws Exception { - server.enqueue(new MockResponse().setBody(" ")); - - boolean result = testObject.fileExistsWithName("foo"); - - RecordedRequest request = assertBasicRequestParameters(server, "GET"); - Map params = parseQueryParams(request); - assertEquals("xml", params.get("format")); - assertEquals("query", params.get("action")); - assertEquals("imageinfo", params.get("prop")); - assertEquals("File:foo", params.get("titles")); - - assertFalse(result); - } - - @Test - public void getUploadCount() throws InterruptedException { - server.enqueue(new MockResponse().setBody("23\n")); - - TestObserver testObserver = testObject.getUploadCount("testUsername").test(); - - RecordedRequest request = server.takeRequest(); - Map params = parseQueryParams(request); - assertEquals("testUsername", params.get("user")); - - assertEquals(1, testObserver.valueCount()); - assertEquals(23, (int)testObserver.values().get(0)); - } - - private RecordedRequest assertBasicRequestParameters(MockWebServer server, String method) throws InterruptedException { - RecordedRequest request = server.takeRequest(); - assertEquals("/", request.getRequestUrl().encodedPath()); - assertEquals(method, request.getMethod()); - assertEquals("Commons/" + BuildConfig.VERSION_NAME + " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE, request.getHeader("User-Agent")); - if ("POST".equals(method)) { - assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type")); - } - return request; - } - - private Map parseQueryParams(RecordedRequest request) { - Map result = new HashMap<>(); - HttpUrl url = request.getRequestUrl(); - Set params = url.queryParameterNames(); - for (String name : params) { - result.put(name, url.queryParameter(name)); - } - return result; - } - - private Map parseBody(String body) throws UnsupportedEncodingException { - String[] props = body.split("&"); - Map result = new HashMap<>(); - for (String prop : props) { - String[] pair = prop.split("="); - result.put(pair[0], URLDecoder.decode(pair[1], "utf-8")); - } - return result; - } -} diff --git a/app/src/test/java/fr/free/nrw/commons/utils/StringSortingUtilsTest.java b/app/src/test/java/fr/free/nrw/commons/utils/StringSortingUtilsTest.java deleted file mode 100644 index 6384fb096..000000000 --- a/app/src/test/java/fr/free/nrw/commons/utils/StringSortingUtilsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package fr.free.nrw.commons.utils; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class StringSortingUtilsTest { - - @Test - public void testSortingNumbersBySimilarity() throws Exception { - List actualList = Arrays.asList("1234567", "4567", "12345", "123", "1234"); - List expectedList = Arrays.asList("1234", "12345", "123", "1234567", "4567"); - - Collections.sort(actualList, StringSortingUtils.sortBySimilarity("1234")); - Assert.assertEquals(expectedList, actualList); - } - - @Test - public void testSortingTextBySimilarity() throws Exception { - List actualList = Arrays.asList("The quick brown fox", - "quick brown fox", - "The", - "The quick ", - "The fox", - "brown fox", - "fox"); - List expectedList = Arrays.asList("The", - "The fox", - "The quick ", - "The quick brown fox", - "quick brown fox", - "brown fox", - "fox"); - - Collections.sort(actualList, StringSortingUtils.sortBySimilarity("The")); - Assert.assertEquals(expectedList, actualList); - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt new file mode 100644 index 000000000..8be291d4d --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt @@ -0,0 +1,33 @@ +package fr.free.nrw.commons + +import fr.free.nrw.commons.upload.FileUtils +import org.junit.Assert.assertEquals +import org.junit.Test +import java.io.* + +class FileUtilsTest { + @Test + fun copiedFileIsIdenticalToSource() { + val source = File.createTempFile("temp", "") + val dest = File.createTempFile("temp", "") + writeToFile(source, "Hello, World") + + FileUtils.copy(FileInputStream(source), FileOutputStream(dest)) + + assertEquals(getString(source), getString(dest)) + } + + private fun writeToFile(file: File, s: String) { + val buf = BufferedOutputStream(FileOutputStream(file)) + buf.write(s.toByteArray()) + buf.close() + } + + private fun getString(file: File): String { + val bytes = ByteArray(file.length().toInt()) + val buf = BufferedInputStream(FileInputStream(file)) + buf.read(bytes, 0, bytes.size) + buf.close() + return String(bytes) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt new file mode 100644 index 000000000..efafa4e3a --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt @@ -0,0 +1,64 @@ +package fr.free.nrw.commons + +import fr.free.nrw.commons.location.LatLng +import org.junit.Assert.assertEquals +import org.junit.Test + +class LatLngTests { + @Test + fun testZeroZero() { + val place = LatLng(0.0, 0.0, 0f) + assertPrettyCoordinateString("0.0 N, 0.0 E", place) + } + + @Test + fun testAntipode() { + val place = LatLng(0.0, 180.0, 0f) + assertPrettyCoordinateString("0.0 N, 180.0 W", place) + } + + @Test + fun testNorthPole() { + val place = LatLng(90.0, 0.0, 0f) + assertPrettyCoordinateString("90.0 N, 0.0 E", place) + } + + @Test + fun testSouthPole() { + val place = LatLng(-90.0, 0.0, 0f) + assertPrettyCoordinateString("90.0 S, 0.0 E", place) + } + + @Test + fun testLargerNumbers() { + val place = LatLng(120.0, 380.0, 0f) + assertPrettyCoordinateString("90.0 N, 20.0 E", place) + } + + @Test + fun testNegativeNumbers() { + val place = LatLng(-120.0, -30.0, 0f) + assertPrettyCoordinateString("90.0 S, 30.0 W", place) + } + + @Test + fun testTooBigWestValue() { + val place = LatLng(20.0, -190.0, 0f) + assertPrettyCoordinateString("20.0 N, 170.0 E", place) + } + + @Test + fun testRounding() { + val place = LatLng(0.1234567, -0.33333333, 0f) + assertPrettyCoordinateString("0.1235 N, 0.3333 W", place) + } + + @Test + fun testRoundingAgain() { + val place = LatLng(-0.000001, -0.999999, 0f) + assertPrettyCoordinateString("0.0 S, 1.0 W", place) + } + + private fun assertPrettyCoordinateString(expected: String, place: LatLng) = + assertEquals(expected, place.prettyCoordinateString) +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt new file mode 100644 index 000000000..63b0b4d0a --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt @@ -0,0 +1,46 @@ +package fr.free.nrw.commons + +import fr.free.nrw.commons.location.LatLng +import fr.free.nrw.commons.utils.LengthUtils +import org.junit.Assert.assertEquals +import org.junit.Test + +class LengthUtilsTest { + @Test + fun testZeroDistance() { + val pointA = LatLng(0.0, 0.0, 0f) + val pointB = LatLng(0.0, 0.0, 0f) + assertDistanceBetween("0m", pointA, pointB) + } + + @Test + fun testOneDegreeOnEquator() { + val pointA = LatLng(0.0, 0.0, 0f) + val pointB = LatLng(0.0, 1.0, 0f) + assertDistanceBetween("111.2km", pointA, pointB) + } + + @Test + fun testOneDegreeFortyFiveDegrees() { + val pointA = LatLng(45.0, 0.0, 0f) + val pointB = LatLng(45.0, 1.0, 0f) + assertDistanceBetween("78.6km", pointA, pointB) + } + + @Test + fun testOneDegreeSouthPole() { + val pointA = LatLng(-90.0, 0.0, 0f) + val pointB = LatLng(-90.0, 1.0, 0f) + assertDistanceBetween("0m", pointA, pointB) + } + + @Test + fun testPoleToPole() { + val pointA = LatLng(90.0, 0.0, 0f) + val pointB = LatLng(-90.0, 0.0, 0f) + assertDistanceBetween("20,015.1km", pointA, pointB) + } + + private fun assertDistanceBetween(expected: String, pointA: LatLng, pointB: LatLng) = + assertEquals(expected, LengthUtils.formatDistanceBetween(pointA, pointB)) +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt new file mode 100644 index 000000000..f75c34568 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt @@ -0,0 +1,23 @@ +package fr.free.nrw.commons + +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class) +class MediaTest { + @Test + fun displayTitleShouldStripExtension() { + val m = Media("File:Example.jpg") + assertEquals("Example", m.displayTitle) + } + + @Test + fun displayTitleShouldUseSpaceForUnderscore() { + val m = Media("File:Example 1_2.jpg") + assertEquals("Example 1 2", m.displayTitle) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/NearbyControllerTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/NearbyControllerTest.kt new file mode 100644 index 000000000..fc0be84d0 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/NearbyControllerTest.kt @@ -0,0 +1,35 @@ +package fr.free.nrw.commons + +import fr.free.nrw.commons.location.LatLng +import fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class) +class NearbyControllerTest { + + @Test + fun testNullAttractions() { + val location = LatLng(0.0, 0.0, 0f) + + val options = loadAttractionsFromLocationToBaseMarkerOptions( + location, null, RuntimeEnvironment.application) + + assertEquals(0, options.size.toLong()) + } + + @Test + fun testEmptyList() { + val location = LatLng(0.0, 0.0, 0f) + + val options = loadAttractionsFromLocationToBaseMarkerOptions( + location, emptyList(), RuntimeEnvironment.application) + + assertEquals(0, options.size.toLong()) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt new file mode 100644 index 000000000..28112b196 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt @@ -0,0 +1,67 @@ +package fr.free.nrw.commons + +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.net.URLEncoder + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class) +class PageTitleTest { + @Test + fun displayTextShouldNotBeUnderscored() { + val pageTitle = PageTitle("Ex_1 ") + assertEquals("Ex 1", pageTitle.displayText) + } + + @Test + fun moreThanTwoColons() { + val pageTitle = PageTitle("File:sample:a.jpg") + assertEquals("File:Sample:a.jpg", pageTitle.prefixedText) + } + + @Test + fun getTextShouldReturnWithoutNamespace() { + val pageTitle = PageTitle("File:sample.jpg") + assertEquals("Sample.jpg", pageTitle.text) + } + + + @Test + fun capitalizeNameAfterNamespace() { + val pageTitle = PageTitle("File:sample.jpg") + assertEquals("File:Sample.jpg", pageTitle.prefixedText) + } + + @Test + fun prefixedTextShouldBeUnderscored() { + val pageTitle = PageTitle("Ex 1 ") + assertEquals("Ex_1", pageTitle.prefixedText) + } + + @Test + fun getMobileUriForTest() { + val pageTitle = PageTitle("Test") + assertEquals(BuildConfig.MOBILE_HOME_URL + "Test", pageTitle.mobileUri.toString()) + } + + @Test + fun spaceBecomesUnderscoreInUri() { + val pageTitle = PageTitle("File:Ex 1.jpg") + assertEquals(BuildConfig.HOME_URL + "File:Ex_1.jpg", pageTitle.canonicalUri.toString()) + } + + @Test + fun leaveSubpageNamesUncapitalizedInUri() { + val pageTitle = PageTitle("User:Ex/subpage") + assertEquals(BuildConfig.HOME_URL + "User:Ex/subpage", pageTitle.canonicalUri.toString()) + } + + @Test + fun unicodeUri() { + val pageTitle = PageTitle("User:例") + assertEquals(BuildConfig.HOME_URL + "User:" + URLEncoder.encode("例", "utf-8"), pageTitle.canonicalUri.toString()) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt new file mode 100644 index 000000000..73760dd40 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -0,0 +1,72 @@ +package fr.free.nrw.commons + +import android.content.Context +import android.content.SharedPreferences +import android.support.v4.util.LruCache +import com.nhaarman.mockito_kotlin.mock +import com.squareup.leakcanary.RefWatcher +import fr.free.nrw.commons.auth.AccountUtil +import fr.free.nrw.commons.auth.SessionManager +import fr.free.nrw.commons.caching.CacheController +import fr.free.nrw.commons.data.DBOpenHelper +import fr.free.nrw.commons.di.CommonsApplicationComponent +import fr.free.nrw.commons.di.CommonsApplicationModule +import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent +import fr.free.nrw.commons.location.LocationServiceManager +import fr.free.nrw.commons.mwapi.MediaWikiApi +import fr.free.nrw.commons.nearby.NearbyPlaces +import fr.free.nrw.commons.upload.UploadController + +class TestCommonsApplication : CommonsApplication() { + private var mockApplicationComponent: CommonsApplicationComponent? = null + + override fun onCreate() { + if (mockApplicationComponent == null) { + mockApplicationComponent = DaggerCommonsApplicationComponent.builder() + .appModule(MockCommonsApplicationModule(this)).build() + } + super.onCreate() + } + + // No leakcanary in unit tests. + override fun setupLeakCanary(): RefWatcher = RefWatcher.DISABLED +} + +class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModule(appContext) { + val accountUtil: AccountUtil = mock() + val appSharedPreferences: SharedPreferences = mock() + val defaultSharedPreferences: SharedPreferences = mock() + val otherSharedPreferences: SharedPreferences = mock() + val uploadController: UploadController = mock() + val mockSessionManager: SessionManager = mock() + val mediaWikiApi: MediaWikiApi = mock() + val locationServiceManager: LocationServiceManager = mock() + val cacheController: CacheController = mock() + val mockDbOpenHelper: DBOpenHelper = mock() + val nearbyPlaces: NearbyPlaces = mock() + val lruCache: LruCache = mock() + + override fun providesAccountUtil(context: Context): AccountUtil = accountUtil + + override fun providesApplicationSharedPreferences(context: Context): SharedPreferences = appSharedPreferences + + override fun providesDefaultSharedPreferences(context: Context): SharedPreferences = defaultSharedPreferences + + override fun providesOtherSharedPreferences(context: Context): SharedPreferences = otherSharedPreferences + + override fun providesUploadController(sessionManager: SessionManager, sharedPreferences: SharedPreferences, context: Context): UploadController = uploadController + + override fun providesSessionManager(context: Context, mediaWikiApi: MediaWikiApi, sharedPreferences: SharedPreferences): SessionManager = mockSessionManager + + override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences): MediaWikiApi = mediaWikiApi + + override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager + + override fun provideCacheController(): CacheController = cacheController + + override fun provideDBOpenHelper(context: Context): DBOpenHelper = mockDbOpenHelper + + override fun provideNearbyPlaces(): NearbyPlaces = nearbyPlaces + + override fun provideLruCache(): LruCache = lruCache +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt new file mode 100644 index 000000000..0082b9d28 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/UtilsFixExtensionTest.kt @@ -0,0 +1,68 @@ +package fr.free.nrw.commons + +import fr.free.nrw.commons.Utils.fixExtension +import org.junit.Assert.assertEquals +import org.junit.Test + +class UtilsFixExtensionTest { + + @Test + fun jpegResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "jpeg")) + } + + @Test + fun capitalJpegWithNoHintResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.JPEG", null)) + } + + @Test + fun jpegWithBogusHintResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", null)) + } + + @Test + fun jpegToCapitalJpegResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "JPEG")) + } + + @Test + fun jpgToJpegResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpg", "jpeg")) + } + + @Test + fun jpegToJpgResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "jpg")) + } + + @Test + fun jpgRemainsJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpg", "jpg")) + } + + @Test + fun pngRemainsPng() { + assertEquals("SampleFile.png", fixExtension("SampleFile.png", "png")) + } + + @Test + fun jpgHintResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile", "jpg")) + } + + @Test + fun jpegHintResultsInJpg() { + assertEquals("SampleFile.jpg", fixExtension("SampleFile", "jpeg")) + } + + @Test + fun dotLessJpgToJpgResultsInJpg() { + assertEquals("SAMPLEjpg.jpg", fixExtension("SAMPLEjpg", "jpg")) + } + + @Test + fun inWordJpegToJpgResultsInJpg() { + assertEquals("X.jpeg.SAMPLE.jpg", fixExtension("X.jpeg.SAMPLE", "jpg")) + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt new file mode 100644 index 000000000..b64d3b8aa --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/category/CategoryDaoTest.kt @@ -0,0 +1,257 @@ +package fr.free.nrw.commons.category + +import android.content.ContentProviderClient +import android.content.ContentValues +import android.database.Cursor +import android.database.MatrixCursor +import android.database.sqlite.SQLiteDatabase +import android.os.RemoteException +import com.nhaarman.mockito_kotlin.* +import fr.free.nrw.commons.BuildConfig +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.category.CategoryContentProvider.BASE_URI +import fr.free.nrw.commons.category.CategoryContentProvider.uriForId +import fr.free.nrw.commons.category.CategoryDao.Table.* +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.util.* + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class) +class CategoryDaoTest { + + private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED, COLUMN_TIMES_USED) + private val client: ContentProviderClient = mock() + private val database: SQLiteDatabase = mock() + private val captor = argumentCaptor() + private val queryCaptor = argumentCaptor>() + + private lateinit var testObject: CategoryDao + + @Before + fun setUp() { + testObject = CategoryDao { client } + } + + @Test + fun createTable() { + onCreate(database) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + + @Test + fun deleteTable() { + onDelete(database) + inOrder(database) { + verify(database).execSQL(DROP_TABLE_STATEMENT) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + } + + @Test + fun migrateTableVersionFrom_v1_to_v2() { + onUpdate(database, 1, 2) + // Table didnt exist before v5 + verifyZeroInteractions(database) + } + + @Test + fun migrateTableVersionFrom_v2_to_v3() { + onUpdate(database, 2, 3) + // Table didnt exist before v5 + verifyZeroInteractions(database) + } + + @Test + fun migrateTableVersionFrom_v3_to_v4() { + onUpdate(database, 3, 4) + // Table didnt exist before v5 + verifyZeroInteractions(database) + } + + @Test + fun migrateTableVersionFrom_v4_to_v5() { + onUpdate(database, 4, 5) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + + @Test + fun migrateTableVersionFrom_v5_to_v6() { + onUpdate(database, 5, 6) + // Table didnt change in version 6 + verifyZeroInteractions(database) + } + + @Test + fun createFromCursor() { + createCursor(1).let { cursor -> + cursor.moveToFirst() + testObject.fromCursor(cursor).let { + assertEquals(uriForId(1), it.contentUri) + assertEquals("foo", it.name) + assertEquals(123, it.lastUsed.time) + assertEquals(2, it.timesUsed) + } + } + } + + @Test + fun saveExistingCategory() { + createCursor(1).let { + val category = testObject.fromCursor(it.apply { moveToFirst() }) + + testObject.save(category) + + verify(client).update(eq(category.contentUri), captor.capture(), isNull(), isNull()) + captor.firstValue.let { cv -> + assertEquals(3, cv.size()) + assertEquals(category.name, cv.getAsString(COLUMN_NAME)) + assertEquals(category.lastUsed.time, cv.getAsLong(COLUMN_LAST_USED)) + assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED)) + } + } + } + + @Test + fun saveNewCategory() { + val contentUri = CategoryContentProvider.uriForId(111) + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val category = Category(null, "foo", Date(234L), 1) + + testObject.save(category) + + verify(client).insert(eq(BASE_URI), captor.capture()) + captor.firstValue.let { cv -> + assertEquals(3, cv.size()) + assertEquals(category.name, cv.getAsString(COLUMN_NAME)) + assertEquals(category.lastUsed.time, cv.getAsLong(COLUMN_LAST_USED)) + assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED)) + assertEquals(contentUri, category.contentUri) + } + } + + @Test(expected = RuntimeException::class) + fun testSaveTranslatesRemoteExceptions() { + whenever(client.insert(isA(), isA())).thenThrow(RemoteException("")) + testObject.save(Category()) + } + + @Test + fun whenTheresNoDataFindReturnsNull_nullCursor() { + whenever(client.query(any(), any(), any(), any(), any())).thenReturn(null) + assertNull(testObject.find("foo")) + } + + @Test + fun whenTheresNoDataFindReturnsNull_emptyCursor() { + whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0)) + assertNull(testObject.find("foo")) + } + + @Test + fun cursorsAreClosedAfterUse() { + val mockCursor: Cursor = mock() + whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor) + whenever(mockCursor.moveToFirst()).thenReturn(false) + + testObject.find("foo") + + verify(mockCursor).close() + } + + @Test + fun findCategory() { + whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1)) + + val category = testObject.find("foo") + assertNotNull(category) + + assertEquals(uriForId(1), category?.contentUri) + assertEquals("foo", category?.name) + assertEquals(123L, category?.lastUsed?.time) + assertEquals(2, category?.timesUsed) + + verify(client).query( + eq(BASE_URI), + eq(ALL_FIELDS), + eq("$COLUMN_NAME=?"), + queryCaptor.capture(), + isNull() + ) + assertEquals("foo", queryCaptor.firstValue[0]) + } + + @Test(expected = RuntimeException::class) + fun findCategoryTranslatesExceptions() { + whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenThrow(RemoteException("")) + testObject.find("foo") + } + + @Test(expected = RuntimeException::class) + fun recentCategoriesTranslatesExceptions() { + whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenThrow(RemoteException("")) + testObject.recentCategories(1) + } + + @Test + fun recentCategoriesReturnsEmptyList_nullCursor() { + whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(null) + assertTrue(testObject.recentCategories(1).isEmpty()) + } + + @Test + fun recentCategoriesReturnsEmptyList_emptyCursor() { + whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0)) + assertTrue(testObject.recentCategories(1).isEmpty()) + } + + @Test + fun cursorsAreClosedAfterRecentCategoriesQuery() { + val mockCursor: Cursor = mock() + whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(mockCursor) + whenever(mockCursor.moveToFirst()).thenReturn(false) + + testObject.recentCategories(1) + + verify(mockCursor).close() + } + + @Test + fun recentCategoriesReturnsLessThanLimit() { + whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(1)) + + val result = testObject.recentCategories(10) + + assertEquals(1, result.size) + assertEquals("foo", result[0]) + + verify(client).query( + eq(BASE_URI), + eq(ALL_FIELDS), + isNull(), + queryCaptor.capture(), + eq("$COLUMN_LAST_USED DESC") + ) + assertEquals(0, queryCaptor.firstValue.size) + } + + @Test + fun recentCategoriesHonorsLimit() { + whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(10)) + + val result = testObject.recentCategories(5) + + assertEquals(5, result.size) + } + + private fun createCursor(rowCount: Int) = MatrixCursor(columns, rowCount).apply { + for (i in 0 until rowCount) { + addRow(listOf("1", "foo", "123", "2")) + } + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionDaoTest.kt new file mode 100644 index 000000000..762e0bb85 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionDaoTest.kt @@ -0,0 +1,335 @@ +package fr.free.nrw.commons.contributions + +import android.content.ContentProviderClient +import android.content.ContentValues +import android.database.MatrixCursor +import android.database.sqlite.SQLiteDatabase +import android.net.Uri +import android.os.RemoteException +import com.nhaarman.mockito_kotlin.* +import fr.free.nrw.commons.BuildConfig +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.Utils +import fr.free.nrw.commons.contributions.Contribution.* +import fr.free.nrw.commons.contributions.ContributionDao.Table +import fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI +import fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import java.util.* + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class) +class ContributionDaoTest { + private val localUri = "http://example.com/" + private val client: ContentProviderClient = mock() + private val database: SQLiteDatabase = mock() + private val captor = argumentCaptor() + + private lateinit var contentUri: Uri + private lateinit var testObject: ContributionDao + + @Before + fun setUp() { + contentUri = uriForId(111) + testObject = ContributionDao { client } + } + + @Test + fun createTable() { + Table.onCreate(database) + verify(database).execSQL(Table.CREATE_TABLE_STATEMENT) + } + + @Test + fun deleteTable() { + Table.onDelete(database) + + inOrder(database) { + verify(database).execSQL(Table.DROP_TABLE_STATEMENT) + verify(database).execSQL(Table.CREATE_TABLE_STATEMENT) + } + } + + @Test + fun upgradeDatabase_v1_to_v2() { + Table.onUpdate(database, 1, 2) + + inOrder(database) { + verify(database).execSQL(Table.ADD_DESCRIPTION_FIELD) + verify(database).execSQL(Table.ADD_CREATOR_FIELD) + } + } + + @Test + fun upgradeDatabase_v2_to_v3() { + Table.onUpdate(database, 2, 3) + + inOrder(database) { + verify(database).execSQL(Table.ADD_MULTIPLE_FIELD) + verify(database).execSQL(Table.SET_DEFAULT_MULTIPLE) + } + } + + @Test + fun upgradeDatabase_v3_to_v4() { + Table.onUpdate(database, 3, 4) + + // No changes + verifyZeroInteractions(database) + } + + @Test + fun upgradeDatabase_v4_to_v5() { + Table.onUpdate(database, 4, 5) + + // No changes + verifyZeroInteractions(database) + } + + @Test + fun upgradeDatabase_v5_to_v6() { + Table.onUpdate(database, 5, 6) + + inOrder(database) { + verify(database).execSQL(Table.ADD_WIDTH_FIELD) + verify(database).execSQL(Table.SET_DEFAULT_WIDTH) + verify(database).execSQL(Table.ADD_HEIGHT_FIELD) + verify(database).execSQL(Table.SET_DEFAULT_HEIGHT) + verify(database).execSQL(Table.ADD_LICENSE_FIELD) + verify(database).execSQL(Table.SET_DEFAULT_LICENSE) + } + } + + @Test + fun saveNewContribution_nonNullFields() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(true, null, null, null, null) + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + captor.firstValue.let { + // Long fields + assertEquals(222L, it.getAsLong(Table.COLUMN_LENGTH)) + assertEquals(321L, it.getAsLong(Table.COLUMN_TIMESTAMP)) + assertEquals(333L, it.getAsLong(Table.COLUMN_TRANSFERRED)) + + // Integer fields + assertEquals(STATE_COMPLETED, it.getAsInteger(Table.COLUMN_STATE)) + assertEquals(640, it.getAsInteger(Table.COLUMN_WIDTH)) + assertEquals(480, it.getAsInteger(Table.COLUMN_HEIGHT)) + + // String fields + assertEquals(SOURCE_CAMERA, it.getAsString(Table.COLUMN_SOURCE)) + assertEquals("desc", it.getAsString(Table.COLUMN_DESCRIPTION)) + assertEquals("create", it.getAsString(Table.COLUMN_CREATOR)) + assertEquals("007", it.getAsString(Table.COLUMN_LICENSE)) + } + } + + @Test + fun saveNewContribution_nullableFieldsAreNull() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(true, null, null, null, null) + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + captor.firstValue.let { + // Nullable fields are absent if null + assertFalse(it.containsKey(Table.COLUMN_LOCAL_URI)) + assertFalse(it.containsKey(Table.COLUMN_IMAGE_URL)) + assertFalse(it.containsKey(Table.COLUMN_UPLOADED)) + } + } + + @Test + fun saveNewContribution_nullableImageUrlUsesFileAsBackup() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(true, null, null, null, "file") + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + captor.firstValue.let { + // Nullable fields are absent if null + assertFalse(it.containsKey(Table.COLUMN_LOCAL_URI)) + assertFalse(it.containsKey(Table.COLUMN_UPLOADED)) + assertEquals(Utils.makeThumbBaseUrl("file"), it.getAsString(Table.COLUMN_IMAGE_URL)) + } + } + + @Test + fun saveNewContribution_nullableFieldsAreNonNull() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(true, Uri.parse(localUri), + "image", Date(456L), null) + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + captor.firstValue.let { + assertEquals(localUri, it.getAsString(Table.COLUMN_LOCAL_URI)) + assertEquals("image", it.getAsString(Table.COLUMN_IMAGE_URL)) + assertEquals(456L, it.getAsLong(Table.COLUMN_UPLOADED)) + } + } + + @Test + fun saveNewContribution_booleanEncodesTrue() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(true, null, null, null, null) + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + + // Boolean true --> 1 for ths encoding scheme + assertEquals("Boolean true should be encoded as 1", 1, + captor.firstValue.getAsInteger(Table.COLUMN_MULTIPLE)) + } + + @Test + fun saveNewContribution_booleanEncodesFalse() { + whenever(client.insert(isA(), isA())).thenReturn(contentUri) + val contribution = createContribution(false, null, null, null, null) + + testObject.save(contribution) + + assertEquals(contentUri, contribution.contentUri) + verify(client).insert(eq(BASE_URI), captor.capture()) + + // Boolean true --> 1 for ths encoding scheme + assertEquals("Boolean false should be encoded as 0", 0, + captor.firstValue.getAsInteger(Table.COLUMN_MULTIPLE)) + } + + @Test + fun saveExistingContribution() { + val contribution = createContribution(false, null, null, null, null) + contribution.contentUri = contentUri + + testObject.save(contribution) + + verify(client).update(eq(contentUri), isA(), isNull(), isNull()) + } + + @Test(expected = RuntimeException::class) + fun saveTranslatesExceptions() { + whenever(client.insert(isA(), isA())).thenThrow(RemoteException("")) + + testObject.save(createContribution(false, null, null, null, null)) + } + + @Test(expected = RuntimeException::class) + fun deleteTranslatesExceptions() { + whenever(client.delete(anyOrNull(), anyOrNull(), anyOrNull())).thenThrow(RemoteException("")) + + val contribution = createContribution(false, null, null, null, null) + contribution.contentUri = contentUri + testObject.delete(contribution) + } + + @Test(expected = RuntimeException::class) + fun exceptionThrownWhenAttemptingToDeleteUnsavedContribution() { + testObject.delete(createContribution(false, null, null, null, null)) + } + + @Test + fun deleteExistingContribution() { + val contribution = createContribution(false, null, null, null, null) + contribution.contentUri = contentUri + + testObject.delete(contribution) + + verify(client).delete(eq(contentUri), isNull(), isNull()) + } + + @Test + fun createFromCursor() { + val created = 321L + val uploaded = 456L + createCursor(created, uploaded, false, localUri).let { mc -> + testObject.fromCursor(mc).let { + assertEquals(uriForId(111), it.contentUri) + assertEquals("file", it.filename) + assertEquals(localUri, it.localUri.toString()) + assertEquals("image", it.imageUrl) + assertEquals(created, it.timestamp.time) + assertEquals(created, it.dateCreated.time) + assertEquals(STATE_QUEUED, it.state) + assertEquals(222L, it.dataLength) + assertEquals(uploaded, it.dateUploaded?.time) + assertEquals(88L, it.transferred) + assertEquals(SOURCE_GALLERY, it.source) + assertEquals("desc", it.description) + assertEquals("create", it.creator) + assertEquals(640, it.width) + assertEquals(480, it.height) + assertEquals("007", it.license) + } + } + } + + @Test + fun createFromCursor_nullableTimestamps() { + createCursor(0L, 0L, false, localUri).let { mc -> + testObject.fromCursor(mc).let { + assertNull(it.timestamp) + assertNull(it.dateCreated) + assertNull(it.dateUploaded) + } + } + } + + @Test + fun createFromCursor_nullableLocalUri() { + createCursor(0L, 0L, false, "").let { mc -> + testObject.fromCursor(mc).let { + assertNull(it.localUri) + assertNull(it.dateCreated) + assertNull(it.dateUploaded) + } + } + } + + @Test + fun createFromCursor_booleanEncoding() { + val mcFalse = createCursor(0L, 0L, false, localUri) + assertFalse(testObject.fromCursor(mcFalse).multiple) + + val mcHammer = createCursor(0L, 0L, true, localUri) + assertTrue(testObject.fromCursor(mcHammer).multiple) + } + + private fun createCursor(created: Long, uploaded: Long, multiple: Boolean, localUri: String) = + MatrixCursor(Table.ALL_FIELDS, 1).apply { + addRow(listOf("111", "file", localUri, "image", + created, STATE_QUEUED, 222L, uploaded, 88L, SOURCE_GALLERY, "desc", + "create", if (multiple) 1 else 0, 640, 480, "007")) + moveToFirst() + } + + private fun createContribution(isMultiple: Boolean, localUri: Uri?, imageUrl: String?, dateUploaded: Date?, filename: String?) = + Contribution(localUri, imageUrl, filename, "desc", 222L, Date(321L), dateUploaded, + "create", "edit", "coords").apply { + state = STATE_COMPLETED + transferred = 333L + source = SOURCE_CAMERA + license = "007" + multiple = isMultiple + timestamp = Date(321L) + width = 640 + height = 480 // VGA should be enough for anyone, right? + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.kt new file mode 100644 index 000000000..bf0ddf772 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/modifications/ModifierSequenceDaoTest.kt @@ -0,0 +1,156 @@ +package fr.free.nrw.commons.modifications + +import android.content.ContentProviderClient +import android.content.ContentValues +import android.database.MatrixCursor +import android.database.sqlite.SQLiteDatabase +import android.net.Uri +import android.os.RemoteException +import com.nhaarman.mockito_kotlin.* +import fr.free.nrw.commons.BuildConfig +import fr.free.nrw.commons.TestCommonsApplication +import fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI +import fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class) +class ModifierSequenceDaoTest { + + private val mediaUrl = "http://example.com/" + private val columns = arrayOf(COLUMN_ID, COLUMN_MEDIA_URI, COLUMN_DATA) + private val client: ContentProviderClient = mock() + private val database: SQLiteDatabase = mock() + private val contentValuesCaptor = argumentCaptor() + + private lateinit var testObject: ModifierSequenceDao + + @Before + fun setUp() { + testObject = ModifierSequenceDao { client } + } + + @Test + fun createFromCursorWithEmptyModifiers() { + testObject.fromCursor(createCursor("")).let { + assertEquals(mediaUrl, it.mediaUri.toString()) + assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), it.contentUri.toString()) + assertTrue(it.modifiers.isEmpty()) + } + } + + @Test + fun createFromCursorWtihCategoryModifier() { + val cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}") + + val seq = testObject.fromCursor(cursor) + + assertEquals(1, seq.modifiers.size) + assertTrue(seq.modifiers[0] is CategoryModifier) + } + + @Test + fun createFromCursorWithRemoveModifier() { + val cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}") + + val seq = testObject.fromCursor(cursor) + + assertEquals(1, seq.modifiers.size) + assertTrue(seq.modifiers[0] is TemplateRemoveModifier) + } + + @Test + fun deleteSequence() { + whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1) + val seq = testObject.fromCursor(createCursor("")) + + testObject.delete(seq) + + verify(client).delete(eq(seq.contentUri), isNull(), isNull()) + } + + @Test(expected = RuntimeException::class) + fun deleteTranslatesRemoteExceptions() { + whenever(client.delete(isA(), isNull(), isNull())).thenThrow(RemoteException("")) + val seq = testObject.fromCursor(createCursor("")) + + testObject.delete(seq) + } + + @Test + fun saveExistingSequence() { + val modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}" + val expectedData = "{\"modifiers\":[$modifierJson]}" + val cursor = createCursor(modifierJson) + val seq = testObject.fromCursor(cursor) + + testObject.save(seq) + + verify(client).update(eq(seq.contentUri), contentValuesCaptor.capture(), isNull(), isNull()) + contentValuesCaptor.firstValue.let { + assertEquals(2, it.size()) + assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI)) + assertEquals(expectedData, it.get(COLUMN_DATA)) + } + } + + @Test + fun saveNewSequence() { + val expectedContentUri = BASE_URI.buildUpon().appendPath("1").build() + whenever(client.insert(isA(), isA())).thenReturn(expectedContentUri) + val seq = ModifierSequence(Uri.parse(mediaUrl)) + + testObject.save(seq) + + assertEquals(expectedContentUri.toString(), seq.contentUri.toString()) + verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture()) + contentValuesCaptor.firstValue.let { + assertEquals(2, it.size()) + assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI)) + assertEquals("{\"modifiers\":[]}", it.get(COLUMN_DATA)) + } + } + + @Test(expected = RuntimeException::class) + fun saveTranslatesRemoteExceptions() { + whenever(client.insert(isA(), isA())).thenThrow(RemoteException("")) + testObject.save(ModifierSequence(Uri.parse(mediaUrl))) + } + + @Test + fun createTable() { + onCreate(database) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + + @Test + fun updateTable() { + onUpdate(database, 1, 2) + + inOrder(database) { + verify(database).execSQL(DROP_TABLE_STATEMENT) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + } + + @Test + fun deleteTable() { + onDelete(database) + + inOrder(database) { + verify(database).execSQL(DROP_TABLE_STATEMENT) + verify(database).execSQL(CREATE_TABLE_STATEMENT) + } + } + + private fun createCursor(modifierJson: String) = MatrixCursor(columns, 1).apply { + addRow(listOf("1", mediaUrl, "{\"modifiers\": [$modifierJson]}")) + moveToFirst() + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt new file mode 100644 index 000000000..c51d354c2 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt @@ -0,0 +1,246 @@ +package fr.free.nrw.commons.mwapi + +import android.content.SharedPreferences +import android.os.Build +import android.preference.PreferenceManager +import fr.free.nrw.commons.BuildConfig +import fr.free.nrw.commons.TestCommonsApplication +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import okhttp3.mockwebserver.RecordedRequest +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config +import java.net.URLDecoder +import java.util.* + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class) +class ApacheHttpClientMediaWikiApiTest { + + private lateinit var testObject: ApacheHttpClientMediaWikiApi + private lateinit var server: MockWebServer + private lateinit var sharedPreferences: SharedPreferences + + @Before + fun setUp() { + server = MockWebServer() + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) + testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences) + testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/") + } + + @After + fun teardown() { + server.shutdown() + } + + @Test + fun authCookiesAreHandled() { + assertEquals("", testObject.authCookie) + + testObject.authCookie = "cookie=chocolate-chip" + + assertEquals("cookie=chocolate-chip", testObject.authCookie) + } + + @Test + fun simpleLoginWithWrongPassword() { + server.enqueue(MockResponse().setBody("")) + server.enqueue(MockResponse().setBody("")) + + val result = testObject.login("foo", "bar") + + assertBasicRequestParameters(server, "POST").let { loginTokenRequest -> + parseBody(loginTokenRequest.body.readUtf8()).let { body -> + assertEquals("xml", body["format"]) + assertEquals("query", body["action"]) + assertEquals("login", body["type"]) + assertEquals("tokens", body["meta"]) + } + } + + assertBasicRequestParameters(server, "POST").let { loginRequest -> + parseBody(loginRequest.body.readUtf8()).let { body -> + assertEquals("1", body["rememberMe"]) + assertEquals("foo", body["username"]) + assertEquals("bar", body["password"]) + assertEquals("baz", body["logintoken"]) + assertEquals("https://commons.wikimedia.org", body["loginreturnurl"]) + assertEquals("xml", body["format"]) + } + } + + assertEquals("wrongpassword", result) + } + + @Test + fun simpleLogin() { + server.enqueue(MockResponse().setBody("")) + server.enqueue(MockResponse().setBody("")) + + val result = testObject.login("foo", "bar") + + assertBasicRequestParameters(server, "POST").let { loginTokenRequest -> + parseBody(loginTokenRequest.body.readUtf8()).let { body -> + assertEquals("xml", body["format"]) + assertEquals("query", body["action"]) + assertEquals("login", body["type"]) + assertEquals("tokens", body["meta"]) + } + } + + assertBasicRequestParameters(server, "POST").let { loginRequest -> + parseBody(loginRequest.body.readUtf8()).let { body -> + assertEquals("1", body["rememberMe"]) + assertEquals("foo", body["username"]) + assertEquals("bar", body["password"]) + assertEquals("baz", body["logintoken"]) + assertEquals("https://commons.wikimedia.org", body["loginreturnurl"]) + assertEquals("xml", body["format"]) + } + } + + assertEquals("PASS", result) + } + + @Test + fun twoFactorLogin() { + server.enqueue(MockResponse().setBody("")) + server.enqueue(MockResponse().setBody("")) + + val result = testObject.login("foo", "bar", "2fa") + + assertBasicRequestParameters(server, "POST").let { loginTokenRequest -> + parseBody(loginTokenRequest.body.readUtf8()).let { body -> + assertEquals("xml", body["format"]) + assertEquals("query", body["action"]) + assertEquals("login", body["type"]) + assertEquals("tokens", body["meta"]) + } + } + + assertBasicRequestParameters(server, "POST").let { loginRequest -> + parseBody(loginRequest.body.readUtf8()).let { body -> + assertEquals("true", body["rememberMe"]) + assertEquals("foo", body["username"]) + assertEquals("bar", body["password"]) + assertEquals("baz", body["logintoken"]) + assertEquals("true", body["logincontinue"]) + assertEquals("2fa", body["OATHToken"]) + assertEquals("xml", body["format"]) + } + } + + assertEquals("PASS", result) + } + + @Test + fun validateLoginForLoggedInUser() { + server.enqueue(MockResponse().setBody("")) + + val result = testObject.validateLogin() + + assertBasicRequestParameters(server, "GET").let { loginTokenRequest -> + parseQueryParams(loginTokenRequest).let { body -> + assertEquals("xml", body["format"]) + assertEquals("query", body["action"]) + assertEquals("userinfo", body["meta"]) + } + } + + assertTrue(result) + } + + @Test + fun validateLoginForLoggedOutUser() { + server.enqueue(MockResponse().setBody("")) + + val result = testObject.validateLogin() + + assertBasicRequestParameters(server, "GET").let { loginTokenRequest -> + parseQueryParams(loginTokenRequest).let { params -> + assertEquals("xml", params["format"]) + assertEquals("query", params["action"]) + assertEquals("userinfo", params["meta"]) + } + } + + assertFalse(result) + } + + @Test + fun editToken() { + server.enqueue(MockResponse().setBody("")) + + val result = testObject.editToken + + assertBasicRequestParameters(server, "GET").let { loginTokenRequest -> + parseQueryParams(loginTokenRequest).let { params -> + assertEquals("xml", params["format"]) + assertEquals("tokens", params["action"]) + assertEquals("edit", params["type"]) + } + } + + assertEquals("baz", result) + } + + @Test + fun fileExistsWithName_FileNotFound() { + server.enqueue(MockResponse().setBody(" ")) + + val result = testObject.fileExistsWithName("foo") + + assertBasicRequestParameters(server, "GET").let { request -> + parseQueryParams(request).let { params -> + assertEquals("xml", params["format"]) + assertEquals("query", params["action"]) + assertEquals("imageinfo", params["prop"]) + assertEquals("File:foo", params["titles"]) + } + } + + assertFalse(result) + } + + @Test + fun getUploadCount() { + server.enqueue(MockResponse().setBody("23\n")) + + val testObserver = testObject.getUploadCount("testUsername").test() + + assertEquals("testUsername", parseQueryParams(server.takeRequest())["user"]) + assertEquals(1, testObserver.valueCount()) + assertEquals(23, testObserver.values()[0]) + } + + private fun assertBasicRequestParameters(server: MockWebServer, method: String): RecordedRequest = server.takeRequest().let { + assertEquals("/", it.requestUrl.encodedPath()) + assertEquals(method, it.method) + assertEquals("Commons/${BuildConfig.VERSION_NAME} (https://mediawiki.org/wiki/Apps/Commons) Android/${Build.VERSION.RELEASE}", + it.getHeader("User-Agent")) + if ("POST" == method) { + assertEquals("application/x-www-form-urlencoded", it.getHeader("Content-Type")) + } + return it + } + + private fun parseQueryParams(request: RecordedRequest) = HashMap().apply { + request.requestUrl.let { + it.queryParameterNames().forEach { name -> put(name, it.queryParameter(name)) } + } + } + + private fun parseBody(body: String): Map = HashMap().apply { + body.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().forEach { prop -> + val pair = prop.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + put(pair[0], URLDecoder.decode(pair[1], "utf-8")) + } + } +} diff --git a/app/src/test/kotlin/fr/free/nrw/commons/utils/StringSortingUtilsTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/utils/StringSortingUtilsTest.kt new file mode 100644 index 000000000..83e2f7169 --- /dev/null +++ b/app/src/test/kotlin/fr/free/nrw/commons/utils/StringSortingUtilsTest.kt @@ -0,0 +1,41 @@ +package fr.free.nrw.commons.utils + +import fr.free.nrw.commons.utils.StringSortingUtils.sortBySimilarity +import org.junit.Assert.assertEquals +import org.junit.Test +import java.util.Collections.sort + +class StringSortingUtilsTest { + + @Test + fun testSortingNumbersBySimilarity() { + val actualList = listOf("1234567", "4567", "12345", "123", "1234") + val expectedList = listOf("1234", "12345", "123", "1234567", "4567") + + sort(actualList, sortBySimilarity("1234")) + + assertEquals(expectedList, actualList) + } + + @Test + fun testSortingTextBySimilarity() { + val actualList = listOf("The quick brown fox", + "quick brown fox", + "The", + "The quick ", + "The fox", + "brown fox", + "fox") + val expectedList = listOf("The", + "The fox", + "The quick ", + "The quick brown fox", + "quick brown fox", + "brown fox", + "fox") + + sort(actualList, sortBySimilarity("The")) + + assertEquals(expectedList, actualList) + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index b0e8b6718..42dfeec75 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.1.51' + ext.kotlin_version = '1.2.31' repositories { jcenter() mavenCentral() From 802b2a8df410adeb5942dfc8742225a849b1b6f9 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Sun, 8 Apr 2018 12:17:20 +0300 Subject: [PATCH 016/184] Hot fix bundle issue (#1425) * Fixed bug #1399 * Changed visibility from visible to gone * Changed behaviour according to review * Changed bottom sheet visibility from visible to gone * Fix adding bundle to an already created fragment --- .../nrw/commons/nearby/NearbyActivity.java | 8 +++--- .../commons/nearby/NearbyListFragment.java | 9 +++++-- .../nrw/commons/nearby/NearbyMapFragment.java | 25 +++++++++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 36dee44a9..176c45c36 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -474,17 +474,17 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::populatePlaces); - nearbyMapFragment.setArguments(bundle); + nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.updateMapSignificantly(); updateListFragment(); return; } if (isSlightUpdate) { - nearbyMapFragment.setArguments(bundle); + nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.updateMapSlightly(); } else { - nearbyMapFragment.setArguments(bundle); + nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.updateMapSignificantly(); updateListFragment(); } @@ -498,7 +498,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp } private void updateListFragment() { - nearbyListFragment.setArguments(bundle); + nearbyListFragment.setBundleForUpdates(bundle); nearbyListFragment.updateNearbyListSignificantly(); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java index e46bd76e7..4a2be8476 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java @@ -33,6 +33,8 @@ import static android.app.Activity.RESULT_OK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; public class NearbyListFragment extends DaggerFragment { + private Bundle bundleForUpdates; // Carry information from activity about changed nearby places and current location + private static final Type LIST_TYPE = new TypeToken>() { }.getType(); private static final Type CUR_LAT_LNG_TYPE = new TypeToken() { @@ -80,8 +82,7 @@ public class NearbyListFragment extends DaggerFragment { } public void updateNearbyListSignificantly() { - Bundle bundle = this.getArguments(); - adapterFactory.updateAdapterData(getPlaceListFromBundle(bundle), + adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates), (RVRendererAdapter) recyclerView.getAdapter()); } @@ -140,4 +141,8 @@ public class NearbyListFragment extends DaggerFragment { } } + public void setBundleForUpdates(Bundle bundleForUpdates) { + this.bundleForUpdates = bundleForUpdates; + } + } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index d37e67b06..3affb2605 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -110,6 +110,8 @@ public class NearbyMapFragment extends DaggerFragment { private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04; + private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location + @Inject @Named("prefs") SharedPreferences prefs; @@ -191,14 +193,12 @@ public class NearbyMapFragment extends DaggerFragment { } public void updateMapSlightly() { - // Get arguments from bundle for new location - Bundle bundle = this.getArguments(); if (mapboxMap != null) { Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriDeserializer()) .create(); - if (bundle != null) { - String gsonLatLng = bundle.getString("CurLatLng"); + if (bundleForUpdtes != null) { + String gsonLatLng = bundleForUpdtes.getString("CurLatLng"); Type curLatLngType = new TypeToken() {}.getType(); curLatLng = gson.fromJson(gsonLatLng, curLatLngType); } @@ -208,17 +208,15 @@ public class NearbyMapFragment extends DaggerFragment { } public void updateMapSignificantly() { - - Bundle bundle = this.getArguments(); if (mapboxMap != null) { - if (bundle != null) { + if (bundleForUpdtes != null) { Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriDeserializer()) .create(); - String gsonPlaceList = bundle.getString("PlaceList"); - String gsonLatLng = bundle.getString("CurLatLng"); - String gsonBoundaryCoordinates = bundle.getString("BoundaryCoord"); + String gsonPlaceList = bundleForUpdtes.getString("PlaceList"); + String gsonLatLng = bundleForUpdtes.getString("CurLatLng"); + String gsonBoundaryCoordinates = bundleForUpdtes.getString("BoundaryCoord"); Type listType = new TypeToken>() {}.getType(); List placeList = gson.fromJson(gsonPlaceList, listType); Type curLatLngType = new TypeToken() {}.getType(); @@ -773,7 +771,7 @@ public class NearbyMapFragment extends DaggerFragment { } } - private void closeFabs ( boolean isFabOpen){ + private void closeFabs ( boolean isFabOpen){ if (isFabOpen) { fabPlus.startAnimation(rotate_backward); fabCamera.startAnimation(fab_close); @@ -784,6 +782,11 @@ public class NearbyMapFragment extends DaggerFragment { } } + public void setBundleForUpdtes(Bundle bundleForUpdtes) { + this.bundleForUpdtes = bundleForUpdtes; + } + + @Override public void onStart() { if (mapView != null) { From 2de9a1fe089d99f7190ea1dc06c77962877a86a2 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 9 Apr 2018 08:15:46 +0200 Subject: [PATCH 017/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ast/strings.xml | 4 ++-- app/src/main/res/values-b+sr+Latn/strings.xml | 4 ++-- app/src/main/res/values-ba/strings.xml | 4 ++-- app/src/main/res/values-bn/strings.xml | 6 ++++-- app/src/main/res/values-br/strings.xml | 4 ++-- app/src/main/res/values-bs/strings.xml | 2 +- app/src/main/res/values-cs/strings.xml | 4 ++-- app/src/main/res/values-da/strings.xml | 4 ++-- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-el/strings.xml | 4 ++-- app/src/main/res/values-es/strings.xml | 4 ++-- app/src/main/res/values-fa/strings.xml | 4 ++-- app/src/main/res/values-fi/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 6 ++++-- app/src/main/res/values-frr/strings.xml | 2 +- app/src/main/res/values-gl/strings.xml | 12 ++++++++---- app/src/main/res/values-hi/strings.xml | 4 ++-- app/src/main/res/values-hu/strings.xml | 4 ++-- app/src/main/res/values-is/strings.xml | 4 ++-- app/src/main/res/values-iw/strings.xml | 4 ++-- app/src/main/res/values-ja/strings.xml | 4 ++-- app/src/main/res/values-jv/strings.xml | 2 +- app/src/main/res/values-kab/strings.xml | 4 ++-- app/src/main/res/values-ko/strings.xml | 4 ++-- app/src/main/res/values-lb/strings.xml | 2 +- app/src/main/res/values-lt/strings.xml | 2 +- app/src/main/res/values-mk/strings.xml | 4 ++-- app/src/main/res/values-mr/strings.xml | 4 ++-- app/src/main/res/values-nb/strings.xml | 4 ++-- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pa/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pms/strings.xml | 4 ++-- app/src/main/res/values-pt-rBR/strings.xml | 4 ++-- app/src/main/res/values-pt/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 8 +++++--- app/src/main/res/values-sd/strings.xml | 2 +- app/src/main/res/values-skr/strings.xml | 1 + app/src/main/res/values-sr/strings.xml | 4 ++-- app/src/main/res/values-su/strings.xml | 4 ++-- app/src/main/res/values-sv/strings.xml | 4 ++-- app/src/main/res/values-th/strings.xml | 4 ++-- app/src/main/res/values-tr/strings.xml | 4 ++-- app/src/main/res/values-uk/strings.xml | 4 ++-- app/src/main/res/values-vi/strings.xml | 4 ++-- app/src/main/res/values-zh-rTW/strings.xml | 4 ++-- app/src/main/res/values-zh/strings.xml | 4 ++-- 47 files changed, 97 insertions(+), 86 deletions(-) diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 1c486a0b8..a04003e1e 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -155,8 +155,8 @@ Ensin descripción Llicencia desconocida Refrescar - Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. - Permisu riquíu: escritura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. + Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. + Permisu riquíu: escritura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. Permisu opcional: llograr l\'allugamientu actual pa suxerir categoríes Aceutar Llugares cercanos diff --git a/app/src/main/res/values-b+sr+Latn/strings.xml b/app/src/main/res/values-b+sr+Latn/strings.xml index d361ef334..0cd72a167 100644 --- a/app/src/main/res/values-b+sr+Latn/strings.xml +++ b/app/src/main/res/values-b+sr+Latn/strings.xml @@ -139,8 +139,8 @@ Nema opisa Nepoznata licenca Osveži - Potrebna dozvola: Provera spoljašnje memorije. Aplikacija bez ovoga ne može da funkcioniše. - Neophodna dozvola: Pisanje spoljašnjeg skladišta. Aplikacija ne može da funkcioniše bez ovoga. + Potrebna dozvola: Provera spoljašnje memorije. Aplikacija bez ovoga ne može da funkcioniše. + Neophodna dozvola: Pisanje spoljašnjeg skladišta. Aplikacija ne može da funkcioniše bez ovoga. Opciona dozvola: Preuzmi trenutnu lokaciju za predloge kategorija U redu Mesta u blizini diff --git a/app/src/main/res/values-ba/strings.xml b/app/src/main/res/values-ba/strings.xml index 03729cfac..293dd3f73 100644 --- a/app/src/main/res/values-ba/strings.xml +++ b/app/src/main/res/values-ba/strings.xml @@ -154,8 +154,8 @@ Һүрәтләүе юҡ Билдәһеҙ лицензия Яңыртып алыу - Кәрәкле рөхсәт: тышҡы һаҡлағыстан алып уҡыу. Ҡушымта шунһыҙ эшләмәйәсәк. - Кәрәкле рөхсәт: тышҡы һаҡлағысҡа яҙыу. Ҡушымта шунһыҙ эшләмәйәсәк. + Кәрәкле рөхсәт: тышҡы һаҡлағыстан алып уҡыу. Ҡушымта шунһыҙ эшләмәйәсәк. + Кәрәкле рөхсәт: тышҡы һаҡлағысҡа яҙыу. Ҡушымта шунһыҙ эшләмәйәсәк. Мотлаҡ булмаған рөхсәт: категория тәҡдиме өсөн ошо урынды алыу Яҡындағы урындар Яҡындағы урындар табылманы diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index fe404d495..e308e69a7 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -162,8 +162,8 @@ বিবরণ নেই অজানা লাইসেন্স পুনঃসতেজ - প্রয়োজনীয় অনুমতি: বহিঃস্ত সঞ্চয়স্থান পড়া। এটি ছাড়া অ্যাপ কাজ করবে না। - অনুমতি প্রয়োজন: অালাদাভাবে সংযুক্ত স্টোরেজ লিখুন। এটি ছাড়া অ্যাপটি চলতে পারেনা। + প্রয়োজনীয় অনুমতি: বহিঃস্ত সঞ্চয়স্থান পড়া। এটি ছাড়া অ্যাপ কাজ করবে না। + অনুমতি প্রয়োজন: অালাদাভাবে সংযুক্ত স্টোরেজ লিখুন। এটি ছাড়া অ্যাপটি চলতে পারেনা। ঐচ্ছিক অনুমতি: বিষয়শ্রেণী পরামর্শের জন্য বর্তমান অবস্থান নেয় ঠিক আছে কাছাকাছি স্থান @@ -254,4 +254,6 @@ টিউটোরিয়াল এড়ান ইন্টারনেট অনুপলব্ধ ইন্টারনেট উপলব্ধ + কোন বিজ্ঞপ্তি পাওয়া যায়নি + পুনঃচেষ্টা করুন diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index 673d9ee7b..8383f7cbe 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -153,8 +153,8 @@ Deskrivadur ebet Aotre-implijout dizanv Freskaat - Aotre rekis : lenn ur stokañ diavaez. Hep se, n\'hall ket an arload mont en-dro. - Aotre ret ; skrivañ war al lec\'h stokañ diavaez. Ne c\'hall ket an arload mont en-dro hep an dra-se. + Aotre rekis : lenn ur stokañ diavaez. Hep se, n\'hall ket an arload mont en-dro. + Aotre ret ; skrivañ war al lec\'h stokañ diavaez. Ne c\'hall ket an arload mont en-dro hep an dra-se. Aotre diret : kaout al lec\'hiadur red evit kinnig rummadoù Mat eo Lec\'hioù nes diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml index 0a753c037..6c0097089 100644 --- a/app/src/main/res/values-bs/strings.xml +++ b/app/src/main/res/values-bs/strings.xml @@ -138,7 +138,7 @@ Nema opisa Nepoznata licenca Osvježi - Potrebna dozvola: Čitanje vanjske memorije. Aplikacija ne može raditi bez ovog. + Potrebna dozvola: Čitanje vanjske memorije. Aplikacija ne može raditi bez ovog. Neobavezna dozvola: Dobavljanje trenutne lokacije za predlaganje kategorija U redu Mjesta u blizini diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index b22c86fb7..6ea1f55bd 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -165,8 +165,8 @@ Bez popisu Neznámá licence Obnovit - Požadováno oprávnění ke čtení externího úložiště. Aplikace bez toho nemůže pracovat. - Požadováno oprávnění k zápisu do externího úložiště. Aplikace bez toho nemůže pracovat. + Požadováno oprávnění ke čtení externího úložiště. Aplikace bez toho nemůže pracovat. + Požadováno oprávnění k zápisu do externího úložiště. Aplikace bez toho nemůže pracovat. Volitelně: Umožněte aplikaci, aby získávala aktuální polohu a nabízela na jejím základě kategorie OK Místa v okolí diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index a0b50111d..e10a93850 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -159,8 +159,8 @@ Ingen beskrivelse Ukendt licens Opdater - Krævet tilladelse: Læs eksternt lager. Programmet kan ikke fungere uden denne tilladelse. - Krævet tilladelse: Skriv til eksternt lager. Program kan ikke fungere uden denne funktion. + Krævet tilladelse: Læs eksternt lager. Programmet kan ikke fungere uden denne tilladelse. + Krævet tilladelse: Skriv til eksternt lager. Program kan ikke fungere uden denne funktion. Valgfri tilladelse: Hent nuværende position for kategoriforslag O.k. Steder i nærheden diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6eeba5b1f..3550010b8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -159,8 +159,8 @@ Keine Beschreibung Unbekannte Lizenz Aktualisieren - Erforderliche Berechtigung: Externen Speicher lesen. Die App funktioniert ohne diese Berechtigung nicht. - Erforderliche Berechtigung: Externen Speicher beschreiben. Die App kann ohne dies nicht funktionieren. + Erforderliche Berechtigung: Externen Speicher lesen. Die App kann ohne diese Berechtigung nicht auf deine Galerie zugreifen. + Erforderliche Berechtigung: Externen Speicher beschreiben. Die App kann ohne diese Berechtigung nicht auf deine Kamera zugreifen. Optionale Berechtigung: Ruft den aktuellen Standort für Kategorievorschläge ab Okay Orte in der Nähe diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 320d7a72f..505856316 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -163,8 +163,8 @@ Καμία περιγραφή Άγνωστη άδεια Ανανέωση - Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να λειτουργήσει χωρίς αυτή. - Απαιτούμενη άδεια: Με εξωτερική αποθήκευση.Το πρόγραμμα δεν μπορεί να λειτουργήσει με αυτήν. + Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να λειτουργήσει χωρίς αυτή. + Απαιτούμενη άδεια: Με εξωτερική αποθήκευση.Το πρόγραμμα δεν μπορεί να λειτουργήσει με αυτήν. Προαιρετική άδεια: Ανάκτηση τρέχουσας θέσης σας για προτάσεις κατηγοριών Εντάξει Κοντινοί Τόποι diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ef67e2024..ff4e246c1 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -163,8 +163,8 @@ Sin descripción Licencia desconocida Actualizar - Permiso obligatorio: lectura de almacenamiento externo. La aplicación no puede funcionar sin él. - Permiso necesario: Escribir en almacenamiento externo. La aplicación no puede funcionar sin él. + Permiso obligatorio: lectura de almacenamiento externo. La aplicación no puede acceder a la galería sin él. + Permiso necesario: Escribir en almacenamiento externo. La aplicación no puede acceder a la cámara sin él. Permiso opcional: obtener la ubicación actual para sugerir categorías Aceptar Lugares cercanos diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 3ec113535..d80b0772c 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -149,8 +149,8 @@ بدون توضیحات مجوز ناشناخته تازه‌کردن - اجازه‌های مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند. - اجازه‌های مورد نیاز: نوشتن حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند. + اجازه‌های مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند. + اجازه‌های مورد نیاز: نوشتن حافظهٔ خارجی. اپلیکیشن بدون آن نمی‌تواند کار کند. اجازه‌های اختیاری: دریافت موقعیت برای پیشنهاد رده تأیید مکان‌‌های اطراف diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 544c8bf11..dd1d37993 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -161,8 +161,8 @@ Ei kuvausta Tuntematon lisenssi Päivitä - Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei toimi ilman tätä oikeutta. - Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi toimia ilman tätä. + Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei toimi ilman tätä oikeutta. + Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi toimia ilman tätä. Valinnainen lupa: Saada tämänhetkinen sijainti loukkasuosituksia varten. OK Lähellä olevat paikat diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8897574a9..0a2f1e3be 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2,6 +2,7 @@ @@ -92,7 +93,7 @@ Acerca de A aplicación Wikimedia Commons é unha aplicación de código aberto creada e mantida polos cesionarios e voluntarios da comunidade de Wikimedia. A Fundación Wikimedia non está involucrada na creación, desenvolvemento ou mantemento da aplicación. Crear unha nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia</a> para informar de problemas e suxestións. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Política de privacidade</a> + <u>Política de privacidade</u> <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> Acerca de Enviar comentarios (por correo electrónico) @@ -160,8 +161,8 @@ Sen descrición Licenza descoñecida Refrescar - Permiso necesarioː ler un almacenamento externo. A aplicación non pode funcionar sen isto. - Permiso necesario: Escribir en almacenamento externo. A aplicación non pode funcionar sen el. + Permiso necesarioː ler un almacenamento externo. A aplicación non pode acceder á súa galería sen isto. + Permiso necesario: Escribir en almacenamento externo. A aplicación non pode acceder á súa cámara sen el. Permiso opcionalː obter a localización actual para suxerir categorías Aceptar Lugares próximos @@ -251,14 +252,17 @@ WIKIDATA WIKIPEDIA COMMONS - FAQ + <u>Avalíenos</u> + <u>FAQ</u> Saltar titorial Internet non dispoñible Internet dispoñible Erro ó recuperar as notificacións Non se atopou ningunha notificación + <u>Traducir</u> Linguas Seleccione a lingua para a que quere enviar as traducións Proceder Cancelar + Reintentar diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 6bf7385be..69bb67655 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -149,8 +149,8 @@ कोई विवरण नहीं अज्ञात लाइसेन्स ताजा करें - अनिवार्य अनुमति: बाहरी स्मृति पढ़ें। एप इसके बिना कार्य नहीं करेगा। - अनिवार्य अनुमति:बाहरी कंप्यूटर स्टोरेज लिखना|इसके बिना एप कार्य नहीं करेगा। + अनिवार्य अनुमति: बाहरी स्मृति पढ़ें। एप इसके बिना कार्य नहीं करेगा। + अनिवार्य अनुमति:बाहरी कंप्यूटर स्टोरेज लिखना|इसके बिना एप कार्य नहीं करेगा। वैकल्पिक अनुमति: श्रेणी सुझाव हेतु वर्तमान स्थान ज्ञात करें ठीक है आसपास के स्थान diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 3b163f9a2..82f1e3c96 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -148,8 +148,8 @@ Nincs leírás Ismeretlen licenc Frissítés - Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. - Szükséges engedély: Külső tárhely írása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely írása. Az alkalmazás nem működik enélkül. Lehetséges engedély: Jelenlegi hely megszerzése, a kategóriajavaslatok lehetőségéért. OK Közeli helyek diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 15afc41f2..45c327170 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -154,8 +154,8 @@ Engin lýsing Óþekkt notkunarleyfi Endurlesa - Nauðsynlegar heimildir: Lesa ytri gagnageymslu. Forritið virkar ekki án þess. - Nauðsynlegar heimildir: Skrifa í ytri gagnageymslu. Forritið virkar ekki án þess. + Nauðsynlegar heimildir: Lesa ytri gagnageymslu. Forritið virkar ekki án þess. + Nauðsynlegar heimildir: Skrifa í ytri gagnageymslu. Forritið virkar ekki án þess. Nauðsynlegar heimildir: Lesa núverandi staðsetningu til að geta stungið upp á flokkum Í lagi Staðir í nágrenninu diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 533c6d950..898778d98 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -162,8 +162,8 @@ אין תיאור רישיון לא ידוע רענון - הרשאה מחייבת: אחסון. היישום לא יכול לעבוד בלי זה. - נדרשת הרשאה: כתיבה לאחסון חיצוני. היישום לא יכול לעבוד בלי זה. + נדרשת הרשאה: קריאת אחסון חיצוני. היישום לא יכול לגשת לגלריה שלך בלי זה. + נדרשת הרשאה: כתיבה לאחסון חיצוני. היישום לא יכול לגשת למצלמה שלך בלי זה. הרשאה לא מחייבת: קבלת מיקום נוכחי בשביל הצעות קטגוריות אישור מקומות בסביבה diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 09e65ba94..711987324 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -143,8 +143,8 @@ 説明はありません。 不明なライセンス 更新 - 必要な権限:外部ストレージを読み込みます。これがなければアプリは機能しません。 - 必要な権限:外部ストレージを作成します。これがなければアプリは機能しません。 + 必要な権限:外部ストレージを読み込みます。これがなければアプリは機能しません。 + 必要な権限:外部ストレージを作成します。これがなければアプリは機能しません。 オプションの権限:カテゴリ候補の現在の位置を取得する 承認 周りの場所 diff --git a/app/src/main/res/values-jv/strings.xml b/app/src/main/res/values-jv/strings.xml index 43d7929e7..e051b6f97 100644 --- a/app/src/main/res/values-jv/strings.xml +++ b/app/src/main/res/values-jv/strings.xml @@ -122,7 +122,7 @@ Tanpa katerangan Lisènsi ora kaweruhan Anyarana - Butuh palilah: Maca panyimpenan njaba. Aplikasi mokal mlaku yèn tanpa iki. + Butuh palilah: Maca panyimpenan njaba. Aplikasi mokal mlaku yèn tanpa iki. Palilah manasuka: Njupuk pernah saiki kanggo saran ing kategori Oké Papan Cedhak Kéné diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index c3cc422c8..342c615b9 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -138,8 +138,8 @@ Ulac aglam Turagt tarussint Smiren - Yesra tasiregt: Ɣeṛ asekles azɣaray. Asnas ur yezmir ara ad yeddu s war aya. - Ysera tasiregt: Aru deg usekles azɣaray. Asnas ur yezmir ara ad yeddu s war aya. + Yesra tasiregt: Ɣeṛ asekles azɣaray. Asnas ur yezmir ara ad yeddu s war aya. + Ysera tasiregt: Aru deg usekles azɣaray. Asnas ur yezmir ara ad yeddu s war aya. Tasiregt tafrayant: Awi adig amiran i yisumar n taggayt IH Idigen iqeṛben diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 5156b7e3a..52f69aabb 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -158,8 +158,8 @@ 설명 없음 알 수 없는 라이선스 새로 고침 - 권한 필요: 외부 저장소 읽기. 이것이 없으면 앱은 동작하지 않습니다. - 권한 필요: 외부 저장소 쓰기. 이것이 없으면 앱은 동작하지 않습니다. + 권한 필요: 외부 저장소 읽기. 이것이 없으면 앱은 갤러리에 접근할 수 없습니다. + 권한 필요: 외부 저장소 쓰기. 이것이 없으면 앱은 카메라에 접근할 수 없습니다. 선택적 권한: 분류 추천을 위해 현재 위치 정보를 가져옵니다. 확인 근처의 장소 diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index a43f2ea89..587887c9b 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -152,7 +152,7 @@ Keng Beschreiwung Onbekannt Lizenz Aktualiséieren - Obligatoresch Autorisatioun: Externe Späicher liesen. D\'App kann net ouni dat funktionéieren. + Obligatoresch Autorisatioun: Externe Späicher liesen. D\'App kann ouni dat net op d\'Galerie zougräifen. Fakultativ Autorisatioun: Déi aktuell Plaz kréie fir Propose fir Kategorien OK Plazen nobäi diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 2011f748b..c5c0813ab 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -116,7 +116,7 @@ Nėra aprašymo Nežinoma licencija Atnaujinti - Reikalinga teisė: Skaityti išorinę talpyklą. Programėle be to negali funkcionuoti. + Reikalinga teisė: Skaityti išorinę talpyklą. Programėle be to negali funkcionuoti. Neprivaloma teisė: Gauti dabartinę vietovę, kad būtų pasiūlomos kategorijos Gerai Netoliese Esančios Vietos diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 81e831769..7171f2738 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -155,8 +155,8 @@ Нема опис Непозната лиценца Превчитај - Потребна дозвола: Треба да се прочита од надворешен склад. Прилогот не може да работи без ова. - Потребна дозвола: Треба да се запише на надворешен склад. Прилогот не може да работи без ова. + Потребна дозвола: Треба да се прочита од надворешен склад. Прилогот без ова нема пристап до вашата галерија. + Потребна дозвола: Треба да се запише на надворешен склад. Прилогот без ова нема пристап до вашата камера. Дозвола по желба: Утврдување на тековната местоположба за предлагање категории ОК Околни места diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml index ec68c9d3e..09eaafbc9 100644 --- a/app/src/main/res/values-mr/strings.xml +++ b/app/src/main/res/values-mr/strings.xml @@ -158,8 +158,8 @@ वर्णन नाही. अनोळखी परवाना ताजेतवाने करा - परवानगी आवश्यक:बाह्य भंडारण वाचन. याशिवाय अॅप काम करू शकत नाही. - परवानगी आवश्यक:बाह्य भंडारण वाचन. याशिवाय अॅप काम करू शकत नाही. + परवानगी आवश्यक:बाह्य भंडारण वाचन. याशिवाय अॅप काम करू शकत नाही. + परवानगी आवश्यक:बाह्य भंडारण वाचन. याशिवाय अॅप काम करू शकत नाही. ऐच्छिक परवानगी:वर्ग सुचवण्यांसाठी सध्याचे स्थान मिळवा ठीक आहे जवळपासची स्थाने diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index f5540c2cc..1a7f38679 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -150,8 +150,8 @@ Ingen beskrivelse Ukjent lisens Gjenoppfrisk - Nødvendig tillatelse: Lese ekstern lagring. Appen virker ikke uten dette. - Påkrevd tillatelse: Skriv til ekstern lagring. Appen fungerer ikke uten dette. + Nødvendig tillatelse: Lese ekstern lagring. Appen virker ikke uten dette. + Påkrevd tillatelse: Skriv til ekstern lagring. Appen fungerer ikke uten dette. Valgfri tillatelse: Hent nåværende posisjon for kategoriforslag OK Plasser i nærheten diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 8c54affe3..f2688cffa 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -139,7 +139,7 @@ Geen beschrijving Onbekende licentie Vernieuwen - Benodigde toestemming: Lees externe opslag. Zonder deze toestemming kan de app niet functioneren. + Benodigde toestemming: Lees externe opslag. Zonder deze toestemming kan de app niet functioneren. Optionele toestemming: Huidige locatie ophalen voor categoriesuggesties OK Plaatsen in de buurt diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index d6fa40a3a..6937ab75d 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -137,7 +137,7 @@ ਕੋਈ ਵੇਰਵਾ ਨਹੀਂ ਅਣਜਾਣ ਲਸੰਸ ਤਾਜ਼ਾ ਕਰੋ - ਆਗਿਆ ਚਾਹੀਦੀ ਹੈ: ਬਾਹਰੀ ਸਟੋਰੇਜ ਬਾਰੇ। ਇਸ ਤੋਂ ਬਿਨਾਂ ਐਪ ਕਾਰਜ ਨਹੀਂ ਕਰ ਸਕੇਗੀ। + ਆਗਿਆ ਚਾਹੀਦੀ ਹੈ: ਬਾਹਰੀ ਸਟੋਰੇਜ ਬਾਰੇ। ਇਸ ਤੋਂ ਬਿਨਾਂ ਐਪ ਕਾਰਜ ਨਹੀਂ ਕਰ ਸਕੇਗੀ। ਠੀਕ ਹੈ ਨਜ਼ਦੀਕੀ ਥਾਵਾਂ ਕੋਈ ਨਜ਼ਦੀਕੀ ਥਾਵਾਂ ਨਹੀਂ ਮਿਲੀਆਂ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index b5ccf4df3..d19dfc7c8 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -159,7 +159,7 @@ Brak opisu Nieznana licencja Odśwież - Wymagane uprawnienia: odczyt z dysku zewnętrznego. Aplikacja nie będzie w stanie funkcjonować bez tego. + Wymagane uprawnienia: odczyt z dysku zewnętrznego. Aplikacja nie będzie w stanie funkcjonować bez tego. Opcjonalne zezwolenie: uzyskiwanie bieżącej lokalizacji dla wygenerowania propozycji kategorii OK Pobliskie miejsca diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index a867a3152..8cd31dfb8 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -155,8 +155,8 @@ Gnun-a descrission Licensa sconossùa Rinfrësché - Autorisassion necessaria: Lese n\'anmagasinament estern. L\'aplicassion a peul pa marcé sensa lòn. - Autorisassion necessaria: Scrive n\'anmagasinament estern. L\'aplicassion a peul pa marcé sensa \'d lòn. + Autorisassion necessaria: Lese n\'anmagasinament estern. L\'aplicassion a peul pa marcé sensa lòn. + Autorisassion necessaria: Scrive n\'anmagasinament estern. L\'aplicassion a peul pa marcé sensa \'d lòn. Autorisassion facoltativa: Oten-e la posission atual për dij sugeriment ëd categorìa Va bin Pòst davzin diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 732fbee18..067a5329c 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -167,8 +167,8 @@ Sem descrição Licença desconhecida Atualizar - Permissão necessária: Ler armazenamento externo. O aplicativo não pode funcionar sem isso. - Permissão necessária: Escreva armazenamento externo. A aplicação não pode funcionar sem isso. + Permissão necessária: leia o armazenamento externo. App não pode acessar sua galeria sem isso. + Permissão necessária: escreva o armazenamento externo. App não pode acessar sua câmera sem isso. Permissão opcional: Obter a localização atual de sugestões de categoria OK Lugares próximos diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index a817711c7..69df2f342 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -164,8 +164,8 @@ Sem descrição Licença desconhecida Actualizar - Permissão necessária: Ler a armazenagem externa. A aplicação não pode funcionar sem isto. - Permissão necessária: Escrever na armazenagem externa. A aplicação não pode funcionar sem isto. + Permissão necessária: Ler a armazenagem externa. A aplicação não pode funcionar sem isto. + Permissão necessária: Escrever na armazenagem externa. A aplicação não pode funcionar sem isto. Permissão opcional: Obter a localização atual para sugestões de categoria OK Locais Próximos diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index f51e7e20b..cc1545be7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -6,6 +6,7 @@ * Envlh * Facenapalm * Gazimagomedov +* Happy13241 * Iluvatar * Kaganer * MaxBioHazard @@ -174,8 +175,8 @@ Нет описания Неизвестная лицензия Обновить - Требуемые разрешения: чтение с внешнего хранилища. Приложение не сможет функционировать без этого. - Требуемые разрешения: запись на внешнее хранилище. Приложение не сможет функционировать без этого. + Требуемые разрешения: чтение с внешнего хранилища. Приложение не сможет доступ ваша галерея без этой. + Требуемые разрешения: запись на внешнее хранилище. Приложение не сможет доступ ваша камера без этой. Необязательное разрешение: получение текущего местоположения для предложения категорий OK Места поблизости @@ -250,6 +251,7 @@ Ошибка! Ссылка не найдена Номинировать к удалению Этот файл был вынесен на удаление. + Просмотреть в браузере Местоположение не изменено. Местоположение недоступно. @@ -265,7 +267,7 @@ ВИКИДАННЫЕ ВИКИПЕДИЯ ВИКИСКЛАД - * + <u>Оцените нас</u> <u>Часто задаваемые вопросы</u> Пропустить руководство Интернет недоступен diff --git a/app/src/main/res/values-sd/strings.xml b/app/src/main/res/values-sd/strings.xml index 405f40831..3ccc39dd3 100644 --- a/app/src/main/res/values-sd/strings.xml +++ b/app/src/main/res/values-sd/strings.xml @@ -132,7 +132,7 @@ ڪا تشريح ناھي اڻڄاتل لائسنس تازو ڪريو - گھربل اجازت: خارجي اسٽوريج پڙھڻ. ايپ ھن کانسواءِ فنڪشن نٿي ڪري سگھي. + گھربل اجازت: خارجي اسٽوريج پڙھڻ. ايپ ھن کانسواءِ فنڪشن نٿي ڪري سگھي. چونڊ اجازت: زمرن جي تجويزن لاءِ ھاڻوڪي مڪانيت وٺو ٺيڪ ويجھڙائيءَ ۾ جڳھون diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index dc9de3fc5..d1d1d5d87 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -122,6 +122,7 @@ وکی پیڈیا عام <u>عام طور تے پچھے ونڄݨ آلے سوال</u> + <u>ترجمہ کرو</u> زباناں اڳوں تے تھیوو منسوخ diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 8511187ae..9dc68faba 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -160,8 +160,8 @@ Нема описа Непозната лиценца Освежи - Потребна дозвола: читање спољашње меморије. \nАпликација не може да функционише без овога. - Потребна дозвола: писање у спољашњој меморији. \nАпликација не може да функционише без овога. + Потребна дозвола: читање спољашње меморије. \nАпликација не може да функционише без овога. + Потребна дозвола: писање у спољашњој меморији. \nАпликација не може да функционише без овога. Необавезна дозвола: преузми тренутну локацију за предлоге категорија У реду Места у близини diff --git a/app/src/main/res/values-su/strings.xml b/app/src/main/res/values-su/strings.xml index 73627197d..b2604eefd 100644 --- a/app/src/main/res/values-su/strings.xml +++ b/app/src/main/res/values-su/strings.xml @@ -139,8 +139,8 @@ Tanpa pedaran Lisénsi teu dipikanyaho Segerkeun - Merlukeun widi: Baca simpenan éksternal. Aplikasi teu bisa jalan tanpa ieu. - Merlukeun widi: Baca simpenan éksternal. Aplikasi teu bisa jalan tanpa ieu. + Merlukeun widi: Baca simpenan éksternal. Aplikasi teu bisa jalan tanpa ieu. + Merlukeun widi: Baca simpenan éksternal. Aplikasi teu bisa jalan tanpa ieu. Idin pilihan: Paké lokasi kiwari pikeun usulan kategori Oké Tempat Sabudeureun diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 3ea0635ed..7bd06b140 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -160,8 +160,8 @@ Ingen beskrivning Okänd licens Uppdatera - Nödvändig behörighet: Läsa extern lagring. Appen fungerar inte utan detta. - Nödvändig behörighet: Skriva till extern lagring. Appen kan inte fungera så här. + Nödvändig behörighet: Läsa extern lagring. Appen fungerar inte utan detta. + Nödvändig behörighet: Skriva till extern lagring. Appen kan inte fungera så här. Valfri behörighet: Hämta aktuell plats för kategoriförslag OK Platser i närheten diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index e86ec44f8..c471b6369 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -112,8 +112,8 @@ ไม่มีคำอธิบาย สัญญาอนุญาตที่ไม่รู้จัก รีเฟรช - สิทธิที่ต้องการ: อ่านที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ - สิทธิที่ต้องการ: เขียนที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ + สิทธิที่ต้องการ: อ่านที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ + สิทธิที่ต้องการ: เขียนที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ สิทธิทางเลือก: รับข้อมูลตำแหน่งที่ตั้งปัจจุบันสำหรับข้อเสนอแนะหมวดหมู่ ตกลง สถานที่ใกล้เคียง diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d373c859e..94d383ff9 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -161,8 +161,8 @@ Açıklama yok Bilinmeyen lisans Yenile - Gerekli izinler: Harici depolama biriminin okunması. Uygulama buna izin verilmeden çalışmaz. - Gerekli izin: Harici depolama birimi üzerine yazma. Uygulama buna izin verilmeden çalışmaz. + Gerekli izinler: Harici depolama biriminin okunması. Uygulama buna izin verilmeden çalışmaz. + Gerekli izin: Harici depolama birimi üzerine yazma. Uygulama buna izin verilmeden çalışmaz. İsteğe bağlı izin: Kategori önerileri için geçerli konum alma Tamam Yakındaki yerler diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 8f39e04c5..6d236a588 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -170,8 +170,8 @@ Немає опису Невідома ліцензія Оновити - Обов\'язковий дозвіл: читання зовнішньої пам\'яті. Програма не може працювати без цього. - Обов\'язковий дозвіл: записування на зовнішнє сховище. Програма не може працювати без цього. + Обов\'язковий дозвіл: читання зовнішньої пам\'яті. Програма не може працювати без цього. + Обов\'язковий дозвіл: записування на зовнішнє сховище. Програма не може працювати без цього. Додатковий дозвіл: отримувати поточне розташування для підказок категорій Гаразд Місця поблизу diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 915376b3f..4cff15064 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -130,8 +130,8 @@ Không miêu tả Giấy phép không rõ Làm tươi - Yêu cầu cấp phép: Đọc thiết bị lưu trữ bên ngoài. Ứng dụng cần được phép đọc thiết bị lưu trữ bên ngoài để hoạt động. - Yêu cầu cấp phép: Ghi vào thiết bị lưu trữ bên ngoài. Ứng dụng cần được phép ghi vào thiết bị lưu trữ bên ngoài để hoạt động. + Yêu cầu cấp phép: Đọc thiết bị lưu trữ bên ngoài. Ứng dụng cần được phép đọc thiết bị lưu trữ bên ngoài để hoạt động. + Yêu cầu cấp phép: Ghi vào thiết bị lưu trữ bên ngoài. Ứng dụng cần được phép ghi vào thiết bị lưu trữ bên ngoài để hoạt động. Tùy chọn cấp phép: Định vị hiện tại để nhận gợi ý thể loại OK Nơi Lân cận diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index c715f9375..a0af7d8de 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -163,8 +163,8 @@ 無說明 不明授權 重新整理 - 必要權限:讀取外部存儲裝置。應用程式必須此功能,才能進行正確運作。 - 必要權限:寫入外部存儲裝置。應用程式必須此功能,才能進行正確運作。 + 必要權限:讀取外部存儲裝置。否則應用程式無法存取您的圖庫。 + 必要權限:寫入外部存儲裝置。否則應用程式無法取用您的相機。 可有可無的權限:獲取目前的地理位置,以用於分類建議 附近地點 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 274ec92c8..1ff3c4496 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -161,8 +161,8 @@ 没有说明 未知许可协议 刷新 - 需要权限:读取外部存储。应用不能在没有它的情况下运行。 - 需要权限:写入外部存储。应用不能在没有它的情况下运行。 + 需要权限:读取外部存储。应用不能在没有它的情况下访问您的图册。 + 需要权限:写入外部存储。应用不能在没有它的情况下访问您的图册。 可选权限:获取当前位置以提供分类建议 确定 附近地点 From 482b06ccf0fcab29b48a49867a895582178d0a69 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Wed, 11 Apr 2018 12:40:13 +0300 Subject: [PATCH 018/184] Hot fix connectivity leak (#1432) * Fixed bug #1399 * Changed visibility from visible to gone * Changed behaviour according to review * Changed bottom sheet visibility from visible to gone * Fix memory leak causing usage of activity as context --- app/src/main/java/fr/free/nrw/commons/utils/NetworkUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/utils/NetworkUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/NetworkUtils.java index e934e53e5..b9da22e6e 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/NetworkUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/NetworkUtils.java @@ -9,7 +9,7 @@ public class NetworkUtils { public static boolean isInternetConnectionEstablished(Context context) { ConnectivityManager cm = - (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + (ConnectivityManager)context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return activeNetwork != null && From 7b150f78a82088cfc321110654037f7a375d4f05 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 12 Apr 2018 09:10:26 +0200 Subject: [PATCH 019/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-el/strings.xml | 8 ++++---- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-is/strings.xml | 26 ++++++++++++++++++++++--- app/src/main/res/values-ko/strings.xml | 9 ++++++++- app/src/main/res/values-mr/strings.xml | 3 ++- app/src/main/res/values-nb/strings.xml | 4 ++++ app/src/main/res/values-pms/strings.xml | 18 +++++++++++++---- app/src/main/res/values-pt/strings.xml | 4 ++-- app/src/main/res/values-qq/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 4 ++-- app/src/main/res/values-sr/strings.xml | 3 ++- app/src/main/res/values-sv/strings.xml | 5 +++-- app/src/main/res/values-uk/strings.xml | 5 +++-- app/src/main/res/values-zh/strings.xml | 4 ++-- 14 files changed, 73 insertions(+), 28 deletions(-) diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 505856316..d98f093dc 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -163,8 +163,8 @@ Καμία περιγραφή Άγνωστη άδεια Ανανέωση - Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να λειτουργήσει χωρίς αυτή. - Απαιτούμενη άδεια: Με εξωτερική αποθήκευση.Το πρόγραμμα δεν μπορεί να λειτουργήσει με αυτήν. + Απαιτούμενη άδεια: Ανάγνωση εξωτερικής αποθήκευσης. Η εφαρμογή δεν μπορεί να έχει πρόσβαση στην συλλογή σας χωρίς αυτή. + Απαιτούμενη άδεια: Με εξωτερική αποθήκευση. Το πρόγραμμα δεν μπορεί να έχει πρόσβαση στην κάμερα σας χωρίς αυτήν. Προαιρετική άδεια: Ανάκτηση τρέχουσας θέσης σας για προτάσεις κατηγοριών Εντάξει Κοντινοί Τόποι @@ -255,14 +255,14 @@ Βικιδεδομένα Βικιπαίδεια Κοινά - + <u>Βαθμολογήστε μας</u> <u>Συχνές ερωτήσεις</u> Παράβλεψη εισαγωγής Το διαδίκτυο δεν είναι διαθέσιμο Το διαδίκτυο είναι διαθέσιμο Σφάλμα κατά την συγκέντρωση ειδοποιήσεων Δεν βρέθηκαν ειδοποιήσεις - + <u>Μεταφράστε</u> Γλώσσες Επιλέξτε την γλώσσα που θα θέλατε να υποβάλετε μεταφράσεις για αυτή Συνέχεια diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0a2f1e3be..d5e587330 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -246,7 +246,7 @@ Erreur! URL non trouvée Proposer pour suppression Cette image a été citée pour suppression. - + Afficher dans le navigateur L\'emplacement n\'a pas changé. Emplacement non disponible. @@ -262,7 +262,7 @@ WIKIDATA WIKIPÉDIA COMMUNS - + <u>Votre appréciation</u> <u>FAQ</u> Sauter le tutoriel Internet indisponible diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 45c327170..3985a654b 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -62,6 +62,7 @@ Leita í flokkum Vista Endurlesa + Listi GPS er óvirkt í tækinu þínu. Viltu virkja það? Virkja GPS Engar innsendingar ennþá @@ -154,8 +155,8 @@ Engin lýsing Óþekkt notkunarleyfi Endurlesa - Nauðsynlegar heimildir: Lesa ytri gagnageymslu. Forritið virkar ekki án þess. - Nauðsynlegar heimildir: Skrifa í ytri gagnageymslu. Forritið virkar ekki án þess. + Nauðsynlegar heimildir: Lesa ytri gagnageymslu. Forritið fær ekki aðgang að myndasafni ekki án þessa. + Nauðsynlegar heimildir: Skrifa í ytri gagnageymslu. Forritið nær ekki sambandi við myndavél ekki án þessa. Nauðsynlegar heimildir: Lesa núverandi staðsetningu til að geta stungið upp á flokkum Í lagi Staðir í nágrenninu @@ -214,6 +215,7 @@ engin lýsing fannst Síða Commons-skrár Wikidata-atriði + Wikipedia-grein Villa kom upp í skyndiminni mynda Einstakur og lýsandi titill, sem mun verða skráarheiti. Þú mátt nota einfaldan texta með bilum. Ekki hafa með neina skráarendingu Lýstu gögnunum eins vel og auðið er: Hvar er myndin tekin? Hvað sýnir hún? Hvert er samhengið? Lýstu fólki og fyrirbærum. Gefðu upp þær upplýsingar sem ekki er auðvelt að giska á, til dæmis á hvaða tíma dags myndin er tekin ef hún sýnir landslag. Ef gögnin sýna eitthvað óvenjulegt, útskýrðu þá hvað það er sem sé sérstakt. @@ -227,6 +229,9 @@ Senda atvikaskrá til forritaranna með tölvupósti Gat ekki ræst vefvafra til að opna slóð Villa: Slóð fannst ekki + Tilnefna til eyðingar + Þessi mynd hefur verið valin til eyðingar. + Skoða í vafra Staðsetning hefur ekki breyst. Staðsetning ekki tiltæk. Heimild þarf til að birta lista yfir staði í nágrenninu @@ -237,6 +242,21 @@ Takk fyrir að hafa gert breytingar %1$s minntist á þig á %2$s. Víxla sýn - Algengar spurningar + STEFNUR + WIKIDATA + WIKIPEDIA + COMMONS + <u>Gefðu okkur einkunn</u> + <u>Algengar spurningar</u> Sleppa kennslu + Nettenging ekki tiltæk + Nettenging í boði + Villa við að sækja tilkynningar + Engar tilkynningar fundust + <u>Þýða</u> + Tungumál + Veldu tungumálið sem þú vill senda inn þýðingar fyrir + Halda áfram + Hætta við + Reyna aftur diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 52f69aabb..573ca9933 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -92,7 +92,7 @@ 가입하기 정보 위키미디어 공용 앱은 오픈 소스 애플리케이션이며 위키미디어 공동체 내의 자원봉사자에 의해 유지됩니다. 위키미디어 재단은 애플리케이션의 생성, 개발, 유지보수에 관여하지 않습니다. - 소스 코드는 <a href=\"https://github.com/commons-app/apps-android-commons\">GitHub</a>에 있으며, 웹사이트는 <a href=\"https://commons-app.github.io/\">GitHub</a>에 있습니다. 버그나 기타 제안은 <a href=\" https://github.com/commons-app/apps-android-commons/issues\">GitHub</a>에 보고해주세요. + 버그나 기타 제안은 <a href=\" https://github.com/commons-app/apps-android-commons/issues\">GitHub</a>에 보고해주세요. <u>개인정보 정책</u> <u>제작진</u> 정보 @@ -146,6 +146,9 @@ 사유 앱의 스크린샷 업로드 예시: - 제목: 시드니 오페라 하우스\n- 설명: 항만 건너편에서 바라본 시드니 오페라 하우스\n- 분류: 시드니 오페라 하우스, 서쪽에서 본 시드니 오페라 하우스, 시드니 오페라 하우스 원경 + 제목: 시드니 오페라 하우스 + 설명: 강 건너에서 바라본 시드니 오페라 하우스 + 분류: Sydney Opera House from the west, Sydney Opera House remote views 당신의 그림을 기여하세요. 위키백과 문서의 생명이 오는 데 도와주세요! 위키백과의 그림은 위키미디어 공용에서 옵니다. 당신의 그림은 전 세계 사람들을 교육하는 데 도움이 됩니다. @@ -187,6 +190,8 @@ 정말 로그아웃하시겠습니까? 공용 로고 공용 웹사이트 + 공용 페이스북 페이지 + 공용 GitHub 소스 코드 배경 그림 미디어 그림 실패 그림이 없습니다 @@ -219,6 +224,8 @@ 위키백과 문서 그림 캐시 처리 오류 이 파일을 설명할 수 있는 제목으로, 파일 이름으로 사용됩니다. 띄어쓰기를 포함한 일반적인 단어를 사용할 수 있습니다. 파일 확장자는 포함하지 마세요 + 사진이 너무 어둡습니다. 정말 업로드하겠습니까? 위키미디어 공용은 사전적인 가치가 있는 사진을 위한 공간입니다. + 사진이 흐릿합니다. 정말 업로드하겠습니까? 위키미디어 공용은 사전적인 가치가 있는 사진을 위한 공간입니다. 권한 부여 외부 저장소 사용하기 장치의 인앱 카메라로 찍은 사진 저장하기 diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml index 09eaafbc9..b88e021e7 100644 --- a/app/src/main/res/values-mr/strings.xml +++ b/app/src/main/res/values-mr/strings.xml @@ -1,5 +1,6 @@ - Commons spadly + Aplikace Commons spadla Něco se pokazilo! Řekněte nám, co jste dělali a dejte nám to vědět e-mailem. Pomůže sjednat nápravu! Děkujeme vám! diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 6ea1f55bd..454517c16 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -9,6 +9,7 @@ * Leanes * Matěj Suchánek * Mormegil +* Patriccck * Spotter * Vojtěch Dostál * Walter Klosse @@ -73,6 +74,7 @@ Hledání kategorií Uložit Obnovit + Seznam GPS ve vašem zařízení není povoleno. Chtěli byste ho spustit? Spustit GPS Žádné nahrané soubory @@ -165,8 +167,8 @@ Bez popisu Neznámá licence Obnovit - Požadováno oprávnění ke čtení externího úložiště. Aplikace bez toho nemůže pracovat. - Požadováno oprávnění k zápisu do externího úložiště. Aplikace bez toho nemůže pracovat. + Požadované oprávnění: Čtení externího úložiště. Aplikace bez toho nemůže pracovat. + Požadované oprávnění: Zapisování do externího úložiště. Aplikace bez toho nemůže pracovat. Volitelně: Umožněte aplikaci, aby získávala aktuální polohu a nabízela na jejím základě kategorie OK Místa v okolí @@ -225,6 +227,7 @@ nebyl nalezen žádný popisek Stránka souboru na Commons Položka Wikidat + Článek na Wikipedii Chyba při meziukládání obrázků Unikátní a popisný název pro daný soubor, který bude sloužit jako název souboru. Můžete použít běžný psaný jazyk s mezerami; nezahrnujte koncovku souboru. Popište prosím obrázek, jak jen to je možné: Kde byl pořízen? Co znázorňuje? Jaký je kontext obrázku? Popisujte prosím významné předměty nebo osoby na obrázku a nezapomeňte na informace, které není možné snadno odhadnout ze samotného obrázku, jako je například denní doba, pokud jde o krajinu. Pokud je na obrázku něco neobvyklého, popište, co to dělá neobvyklým. @@ -240,6 +243,7 @@ Chyba! URL nenalezeno Navrhnout na smazání Tento obrázek byl nominován na smazání. + . Zobrazit v prohlížeči Vaše umístění se nezměnilo. Umístění není dostupné. @@ -251,11 +255,21 @@ Děkujeme za vaši editaci %1$s vás zmínil na %2$s. Přepnout pohled + POKYNY + WIKIDATA + WIKIPEDIE + COMMONS <u>Ohodnoť nás</u> <u>Často kladené otázky</u> Přeskočit úvod Internet je nedostupný Internet je dostupný + Při načítání oznámení došlo k chybě + Nebyly nalezeny žádné oznámení <u>Přeložit</u> + Jazyky + Vyberte jazyk, pro který chcete odeslat překlady + Pokračovat + Zrušit Zkusit znovu From 35a7d4959043bd7b440a847be8cdc5810f192ba9 Mon Sep 17 00:00:00 2001 From: kamilya35231 <35804101+kamilya35231@users.noreply.github.com> Date: Mon, 16 Apr 2018 17:37:04 +0600 Subject: [PATCH 021/184] Fix for #1437 :Button that opens Google Maps shows always only the coordinates of the first chosen mark (#1446) --- .../main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 354dbd8ee..c8c656faa 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -666,7 +666,7 @@ public class NearbyMapFragment extends DaggerFragment { directionsButton.setOnClickListener(view -> { //Open map app at given position - Intent mapIntent = new Intent(Intent.ACTION_VIEW, place.location.getGmmIntentUri()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, this.place.location.getGmmIntentUri()); if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) { startActivity(mapIntent); } From 9a3b6fc964199626c68681f73dba74ea94ae54bf Mon Sep 17 00:00:00 2001 From: Gabriela Radu <527144+gabrielaradu@users.noreply.github.com> Date: Mon, 16 Apr 2018 15:03:24 +0300 Subject: [PATCH 022/184] Deletion button being disabled (#1403) * used CDATA * Improvements in Notification Activity (#1374) * Improvements in Notification Activity * Update NotificationActivity.java * Share feature (#1338) * added share app feature in About * added share app feature in About * a small fix * Use custom tabs for nearby web views (#1347) * Localisation updates from https://translatewiki.net. * Fix for issue #1380 Improved Notification UI (#1387) * Links added to TextView about_upload_to in aboutActivity (#1326) * Added the link in about_upload_to textfield * Merge conflicts resolved * Removed the extra textView * Fix re-enabling delete button if the action is canceled. * Keep delete button enabled until a reason is given. --- .../fr/free/nrw/commons/AboutActivity.java | 38 ++++++++++++++ .../commons/media/MediaDetailFragment.java | 15 +++++- .../nrw/commons/nearby/NearbyMapFragment.java | 4 +- .../nrw/commons/nearby/PlaceRenderer.java | 4 +- .../notification/NotificationActivity.java | 21 +++++++- .../notification/NotificationRenderer.java | 4 +- app/src/main/res/drawable-mdpi/share.png | Bin 0 -> 9576 bytes .../main/res/drawable/ic_share_black_24dp.xml | 5 ++ app/src/main/res/layout/activity_about.xml | 17 ++----- app/src/main/res/layout/item_notification.xml | 1 + app/src/main/res/layout/toolbar.xml | 1 + app/src/main/res/menu/menu_about.xml | 15 ++++++ app/src/main/res/values-ast/strings.xml | 2 +- app/src/main/res/values-bn/strings.xml | 12 ++++- app/src/main/res/values-ca/strings.xml | 2 +- app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values-da/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 15 +++++- app/src/main/res/values-diq/strings.xml | 2 +- app/src/main/res/values-el/strings.xml | 13 ++++- app/src/main/res/values-es/strings.xml | 22 +++++++- app/src/main/res/values-fi/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 17 ++++++- app/src/main/res/values-gl/strings.xml | 43 ++++++++++++++-- app/src/main/res/values-hi/strings.xml | 4 ++ app/src/main/res/values-is/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 12 ++++- app/src/main/res/values-iw/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 18 ++++++- app/src/main/res/values-ku/strings.xml | 2 +- app/src/main/res/values-lb/strings.xml | 20 +++++++- app/src/main/res/values-lv/strings.xml | 3 ++ app/src/main/res/values-mk/strings.xml | 14 ++++- app/src/main/res/values-mr/strings.xml | 2 +- app/src/main/res/values-nb/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 26 ++++++++-- app/src/main/res/values-oc/strings.xml | 9 ++++ app/src/main/res/values-pl/strings.xml | 7 ++- app/src/main/res/values-pms/strings.xml | 10 +++- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-pt/strings.xml | 48 ++++++++++++++++-- app/src/main/res/values-qq/strings.xml | 6 +++ app/src/main/res/values-ru/strings.xml | 12 ++++- app/src/main/res/values-skr/strings.xml | 10 ++++ app/src/main/res/values-sr/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 20 +++++++- app/src/main/res/values-uk/strings.xml | 22 ++++++++ app/src/main/res/values-zh-rTW/strings.xml | 15 +++++- app/src/main/res/values-zh/strings.xml | 20 +++++++- app/src/main/res/values/strings.xml | 15 +++--- 50 files changed, 488 insertions(+), 76 deletions(-) create mode 100644 app/src/main/res/drawable-mdpi/share.png create mode 100644 app/src/main/res/drawable/ic_share_black_24dp.xml create mode 100644 app/src/main/res/menu/menu_about.xml diff --git a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java index ecf4c21f0..e6bf34736 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java @@ -6,11 +6,15 @@ import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.text.Html; import android.text.SpannableString; import android.text.style.UnderlineSpan; import android.util.Log; import android.support.customtabs.CustomTabsIntent; import android.support.v4.content.ContextCompat; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.LinearLayout; @@ -62,6 +66,18 @@ public class AboutActivity extends NavigationBaseActivity { content.setSpan(new UnderlineSpan(), 0, content.length(), 0); faqText.setText(content); versionText.setText(BuildConfig.VERSION_NAME); + TextView rate_us = findViewById(R.id.about_rate_us); + TextView privacy_policy = findViewById(R.id.about_privacy_policy); + TextView translate = findViewById(R.id.about_translate); + TextView credits = findViewById(R.id.about_credits); + TextView faq = findViewById(R.id.about_faq); + + rate_us.setText(Html.fromHtml(getString(R.string.about_rate_us))); + privacy_policy.setText(Html.fromHtml(getString(R.string.about_privacy_policy))); + translate.setText(Html.fromHtml(getString(R.string.about_translate))); + credits.setText(Html.fromHtml(getString(R.string.about_credits))); + faq.setText(Html.fromHtml(getString(R.string.about_faq))); + initDrawer(); } @@ -108,6 +124,28 @@ public class AboutActivity extends NavigationBaseActivity { Utils.handleWebUrl(this,Uri.parse("https://github.com/commons-app/apps-android-commons/wiki/Frequently-Asked-Questions\\")); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_about, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.share_app_icon: + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, "http://play.google.com/store/apps/details?id=fr.free.nrw.commons"); + sendIntent.setType("text/plain"); + startActivity(Intent.createChooser(sendIntent, "Share app via...")); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + @OnClick(R.id.about_translate) public void launchTranslate(View view) { final ArrayAdapter languageAdapter = new ArrayAdapter(AboutActivity.this, diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index b06869e8d..f522fdd3a 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -304,9 +304,10 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); } if (delete.getVisibility() == View.VISIBLE) { + enableDeleteButton(true); + delete.setOnClickListener(v -> { - delete.setEnabled(false); - delete.setTextColor(getResources().getColor(R.color.deleteButtonLight)); + AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); alert.setMessage("Why should this file be deleted?"); final EditText input = new EditText(getActivity()); @@ -317,6 +318,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { String reason = input.getText().toString(); DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); deleteTask.execute(); + enableDeleteButton(false); } }); alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @@ -358,6 +360,15 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { } } + private void enableDeleteButton(boolean visibility) { + delete.setEnabled(visibility); + if(visibility) { + delete.setTextColor(getResources().getColor(R.color.primaryTextColor)); + } else { + delete.setTextColor(getResources().getColor(R.color.deleteButtonLight)); + } + } + private void rebuildCatList() { categoryContainer.removeAllViews(); // @fixme add the category items diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 3affb2605..a2ce12444 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -53,6 +53,7 @@ import javax.inject.Named; import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.utils.UriDeserializer; import fr.free.nrw.commons.utils.ViewUtil; @@ -747,8 +748,7 @@ public class NearbyMapFragment extends DaggerFragment { } private void openWebView(Uri link) { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, link); - startActivity(browserIntent); + Utils.handleWebUrl(getContext(), link); } private void animateFAB(boolean isFabOpen) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java index 5216dc36d..9cbe28db4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java @@ -27,6 +27,7 @@ import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.di.ApplicationlessInjection; import timber.log.Timber; @@ -200,8 +201,7 @@ public class PlaceRenderer extends Renderer { } private void openWebView(Uri link) { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, link); - view.getContext().startActivity(browserIntent); + Utils.handleWebUrl(getContext(), link); } private boolean showMenu() { diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java index 7c01a44b8..dc52f198a 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.design.widget.Snackbar; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -15,6 +16,7 @@ import android.widget.RelativeLayout; import com.pedrogomez.renderers.RVRendererAdapter; +import java.lang.ref.WeakReference; import java.util.Collections; import java.util.List; @@ -25,6 +27,7 @@ import butterknife.ButterKnife; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.theme.NavigationBaseActivity; +import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -62,9 +65,23 @@ public class NotificationActivity extends NavigationBaseActivity { recyclerView.setLayoutManager(new LinearLayoutManager(this)); DividerItemDecoration itemDecor = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); recyclerView.addItemDecoration(itemDecor); - addNotifications(); + refresh(); } + private void refresh() { + if (!NetworkUtils.isInternetConnectionEstablished(this)) { + progressBar.setVisibility(View.GONE); + Snackbar.make(relativeLayout , R.string.no_internet, Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.retry, view -> { + refresh(); + }).show(); + }else { + progressBar.setVisibility(View.VISIBLE); + addNotifications(); + } + } + + @SuppressLint("CheckResult") private void addNotifications() { Timber.d("Add notifications"); @@ -124,4 +141,4 @@ public class NotificationActivity extends NavigationBaseActivity { .commit(); mNotificationWorkerFragment.setNotificationList(notificationList); } -} \ No newline at end of file +} diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java index 73dcaf7b5..17a318e74 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java @@ -47,8 +47,8 @@ public class NotificationRenderer extends Renderer { @Override public void render() { Notification notification = getContent(); - StringBuilder str = new StringBuilder(notification.notificationText.trim()); - str.append(" "); + String str = notification.notificationText.trim(); + str = str.concat(" "); title.setText(str); time.setText(notification.date); switch (notification.notificationType) { diff --git a/app/src/main/res/drawable-mdpi/share.png b/app/src/main/res/drawable-mdpi/share.png new file mode 100644 index 0000000000000000000000000000000000000000..17473572e1aa94ffdd7a5de77533a25920bd4df3 GIT binary patch literal 9576 zcmdT~i9eKG*nVbV5Mzs1G}*?IEy`F6WgS9fYq2CuS*K(v#WO98iWplVS|&2GXIG|@ zrG+fIneR;R`+mRgU-~Zk0+2T)yMAZ=YMH#a9)!|brZN{FgnwNL-b6Ok#WjdDAQ~RmON(fgGniNy-`^w6`~j1Y&T6u2PrQG} zRNzfeo~Q(LyyI1AI~pBp1R0^0+6&|WMTIfTgpJ(%*Juh>gAhX<=vz-yIFs`MrChXbEJuLtpzelqISU&S|v(baQm`U(lSo1*| zzJCE4e$Q`eP77*d&b~v z=FGV!6b&CWe56fwiEUGJoFHoSP;_ZGjb3hyCH;!2&K8g3x1+gjlE=4FwC=rs`*Bw~ zzT~c%P5fQ2gE!yx-UKDfZiQAoty-su59@ZczG!*XR&lLIPNQGFY50$FSOp@1tjft{i@m$=o$QHh?ZGM$ z8LcFgW>-Q_SgnU9TwF126YSWHNTV-|2sdmQGBBn74&bkp*E8NX{Xr8V9&C-IT&S_U z-_wrDfE{Ws*wLoGkmr+X%GL)pSZTF0jP=)^5ba^z8>YU0P~+6Jfqw#gZ+JJO^Uu@$ za85wd->@TE8juQ|}+4bhup~CrW0x>R!w9wJ0nI5bw;m_m8_MyK@gJhf@Og7+6 z?fQ+73dGXyj#?{`hK)f71lfY41vt9>W&pImThRm&oc)A}W_5s`+QcEE&>wrG7Xsz1Z~?NRp3tqyJVEx}SAy!f$`H+dNhx&Ip&CW@il%B*q7+I_MRa0s zmB$^8hBY`+FrAiy3i`Cd?bYHpm|g4fH%2Oy1Z;cK-fDF>+0)#*22=>(rsFJ*r*>h} zc*e3PNL;sEm32Ek2}~+Ayt^6YI@R&Xn-)tKN@m(N*@;l zF35g|Drlj&bM_*yxlIKC)&7Z?rvO#&#$T0#{3)H-G#%#^Z$do_6J?G(03m02Rw8u z)u;g8^y%-YM%_PIM8b6Hs++=KZ!7q#Fu$@D7#F3Oc7B1;Y2lG*3s)kRFFqxu)gzBc zNik>s4Loii9~Wc97i$wO=H4wbjHn($r1iO7fbUWhxy%VIM)`CNDgfXrInIyThH>Iw zbnLz}rCA4nI_hnV#gR8~sDZU!Bm30BGV32BvqYFgrc>7ew{1Hpan+W8YL?p|A`oU4 zPg+0fD}eoy)&&gHG>kSv#L8D%pOo$&ks3y9Zxm0XH_3>$Y=||~RW!bmdn80?j9&(9 z47YO`RNoafC{LB-61n#tt6d&U6QjJ0y0j93XvdRWeyr+)@g8>^LHQ!ibowd<5$YFh zXl{bd$S;VOoe`TK1P$s>fIa_hQK@eF9G@=U_{t0NZm`P9V3ljFpo)>(o{`dPZJ$II6KQF(U{kbdQ8qb^D z)D?);(`%f)HKEme*DMEj%RWC=x#T84ssmC(?Wfh)T_d1kk(E1*Z3B6m0+)!aK$;1& z)AOwl=Ip4P^W`mdet#p*85Z8}%cy$qnK1;LsD*Ib25h>}q0V~U=Cd}UN=i4F3IA!~k&b?9^#QKwV2(Cr3Dto*3h=GzWf;xJxJ0KhPNFS(kA~U4`f84qxsh)z zORe|+w2dfNyMg2Ax9QhN?ZE+y>6gdup5;@>3Ul^P?yF*^O=!8A?p3Y>2Pcj`#d~qw zoaM#}Y+HQfDyfC`p`;`@fEf!sy&ahJ4qL$$(<0um)$}6Xz3U0{^F(W2?E|NNQaXNZ z27df;YxD|FYTuu;e&IQ0qh4RdQ7-n`^nI9~zZ zt8U==Hzh(9imK*;Tv^TATNF$VG@pLGKg6WKYHP{9XUWQ^XBD_d4(}PW%|E|9RF+kU?|+(C1@p3XFdo4XRka`we6`OGearR?0)@EB?AP%=W*E>$U!IZ8#HnNj8{ zg8GOSL79Q4kA{UC7|0uWK7-;o9iqllBmcq2n63mUXP=>Xq{irfh@DpJ&+0EWVT}?gWoq*1vkYY6z2i~XnZueTP)4%%Yw0vDOZ#>?A~p0| z_rn>lkLvH(JswNI6DFq9ZAPSxlCC9Q0CRyTRD*wv&&Q=OQZJdLaKoa*6CdPn9Hz$X$!wSXc3S#4KMt zIOFuqF6IVCe$46K=wCR06UI@(V8`Fft+mjynx6O<9sm8Aa@2dSkt34zGCgP~<=~L^Mwxg-YhA9O??Ba&Mq2Zj51Ez?xdT^Iq3h+ak)19 z(SiDXANRt7d_k|(1!~W#==|(%!3D87&6EC`hQ&5Es0dUzo-12l8qW8=E4NtP{vBKl zjpO4#1aJ|e6N={yDoJ@2j#t*i=~6c z3lG8DmV#vapY&)Gy8S+`t$PE@#59+yslM!gF2k~FYJPWTqDeA#N9hvd@1`(B%f@AW zj;8;f@Zy=Sb8QAM3KgRbMq4%%I^!nh%XTI~zUajsER8M7Y^JX9F^=u`Z~PQ@V)3Nm zDDtet@|H>^V+ZfB-E35~W+kdhv@^h8?dhBqDH^Xg-*9sZ<^kC zDS!DJ0X2XQr>KXywM_uL|?p(JYCiB+=iPSmnB zUvVt&sqeN$@R5iZh9^lX;QVoo0v z4gLP2z>0Yo5!U2py(IQU>FfoWu=G9!@H`yDlJ&2VFG((v{PMEU`9WxUp9R);>Gd&| zMCfY&-g;yqT1Ua7)-G7r6gu}K>i1*u6t^ftv6|lrb`OrF<9D^2b{1X=JMjHME7JBu zsYQw1`iJ@;-;YO(l>i2QPeh?Yon5w@x+x@Qc>dVx(rc`e$lnq04yu$EP3X&JIAz7i zV4YE4DA~Hq&BR&JranTWpT-%aGNcZF0To|%p#mC+5YYQMi*k#qmRLq`3YjTg2k`FK z!SmVJ&{cQ&my}tF>E#ILZlx0b%?Pjh*VLr1ZES^J8!f)a*6dNk9mZGavM11fV`k@5 zS{Y$_WF4|JIpU-=kuV{^d{?I&zt%kI>;4d07CK=vjsk7>Usr}gOr_)!+c1in2Z3WksvN9mEk?9+AvI4A%|*iPLI zLwHl_WrGXX-z1pnJ@ciRJQaugQ=hf_o(@+tnEjvD?Z>==ATOdx##K$k#%Ohen4Ax~Eq}qP3IV0;;Na^(K%=ZW*B~v&!Y-`og@#19MD!#

S9tEreyZ`v9H1JjfGMu`}Fm1YX<2SIW53|}|0n@?H|be#%9ud^aYg{l(bLfC!{78@+*h;Rk?aCN*8fG1GguuN?694J)uUlmdVE{ zbftpud+RewSdFEft6|nV#E>E{kyzn{(T?|`p*oP=yf^{EY#00Q(B2oIFua`?i|;SN z!O6VHJzfnjb*~T09O6apCx#LDl05LGa1Z!$QwGk0)&yeXjWz)w=?&Ka5b&V&j@gU! zJDKkgULe`Z`V_P0Pun1gxb@-yFc+<ve#t0`1~zTXiC zEb|8iB)@p3C9Veb5Bdh)mtPA1gYk-&g4_Vz(3+0#i-z$>;Y-7cZksm1j{gkT1X(F? z{U*;Q60t7P0{=7*83tkY1zyGI@RjrV*f%O4r3ty7#ISzz28e>?Q9SRwIG#jL)cl1o zB!K<^Z-Zg#v-)HArQr!L-ZPc6`}d4tTM#mr@dT@`Srd%7DKZ@Fg<3t_@r7}3?QdP@%SVTv$M;)xMM7H$8vqq>QT7OyW6cWPdGes^bFgk9KSS0nwpj4RH_S-* zQyllSMkSt*jxS5X!9&u^3&VdF*LxL%SZyq8b9Sd~Wa0DI@bMG(0t?wh)3%^ZYl zIO@SfsSg4cdq2M8k3ASI#v_Zqwe>#fYGY9NN|NzJxEXnHtW1Sz%*5K!dc7UvpMkCT z5{^KcDiggYHR1kjaoZ>MW7{tpQ8;KnPnN3x*4y}~{0zub&W644*fCm6DnyDb&Jkp_ zgPkGU4K}=o_)Yi=U>vIW#hdp(PBEe_d-&(xiq)-HN+kNj7W*G}j^E zmP9@YFmtmd9O|&ZSBm3)j#26%XTBMw#RqA0L?qfT>}YZ$BnilnX)>Rl5@&_2K%06k z4%cccr$(QPj}|+Qi&m{GkH_lCl0AcEiM5{vm`x(6B7}1%Rw=BlFj<^ZNW!Gki((aj z$vyY-C|&Smsk8eWg41~(HQF!1?;42yH`MX_2)3YO#TtwaQ|XK!gHIE~9NFClI>4#h z8X`!@aka&UG&;cuS$Sjw+{jEH-c2`qx7kS6D0_L!I2DH=UOR&E`&7<{Z4;z0ij&(y zD4wV*6uC-e1wmiL!{Eq|PmGOCsrnW%s6zg3WrN2wH;|ehtdY4cwCc;&FL~cCu6g*q zzyowS#)Ga(%Y2Hpn4VGElGy`nQv1YEY!e1#2b#HD2jygg(mT& z^gaYQ5F;W!S{XQtxMgUgyAj>UAfBgr5i6m$H}{d~S#aEwC8{23n>xG=5!aKgl%nCG z0w>{|AoE)erEv##ZHhGF1o_{yi7qel6y^9X|8}53vD>Qx$&1e#GjpFe#RP2@YT43I zhTN3r<3OoEnU;MrvvYMRf|fG4e&J`vkfE*Vae5br9)2qlng~0ijp@cjk96+hy8qq+{Rw|$5Y z?smt^4AusrdZvH4N4!4LmYOMA1a15KrBvl)l@b9$ z!D?pOQoc319IV5Tg~(b}Z*Q59WWgRyYKyTxS0hzvTDhYtWU`JK;4fKrf+^#N){|`% z;&Iw-*^`kl29AR_wT*ubYjY~5nXrX?rChSluu0^;^OFTF@>g%1pF#62<@C8y%A_^?oQd9nIn*O=`1s565ww3)hb0(%o=;6O>h9Dib1%C4R!zoob;uUZaewRc z8qC`_CWkYYalN_)4NKswMh72$MQ_37N>62l% zk^iZQU2V0VUtaM&wtLley)gftd!G2sZ!xa3*uB15{OcQ*g{vm^x#ox{Z!tQWtl0OY z@q}!I)|_UP!LQb~Tpv;KyW8An$Reos4mAmL5f3I&YA)~TPQ**HjxF_%udQOpZ>Nv= zo3&4BkKLFt-rSJ2I=w%u2^BjBm*2n$B(g8bSgMtn&LlTH2BZD=A$I^(8MIa!E#xLyJ%y6m|YPc@*boR;{rV5WC`Aw**%En7g z3$QfiCR{1gXxEpSk>@V^7!8=r(a!j_JJo3zfcY)S7Jrftvn#Z1&ZA zeYjI3z9gV%@F*nn>kjudVUqdeyNHzL-+_H&%yK*695pyQ=HKM2||wC zj{l)=QF6KfoiDWcQo^U;x)BOVyf}w(?W~dAYr>_k0-IBccQG2*olYU81Hnng7?x~+ zhd8QnLj%<&E;$m-#~7k5ey%@u+2ucsR;)5yGc!`U6?7U|xs~&htq=tmYK@M=tYT(N zvSY~Na}u2UsiZ9*maD$dcPSF0pA5s~qXCHoXusg3=T^2%CyNb$7<(tX3~@aC+)hd# zzZI_P@f6U)B_>H+ytcyooAGy-T4yoBJy(=PIwzTEe`nz^7!c0a4x(3umQ5=2jf6Wq zQH;A6;8ux9!dWvH1Y4?CQ>A`wCT5`c{#7oEZu95*f|pM~Io%SlVjecYWb=+ z+vK>euIREQNOXFGF$i-N?yjnSc9S5{Rpquanc@m=K@B|pzfoKtZ7P5SWWw4uMXO$m&<&#*IHfBU zfHCjd$&&E@3RV+9n3Stuc+=3L`2f{Ws$@7+$W8KCEiDeCruAUNWGh)}kPS(n> zBA$4YARD`Fj-e2zEL$oYrFQA0#4WmnHe}F+y>0JBd?k4x9Y-JeBi8BUT?O)j+#a@o z7mt#*ud(Fm7fyiT2f~6|?)MrXQq;ZpSM>O!l{f-P;Ez@k%FA$eZ2edGs5!u^xcsm1 zk)jE7cjf=2j&Q*T9YBF1@^KoAJLC#*3KtRtKvy8w`d>}vKsIQsM*rW&j$$mXdHyTV z{83u|lVm1&BFx5LH~%Oo)@JP5-T&!8Y+eR~`LD+q68H`zNdF*x#mn<YyuLGd=)x3YClXApN6u2+2&btdxVl@a_3f#Ej&Fj(Xx!KR! zY&p;gPhqhd$%gDbf5tG4L4k1I2;DA1dGS+BSJ3MQ4u6Fwr`2v;c8nId*O-4^E`is7 zs5waa^v%I^{88}gww~C@p|TaG7}iW_=0~=|4W9l|odn|gq!yKZUk^ru0wf7a__(R?7{j-d~y;r4{Zm>H~xfCQX2@KA)TSs*dA zQ55A2t!Lrr!HK;5`0@dZopPeDv3Kf>QjC5%U;88giy-H!&Z<@J4D&atY#~? zPizJf@gY&p09#Bp%@#I10yL1Rq#wzNZ4BR=HK{8l9Y7()myO5zX;htiF!f2tFTvj| zY2X=89gY`8R3L!T=kn46s(9L-aQ85u0#VK&!wCQN0I(A68uV9C5=ecYiLpEWt9ObA1bs{XT`k6YaN4H(XzBubGKb)Ggx00`ya}i0riSw1F~dRK#q@ zLN>l+dy&|)q2ZKZ?v<-Sdi+vEeSbZH2PF7@~~z6(L=RO zLJ12FG}&-5pof8L74O-(mqJ!lh?j=Z%QCu!tBDOGglj`D6Mn)Kcko040kMp)gjW+A z-vSO3B{QC_sYY}~UB#H8M=j$m$7XW*TI7cwhIu;B=!u)KEfNjqjaF5g=Vl@R4~R)c zB-Snn0i%(d#T-6`tG4crs4YSiBTVbog2DBNTU(jmn1z(A3B#Y)288@Kjh8fJR(S9S zV$$#n!&aRSF_nJ6V + + diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 9551e6e64..60519f591 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -111,7 +111,7 @@ android:layout_marginTop="@dimen/standard_gap" android:gravity="center" android:textColor="@color/primaryColor" - android:text="@string/about_rate_us" /> + /> + /> + /> + /> - - diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml index ce43e4430..8eae8a4d2 100644 --- a/app/src/main/res/layout/item_notification.xml +++ b/app/src/main/res/layout/item_notification.xml @@ -51,5 +51,6 @@ app:colorClickableText="#969494" android:textAppearance="@style/TextAppearance.AppCompat.Body2" tools:text="@string/placeholder_place_name" + android:padding="12dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index c7aac814a..f4e6d7cb4 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -9,4 +9,5 @@ android:minHeight="?attr/actionBarSize" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:background="?attr/colorPrimaryDark"> + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_about.xml b/app/src/main/res/menu/menu_about.xml new file mode 100644 index 000000000..e56fc3af2 --- /dev/null +++ b/app/src/main/res/menu/menu_about.xml @@ -0,0 +1,15 @@ + +

+ + + \ No newline at end of file diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 062b34fe8..e4b68ebb9 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -234,6 +234,6 @@ Gracies por facer una edición %1$s te mentó en %2$s. Alternar vista - Entrugues más frecuentes + Entrugues más frecuentes Saltar el tutorial diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index cbfd8e322..2a0650f0b 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -59,6 +59,7 @@ বিষয়শ্রেণী অনুসন্ধান সংরক্ষণ পুনঃসতেজ + তালিকা GPS আপনার ডিভাইসে অক্ষম করা আছে। আপনি কি এটি সক্ষম করতে চান? GPS সক্রিয় করুন এখনো কোন আপলোড নেই @@ -210,6 +211,7 @@ কোন বিবরণ পাওয়া যায়নি কমন্সে ফাইলের পাতা উইকিউপাত্ত পদ + উইকিপিডিয়া নিবন্ধ ছবি আনার সময় ত্রুটি ফাইলের একটি স্বতন্ত্র বর্ণনামূলক নাম যা ফাইলের নাম হিসাবে কাজ করবে। অাপনি সাধারণ ভাষা ব্যবহার করতে পারেন শূন্যস্থানসহ। ফাইলের এক্সটেনশন যুক্ত করবেন না। যতটা সম্ভব মিডিয়াটি বর্ণনা করুন: এটি কোথায় ধারণ করা হয়েছিল? এটি কি প্রদর্শন করে? এটির প্রসঙ্গ কি? ধারণকৃত বস্তু অথবা ব্যক্তির বর্ণনা করুন। সহজে অনুমান করা যায়না সেরকম তথ্য উদঘাটন করুন, উদাহরণস্বরূপ, যদি ল্যান্ডস্কেপ হয় তাহলে দিবসকালের সময় দিন। @@ -222,6 +224,8 @@ লগ ফাইল পাঠান ইমেইলের মাধ্যমে উন্নয়নকারীর কাছে লগ ফাইল পাঠান ত্রুটি! ইউআরএল পাওয়া যায়নি + অপসারণের জন্য মনোনীত + ব্রাউজারে দেখুন অবস্থান পরিবর্তন হয়নি। অবস্থান উপলব্ধ নয়। কাছাকাছি স্থানসমূহের একটি তালিকা প্রদর্শন করতে অনুমতি প্রয়োজন @@ -231,6 +235,12 @@ %1$s আপনার আলাপ পাতায় একটি বার্তা দিয়েছেন একটি সম্পাদনা করার জন্য আপনাকে ধন্যবাদ %1$s আপনাকে %2$s-এ উল্লেখ করেছেন। - প্রায়শই জিজ্ঞাসিত প্রশ্নসমূহ + দিকনির্দেশ + উইকিউপাত্ত + উইকিপিডিয়া + কমন্স + প্রায়শই জিজ্ঞাসিত প্রশ্নসমূহ টিউটোরিয়াল এড়ান + ইন্টারনেট অনুপলব্ধ + ইন্টারনেট উপলব্ধ diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index dcc406b73..8d643c746 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -181,5 +181,5 @@ LLEGIU L’ARTICLE Gràcies per fer una modificació %1$s us ha mencionat a %2$s. - Preguntes freqüents + Preguntes freqüents diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index f8e24cc7c..b5e05fa4a 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -236,6 +236,6 @@ Děkujeme za vaši editaci %1$s vás zmínil na %2$s. Přepnout pohled - Často kladené dotazy + Často kladené otázky Přeskočit úvod diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 5edafa308..86e83db3d 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -236,6 +236,6 @@ Tak fordi du lavede en redigering %1$s nævnte dig på %2$s. Skift visning - Ofte stillede spørgsmål + Ofte stillede spørgsmål Udelad øvelse diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 0f9e56bd3..ec2d725db 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -227,6 +227,8 @@ Zum Öffnen der URL wurde kein Webbrowser gefunden Fehler! URL nicht gefunden Zur Löschung vorschlagen + Dieses Bild wurde zur Löschung vorgeschlagen. + Im Browser ansehen Der Standort hat sich nicht geändert. Der Standort ist nicht verfügbar. @@ -242,7 +244,16 @@ WIKIDATA WIKIPEDIA COMMONS - - Häufig gestellte Fragen + <u>Bewerte uns</u> + <u>Häufig gestellte Fragen</u> Tutorial überspringen + Internet nicht verfügbar + Internet verfügbar + Fehler beim Abruf der Benachrichtigungen + Keine Benachrichtigungen gefunden + <u>Übersetzen</u> + Sprachen + Wähle die Sprache aus, für die du Übersetzungen durchführen möchtest. + Fortfahren + Abbrechen diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index f8b2e7033..d4a829e9a 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -26,7 +26,7 @@ Barkerdışê mınê peyêni Ratneya - Nêbı + Ebe ser nêkewt %1$d%% temamya Bar beno Galeri ra diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index c01f9ab3a..a6eac073e 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -227,6 +227,8 @@ Δεν βρέθηκε φυλλομετρητής για το άνοιγμα της διευθύνσεως URL Σφάλμα! Η διεύθυνση URL δεν βρέθηκε Προτείνετε για διαγραφή + Αυτή εικόνα έχει προταθεί για διαγραφή. + Προβολή στον περιηγητή Ο εντοπισμός δεν έχει αλλάξει. Ο τόπος δεν είναι διαθέσιμος. @@ -243,6 +245,15 @@ Βικιπαίδεια Κοινά - Συχνές ερωτήσεις + Συχνές ερωτήσεις Παράβλεψη εισαγωγής + Το διαδίκτυο δεν είναι διαθέσιμο + Το διαδίκτυο είναι διαθέσιμο + Σφάλμα κατά την συγκέντρωση ειδοποιήσεων + Δεν βρέθηκαν ειδοποιήσεις + + Γλώσσες + Επιλέξτε την γλώσσα που θα θέλατε να υποβάλετε μεταφράσεις για αυτή + Συνέχεια + Ακύρωση diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ab044505c..9977f3afd 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -59,6 +59,7 @@ Buscar categorías Guardar Actualizar + Lista El GPS está desactivado en tu dispositivo. ¿Quieres activarlo? Activar GPS No hay subidas aún @@ -125,7 +126,7 @@ Wikimedia Commons aloja la mayoría de las imágenes utilizadas en Wikipedia. ¡Tus imágenes ayudan a instruir a personas de todo el mundo! Carga únicamente imágenes capturadas o creadas por ti. - - Objetos naturales (flores, animales, montañas)\n- Objetos útiles (bicicletas, estaciones de tren)\n- Personas famosas (tu alcalde, algún atleta olímpico que conociste) + Objetos naturales (flores, animales, montañas)\n• Objetos útiles (bicicletas, estaciones de tren)\n• Personas famosas (tu alcalde, algún atleta olímpico que conociste) Naturaleza (flores, animales, montañas) Objetos utilitarios (bicicletas, estaciones de tren) Gente famosa (tu regente, algún atleta que hayas conocido…) @@ -138,6 +139,7 @@ - Título: Casa de la Ópera de Sídney\n- Descripción: Casa de la Ópera de Sídney vista desde el otro lado de la bahía\n- Categorías: Casa de la Ópera de Sídney desde el oeste, Vistas a distancia de la Casa de la Ópera de Sídney Título: Ópera de Sídney Descripción: La Ópera de Sídney, vista desde el otro lado de la bahía + Categorías: Ópera de Sídney desde el oeste, Vistas a distancia de la Ópera de Sídney Contribuye con tus imágenes.\n¡Ayuda a que los artículos de Wikipedia tengan vida! Las imágenes en Wikipedia proceden de\nWikimedia Commons. Tus imágenes ayudan a educar a la gente\nalrededor del mundo. @@ -210,6 +212,7 @@ no se encontró ninguna descripción Página del archivo en Commons Elemento de Wikidata + Artículo de Wikipedia Error al almacenar imágenes en la antememoria Un título único descriptivo para el archivo, que servirá como un nombre de archivo. Puede usar un lenguaje claro con espacios. No incluya la extensión del archivo. Por favor, describa el elemento multimedia tanto como sea posible: ¿dónde fue tomado?, ¿qué muestra?, ¿cuál es el contexto? Por favor, describa los objetos o personas. Ofrezca la información que no puede ser inferida tan fácilmente, por ejemplo el momento del día si es un paisaje. Si el medio muestra algo inusual, explique qué lo hace insual. @@ -224,6 +227,7 @@ No se encontró ningún navegador con el que abrir el URL Error: no se encontró el URL Nominar para borrado + Se ha nominado esta imagen para su borrado. Ver en navegador La ubicación no ha cambiado. La ubicación no está disponible. @@ -234,5 +238,19 @@ %1$s dejó un mensaje en tu página de discusión Gracias por realizar una edición %1$s te ha mencionado en %2$s. - Preguntas frecuentes + CÓMO LLEGAR + WIKIDATA + WIKIPEDIA + COMMONS + <u>Preguntas frecuentes</u> + Omitir tutorial + Internet no disponible + Internet disponible + Error al recuperar las notificaciones + No se encontró ninguna notificación + <u>Traducir</u> + Idiomas + Selecciona el idioma en que quieres enviar traducciones + Cancelar + Reintentar diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index e69997922..3ff5c0ff1 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -231,6 +231,6 @@ Kiitos muokkaamisestasi %1$s mainitsi sinut %2$s. Vaihda näkymä - Usein Kysytyt Kysymykset + Usein Kysytyt Kysymykset Ohita opetus diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7003515d8..f4cde4532 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -59,6 +59,7 @@ Rechercher des catégories Enregistrer Rafraîchir + Liste Le GPS est désactivé sur votre appareil. Voulez-vous l’activer ? Activer le GPS Encore aucun téléversement @@ -211,6 +212,7 @@ aucune description trouvée Page des fichiers de Commons Élément de Wikidata + Article Wikipédia Erreur en mettant les images en cache Un titre descriptif unique pour le fichier, qui servira de nom de fichier. Vous pouvez utiliser un langage simple avec des espaces. N’incluez pas l’extension du fichier Veuillez décrire le média autant que possible : Où a-t-il été enregistré ? Que montre-t-il ? Quel est le contexte ? Veuillez décrire les objets ou les personnes. Révélez les informations qui ne peuvent pas être devinées facilement, par exemple l’heure de la journée si c’est un paysage. Si le média montre quelque chose d’inhabituel, veuillez expliquer ce qui le rend exceptionnel. @@ -225,6 +227,7 @@ Pas d\'afficheur web trouvé pour ouvrir l\'URL Erreur! URL non trouvée Proposer pour suppression + Cette image a été citée pour suppression. Afficher dans le navigateur L\'emplacement n\'a pas changé. Emplacement non disponible. @@ -236,7 +239,19 @@ Merci de faire une modification %1$s vous a mentionné sur %2$s . Basculer l’affichage + DIRECTIONS + WIKIDATA + WIKIPÉDIA + COMMUNS - Questions posées fréquemment + FAQ Sauter le tutoriel + Internet indisponible + Internet disponible + Erreur sur recherche des notifications + Pas de notification trouvée + Langues + Sélectionner la langue pour laquelle vous voulez soumettre des traductions + Continuer + Annuler diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 5b5f67f18..e7ec5a5fa 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -1,11 +1,17 @@ + Aparencia + Xeral + Comentarios + Localización Commons + Configuracións Nome de usuario Contrasinal Acceda á súa conta de Commons Beta Acceder ao sistema + Esqueceu o contrasinal? Rexistrarse Accedendo ao sistema Por favor, agarde… @@ -37,6 +43,7 @@ Compartir Mostrar no navegador Título + Por favor, proporcione un título para este ficheiro Descrición Erro ao acceder ao sistema: Fallou a rede Erro ao acceder ao sistema: Comprobe o seu nome de usuario @@ -52,6 +59,7 @@ Procurar categorías Gardar Refrescar + Lista O GPS está desactivado no seu dispositivo. Quere activalo? Activar GPS Aínda non hai subas @@ -77,7 +85,7 @@ A aplicación Wikimedia Commons é unha aplicación de código aberto creada e mantida polos cesionarios e voluntarios da comunidade de Wikimedia. A Fundación Wikimedia non está involucrada na creación, desenvolvemento ou mantemento da aplicación. Crear unha nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia</a> para informar de problemas e suxestións. <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Política de privacidade</a> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> + <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> Acerca de Enviar comentarios (por correo electrónico) Non hai instalado ningún cliente de correo @@ -89,7 +97,7 @@ Esta imaxe quedará baixo a licenza %1$s Publicando esta imaxe, declaro que é da miña obra, que non contén material con dereitos de autor ou selfies e que se adhire ás <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Políticas de Wikimedia Commons</a>. Descargar - Licenza + Licenza por defecto Usar o título ou a descrición anterior Obter automaticamente a localización actual Obter a localización actual para ofrecer suxestións de categoría se a imaxe non está xeolocalizada @@ -118,11 +126,20 @@ Wikimedia Commons alberga a maioría das imaxes usada en Wikipedia. As súas imaxes axudan a educar a persoas de todo o mundoǃ Por favor, suba unicamente imaxes capturadas ou creadas totalmente por vostedeː - - Obxectos naturais (flores, animais, montañas)\n- Obxectos útiles (bicicletas, estacións de tren)\n- Personaxes famosos (o seu alcalde, atletas olímpicos que coñeza) + Obxectos naturais (flores, animais, montañas)\n• Obxectos útiles (bicicletas, estacións de ferrocarril)\n• Persoas famosas (o seu alcalde, atletas olímpicos que coñeza) + Natureza (flores, animais, montañas) + Obxectos útiles (bicicletas, estacións de ferrocarril) + Persoas famosas (o seu alcalde, atletas olímpicos que coñeza) Por favor, NON subaː - Selfies ou imaxes dos seus amigos\n- Imaxes descargadas de Internet\n- Capturas de pantalla de aplicacións con dereitos de autor + Autorretratos ou fotos dos seus amigos + Imaxes descargadas de Internet + Capturas de pantalla de aplicacións privativas Exemplo de subaː - Título: Ópera de Sydney\n- Descrición: A Ópera de Sydney vista dende a baía\n- Categorías: Sydney Opera House from the west, Sydney Opera House remote views + Título: Ópera de Sydney + Descrición: A Ópera de Sydney, vista desde o outro lado da baía + Categorías: Ópera de Sydney desde o oeste, vistas a distancia da Ópera de Sydney Achegue as súas imaxes. Axude a que os artigos da Wikipedia cobren vida! As imaxes da Wikipedia veñen da Wikimedia Commons. As súas imaxes axudan a educar xente de todo o mundo. @@ -195,6 +212,7 @@ non se atopou descrición Páxina do ficheiro en Commons Elemento en Wikidata + Artigo de Wikipedia Erro mentras se gardaban as imaxes na caché Un título único descritivo para o ficheiro, que servirá como un nome de ficheiro. Pode usar unha linguaxe clara con espazos. Non inclúa a extensión do ficheiro Por favor, describa o ficheiro todo o posibleː Onde se gravou? Cal é o contexto? Por favor, describa os obxectos ou persoas. Indique información que non pode ser adiviñada de forma doada, por exemplo, a hora do día se é unha paisaxe. Se o ficheiro amosa algo pouco habitual, por favor, explique que é o que o fai excepcional. @@ -206,6 +224,11 @@ Comezar sesión na súa conta Enviar ficheiro de rexistro Enviar ficheiro de rexistro ós desenvolvedores por correo electrónico + Non se atopou ningún navegador co que abrir a URL + Errorǃ Nos se atopou a URL + Nomear para borrado + Esta imaxe foi nomeada para borrar. + Ver en navegador A localización non cambiou. A localización non está dispoñible. Precísase permiso para amosar unha lista de lugares preto de aquí @@ -216,4 +239,18 @@ Grazas por realizar unha edición %1$s mencionouno en %2$s. Cambiar modo de visualización + COMO CHEGAR + WIKIDATA + WIKIPEDIA + COMMONS + FAQ + Saltar titorial + Internet non dispoñible + Internet dispoñible + Erro ó recuperar as notificacións + Non se atopou ningunha notificación + Linguas + Seleccione a lingua para a que quere enviar as traducións + Proceder + Cancelar diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 869f6b72b..441367caf 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -218,4 +218,8 @@ विकीडाटा विकीपीडिया कॉमन्स + इंटरनेट उपलब्ध नहीं + इंटरनेट उपलब्ध + सूचनाएं लाने में त्रुटि + कोई सूचनाएँ नहीं मिलीं diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index c766bf7b2..d77dc6222 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -234,6 +234,6 @@ Takk fyrir að hafa gert breytingar %1$s minntist á þig á %2$s. Víxla sýn - Algengar spurningar + Algengar spurningar Sleppa kennslu diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b0dcce458..5411ccfe4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -56,6 +56,7 @@ Cerca categorie Salva Aggiorna + Elenco Il GPS è disabilitato nel dispositivo. Vuoi attivarlo? Attiva GPS Non è stato ancora caricato niente @@ -186,9 +187,11 @@ nessuna descrizione trovata Pagina di Commons del file Elemento Wikidata + Voce Wikipedia Dai autorizzazione Accedi alla tua utenza Errore! URL non trovato + Questa immagine è stata proposta per la cancellazione. La posizione non è cambiata. Posizione non disponibile. OTTIENI DIREZIONI @@ -197,5 +200,12 @@ %1$s ti ha lasciato un messaggio nella tua pagina di discussione Grazie per aver fatto una modifica %1$s ti ha menzionato su %2$s. - Domande frequenti + WIKIDATA + WIKIPEDIA + COMMONS + Domande frequenti + Internet non disponibile + Internet disponibile + Lingue + Annulla diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index ed94cdc29..096e94d3f 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -231,6 +231,6 @@ תודה לך על העריכה אוזכרת על ידי %2$s ב{{GRAMMAR:תחילית|%1$s}}. החלפת מצב תצוגה - שאלות נפוצות + שאלות נפוצות לדלג על ההדרכה diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 27c261d3d..ab4e54e4e 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -59,6 +59,7 @@ 분류 검색 저장 새로 고침 + 목록 장치에서 GPS가 꺼져 있습니다. 켜시겠습니까? GPS 사용 아직 올린 항목이 없습니다 @@ -204,6 +205,7 @@ 설명이 없습니다 공용 파일 문서 위키데이터 항목 + 위키백과 문서 그림 캐시 처리 오류 이 파일을 설명할 수 있는 제목으로, 파일 이름으로 사용됩니다. 띄어쓰기를 포함한 일반적인 단어를 사용할 수 있습니다. 파일 확장자는 포함하지 마세요 권한 부여 @@ -214,6 +216,8 @@ 이메일로 개발자에게 로그 파일 보내기 URL을 열기 위한 웹 브라우저를 찾지 못했습니다 오류! URL을 찾을 수 없습니다 + 삭제 신청 + 이 그림은 삭제가 신청되었습니다. 브라우저에서 보기 위치가 변경되지 않았습니다. 위치를 사용할 수 없습니다. @@ -222,6 +226,18 @@ %1$s님이 당신의 사용자 토론 문서에 글을 남겼습니다 편집해 주셔서 감사합니다 %1$s님이 %2$s에서 나를 언급했습니다. - 자주 묻는 질문 + 방향 + 위키데이터 + 위키백과 + 공용 + FAQ 강좌 건너뛰기 + 인터넷 사용 불가 + 인터넷 사용 가능 + 알림 가져오기 오류 + 알림이 없습니다 + 언어 + 번역 제출을 위한 언어를 선택하십시오 + 진행 + 취소 diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml index 9e2ce9c71..884cce8b3 100644 --- a/app/src/main/res/values-ku/strings.xml +++ b/app/src/main/res/values-ku/strings.xml @@ -70,6 +70,6 @@ Paşragihandin Derkeve Destûr bide - Pirsên ku pir têne pirsîn + <u>Pirsên ku pir têne pirsîn</u> Rênîşandanê derbas bike diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index 3a642b8d1..4ee72dd92 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -57,6 +57,7 @@ Kategorie sichen Späicheren Aktualiséieren + Lëscht GPS ass op Ärem Apparat ausgeschalt. Wëllt Dir en aktivéieren? GPS aktivéieren Nach keng eropgeluede Fichieren @@ -132,6 +133,7 @@ Biller déi Dir aus dem Internet erofgelueden hutt Beispill-Upload: - Titel: Sydney Opera House\n- Beschreiwung: Sydney Opera House vun der Bay aus gesinn\n- Kategorien: Sydney Opera House, Sydney Opera House vu Westen, Sydney Opera House vu wäitem + Titel: Oper vu Sydney Beschreiwung:Oper vu Sydney esou wéi ee se vun der Bucht aus gesäit Maacht mat mat Äre Biller. Hëlleft Wikipedia-Artikele méi lieweg ze maachen! Biller op Wikipedia komme vu Wikimedia Commons. @@ -197,6 +199,7 @@ keng Beschreiwung fonnt Commons-Fichierssäit Wikidata-Element + Wikipedia-Artikel Autorisatioun ginn Externe Späicher benotzen Biller späicheren déi mat der in-app Kamera vun Ärem Apparat gemaach goufen @@ -205,6 +208,7 @@ Log-Fichier per E-Mail un d\'Entwéckler schécken Feeler! URL net fonnt Nominéiere fir ze Läschen + Dëst Bild gouf virgeschloe fir geläscht ze ginn. Am Browser weisen De Plaz huet net geännert. Plaz ass net disponibel. @@ -212,5 +216,19 @@ Wëllkomm op Wikimedia Commons, %1$s! Mir si frou datt Dir hei sidd. Merci datt Dir eng Ännerung gemaach hutt %1$s huet Iech op %2$s ernimmt. - Dacks gestallt Froen + RICHTUNGEN + WIKIDATA + WIKIPEDIA + COMMONS + <u>Bewäert eis</u> + <u>FAQ</u> + Internet net disponibel + Internet disponibel + Feeler beim Ofruffe vun den Notifikatiounen + Keng Notifikatioune fonnt + <u>Iwwersetzen</u> + Sproochen + Sicht déi Sprooch eraus Fir déi Dir Iwwersetzunge maache wëllt + Ofbriechen + Nach eng Kéier probéieren diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 5dfd96a47..2c2d28657 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -100,4 +100,7 @@ LASĪT RAKSTU Paldies par labojumu Pārslēgt skatu + Valodas + Turpināt + Atcelt diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 0325dcf80..8236bc7bb 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -227,6 +227,7 @@ Не најдов прелистувач за да ја отворам URL Грешка! Не ја пронајдов URL Предложи за бришење + Сликава е предложена за бришење. Погледај во прелистувач Местоположбата не е сменета. Местоположбата е недостапна. @@ -242,6 +243,17 @@ ВИКИПОДАТОЦИ ВИКИПЕДИЈА РИЗНИЦА - Често поставувани прашања + <u>Оценете нè</u> + <u>ЧПП</u> Прескокни упатство + Нема семрежен пристап + Има семрежен пристап + Грешка при добивањето на известувањата + Не пронајдов известувања + <u>Преведи</u> + Јазици + Изберете за кој јазик сакате да поднесете преводи + Продолжи + Откажи + Пробај пак diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml index 90f8f6a0b..55cb5b496 100644 --- a/app/src/main/res/values-mr/strings.xml +++ b/app/src/main/res/values-mr/strings.xml @@ -235,6 +235,6 @@ %1$s यांनी तुमचा उल्लेख %2$s येथे केला. टॉगल दृश्य - सतत विचारले जाणारे प्रश्न + सतत विचारले जाणारे प्रश्न ट्यूटोरियल वगळा diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index d1499536f..8092e8a57 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -225,5 +225,5 @@ Takk for at du har gjort en redigering %1$s nevnte deg på %2$s. Skift visning - Ofte stilte spørsmål + Ofte stilte spørsmål diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 421a8e8bc..42bac4ecd 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -50,18 +50,19 @@ Categorieën zoeken Opslaan Vernieuwen + Lijst Nog geen uploads - - Nog geen uploads - 1 upload + + \@string/contributions_subtitle_zero + %1$d upload %1$d uploads Bezig met 1 upload Bezig met %1$d uploads - - 1 upload + + %1$d upload %1$d uploads Er zijn geen categorieën met \"%1$s\" gevonden @@ -152,5 +153,20 @@ Instellingen Terugkoppeling Afmelden + Wikipedia-artikel Error tijdens het laden van de afbeeldingen + Nomineer voor Verwijdering + Deze afbeelding is genomineerd voor verwijdering. + Bekijk in Browser + VERWIJZINGEN + WIKIDATA + Vaak gestelde vragen + Geen internet + Internet beschikbaar + Fout bij ophalen berichten. + Geen berichten. + Talen + Selecteer de taal waarvoor u vertalingen wil indienen + Ga door + Annuleren diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml index ee4f65da8..77cc1eba8 100644 --- a/app/src/main/res/values-oc/strings.xml +++ b/app/src/main/res/values-oc/strings.xml @@ -124,4 +124,13 @@ Títol del mèdia Descripcion Venir un bèta-testaire + Aqueste imatge es estat designat per supression + <u>Nos notar</u> + <u>FAQ</u> + Internet pas disponible + Internet disponible + Error en anant cercar las notificacions. + Cap de notificacion trobada. + <u>Revirar</u> + Seleccionatz la lenga dins la quala volriatz sometre de traduccions diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 009c00b9e..18b6254a2 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -80,7 +80,7 @@ Ustawienia Zarejestruj się O aplikacji - Oprogramowanie Open Source, wydane na licencji <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a>. Wikimedia Commons i jego logo są znakami towarowymi Wikimedia Foundation i są wykorzystywane za zgodą Wikimedia Foundation. Nie jesteśmy powiązani z Wikimedia Foundation. + Aplikacja Wikimedia Commons jest oprogramowaniem typu open-source tworzonym i rozwijanym przez stypendystów i wolontariuszy ze społeczności Wikimedii. Fundacja Wikimedia nie bierze udziału w tworzeniu, rozwijaniu ani utrzymywaniu aplikacji. <a href=\"https://github.com/commons-app/apps-android-commons\">Kod źródłowy</a> oraz <a href=\"https://commons-app.github.io/\">strona internetowa</a> na GitHub. Aby zgłosić błąd lub sugestię, utwórz nowe <a href=\"https://github.com/commons-app/apps-android-commons/issues\">zgłoszenie na GitHub</a>. <u>Polityka prywatności</u> <u>Twórcy</u> @@ -195,6 +195,7 @@ Podaj krótką, opisową i unikalną nazwę, która będzie służyła jako nazwa pliku. Możesz używać prostego języka i spacji. Nie dodawaj rozszerzenia pliku. Zaloguj się na swoje konto Błąd! Nie znaleziono adresu URL + Otwórz w przeglądarce Witamy w Wikimedia Commons, %1$s! Cieszymy się, że tu jesteś. Dziękujemy za dokonanie edycji %1$s wspomniał o Tobie w %2$s. @@ -203,6 +204,8 @@ WIKIDANE WIKIPEDIA POWSZECHNE - Najczęściej zadawane pytania + FAQ Pomiń samouczek + Języki + Anuluj diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 9f577aba2..0a444b568 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -59,6 +59,7 @@ Sërché dle categorìe Argistré Agiorné + Lista Ël GPS a l\'é disabilità su sò angign. Veul-lo ativelo? Ativé ël GPS Ancor gnun cariament @@ -211,6 +212,7 @@ gnun-a descrission trovà Pàgina dj\'archivi ëd Comun Element ëd WikiData + Artìcol ëd Wikipedia Eror antramentre ch\'as butavo le plance an memòria local Un tìtol dëscritiv ùnich për l\'archivi, che a servirà com nòm d\'archivi. A peul dovré un lengagi sempi con djë spassi. Ch\'a ancluda pa l\'estension dl\'archivi Për piasì, ch\'a descriva ël mojen mej ch\'a peul: Andoa a l\'é stàit fàit? Për piasì, ch\'a descriva j\'oget o le përson-e. Ch\'a arvela j\'anformassion ch\'a l\'é nen belfé andviné, për esempi l\'ora dël dì, s\'a l\'é un panorama. Si ël mojen a smon cheicòs ëd foravìa, për piasì ch\'a spiega lòn ch\'a lo rend foravìa. @@ -236,6 +238,12 @@ Mersì d\'avèj fàit na modìfica %1$s a l\'ha massionalo su %2$s . Cangé la visualisassion - Chestion frequente + DIRESSION + WIKIDATA + WIKIPEDIA + COMUN + Chestion frequente Sauté lë spiegon + Lenghe + Selessioné la lenga për la qual a veul le tradussion? diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 762e45c0b..76f8c5c9c 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -236,6 +236,6 @@ Obrigado por ter realizado uma edição %1$s fez menção a você em %2$s. Visualização de alternância - Perguntas mais frequentes + Perguntas mais frequentes Pular tutoril diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 954c3f99f..b0d284f92 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,11 +1,17 @@ + Aparência + Geral + Comentários + Localização Wikimedia Commons + Configurações Nome de utilizador(a) Palavra-passe Entre com a sua conta do Commons Beta Iniciar sessão + Esqueceu-se da palavra-passe? Registar-se A iniciar sessão Aguarde, por favor… @@ -37,6 +43,7 @@ Partilhar Ver no navegador Título + Forneça um título para este ficheiro, por favor Descrição Não foi possível iniciar sessão - falha de rede Não foi possível iniciar sessão - verifique o seu nome de utilizador(a) @@ -52,6 +59,7 @@ Pesquisar categorias Gravar Atualizar + Lista O GPS está desativado no seu dispositivo. Gostarias de ativá-lo? Ativar GPS Ainda não foram enviados ficheiros @@ -76,8 +84,8 @@ Sobre A aplicação do Wikimedia Commons é uma aplicação de código aberto criada e mantida por bolseiros e voluntários da comunidade Wikimedia. A Wikimedia Foundation não está envolvida na criação, desenvolvimento ou manutenção da aplicação. Criar uma nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidência no GitHub</a> para reportar erros e sugestões. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Política de privacidade</a> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Créditos</a> + <u>Política de privacidade</u> + <u>Créditos</u> Sobre Enviar comentários (por e-mail) Não foi instalado nenhum cliente de correio eletrónico @@ -89,7 +97,7 @@ Essa imagem será licenciada sob %1$s Ao carregar esta imagem, declaro que esta é a minha própria obra, que não contém material protegido ou selfies, e que adere às <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines/pt\">políticas do Wikimedia Commons</a>. Descarregar - Licença + Licença padrão Usar título/descrição anteriores Obter automaticamente a localização atual Recuperar localização atual para oferecer sugestões da categoria se a imagem não é georreferenciada @@ -118,11 +126,20 @@ Wikimedia Commons armazena a maioria das imagens que são usadas na Wikipédia. As suas imagens ajudam a educar pessoas em todo o mundo! Por favor, carregue apenas imagens tiradas ou criadas exclusivamente por si: - - Objetos naturais (flores, animais, montanhas)\n- Objetos úteis (bicicletas, estações de comboio)\n- Pessoas famosas (o seu presidente da câmara, atletas olímpicos que conheça) + Objetos naturais (flores, animais, montanhas)\n• Objetos úteis (bicicletas, estações de comboio)\n• Pessoas famosas (o seu presidente da câmara, atletas olímpicos que conheça) + Objetos naturais (flores, animais, montanhas) + Objetos úteis (bicicletas, estações de comboio) + Pessoas famosas (o seu presidente da câmara, atletas olímpicos que conheça) Por favor, NÃO carregue: - Autorretratos ou imagens dos seus amigos\n- Imagens descarregadas da Internet\n- Capturas de ecrã de aplicações com direitos de autor + Autorretratos ou fotografias dos seus amigos + As imagens que descarregou da Internet + Capturas de ecrã de aplicações proprietárias Exemplo de carregamento: - Título: Ópera de Sydney\n- Descrição: A Ópera de Sydney vista do outro lado da baía\n- Categorias: Ópera de Sydney vista do ocidente, Vistas à distância da Ópera de Sydney + Título: Ópera de Sydney + Descrição: A Ópera de Sydney vista do outro lado da baía + Categorias: Ópera de Sydney vista do ocidente, vistas à distância da Ópera de Sydney Contribua com as suas imagens. Ajude os artigos da Wikipédia a ganhar vida! As imagens na Wikipédia provêm do Wikimedia Commons. As suas imagens ajudam a educar as pessoas em todo o mundo. @@ -195,6 +212,7 @@ não foi encontrada nenhuma descrição Página do ficheiro no Commons Item do Wikidata + Artigo na Wikipédia Erro ao colocar imagens na cache Um título descritivo exclusivo para o ficheiro, que servirá como um nome de ficheiro. Pode utilizar uma linguagem simples com espaços. Não inclua a extensão do ficheiro Por favor, descreva o ficheiro da melhor forma possível: Onde foi tirado? O que isso mostra? Qual é o contexto? Por favor, descreva os objetos ou as pessoas. Indique as informações que não podem ser facilmente adivinhadas, por exemplo, a hora do dia, se for uma paisagem. Se o ficheiro mostrar algo incomum, explique o que torna incomum. @@ -206,6 +224,11 @@ Inicie sessão na sua conta Enviar ficheiro de registo Enviar o ficheiro de registo aos programadores por correio eletrónico + Não foi encontrado nenhum navegador da Internet para abrir o URL + Erro! Não foi possível encontrar o URL + Nomear para eliminação + Esta imagem foi nomeada para eliminação. + Ver no navegador A localização não foi alterada. A localização não está disponível. É necessária a permissão para mostrar uma lista dos sítios aqui perto @@ -216,4 +239,21 @@ Obrigado por ter realizado uma edição %1$s fez menção a si em %2$s. Alternar modo de visionamento + DIREÇÕES + WIKIDATA + WIKIPÉDIA + COMMONS + <u>Avalie-nos</u> + <u>FAQ</u> + Saltar a explicação + A Internet não está disponível + A Internet está disponível + Erro ao tentar obter as notificações + Não foram encontradas notificações + <u>Traduzir</u> + Línguas + Selecione a língua para a qual quer enviar as traduções + Avançar + Cancelar + Tentar novamente diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index 6312deb40..70e916171 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -50,6 +50,7 @@ This message is followed by a list of the categories.\n{{Identical|Search category}} Hint text on menu item to save selected categories.\n{{Identical|Save}} {{Identical|Refresh}} + {{Identical|List}} {{Identical|Upload}} Message shown to the user when no category matching what they searched for was found. %1$s represents the category name Text explaining to users why and how to add categories to images. Users can also tap this message to skip adding categories. @@ -114,5 +115,10 @@ {{Identical|Upload}} {{Identical|Nearby}} {{Identical|Tutorial}} + \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' + \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' + {{Identical|Language}} + {{Identical|Cancel}} + {{Identical|Retry}} diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1c7c29231..9a6a9b44b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -60,6 +60,7 @@ Выбор категорий Сохранить Обновить + Список GPS отключён в вашем устройстве. Хотите включить его? Включить GPS Загрузок пока нет @@ -215,6 +216,7 @@ описание не найдено Страница файла на Викискладе Элемент Викиданных + Статья Википедии Ошибка при кэшировании картинок Уникальное описание, которое будет сохранено как имя файла. Вы можете использовать естественный язык, разделяя слова пробелами. Пожалуйста, не указывайте расширение файла. Пожалуйста, подробно опишите загружаемый файл: где он был снят? что на нём изображено? каков его контекст? Пожалуйста опишите изображённых персон или объекты. Добавьте информацию, о которой нельзя легко догадаться, например, время суток, когда снимался файл. Если снято что-то необычное, постарайтесь пояснить, что именно в этом необычного. @@ -240,7 +242,15 @@ Спасибо за правку %1$s упомянул вас на %2$s. Переключить режим просмотра + НАПРАВЛЕНИЯ + ВИКИДАННЫЕ + ВИКИПЕДИЯ + ВИКИСКЛАД * - Часто задаваемые вопросы + Часто задаваемые вопросы Пропустить руководство + Языки + Выбрать язык, переводы на который вы хотели бы видеть? + Выполняется + Отмена diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index 5ff73b3fa..a29907afd 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -10,6 +10,7 @@ ورتݨ آلا ناں پاس ورڈ لاگ ان تھیوو + پاسورڈ بھل ڳئے ہو؟ سائن اپ لاگ ان تھیندا پئے انتظار کرو۔۔۔ @@ -45,6 +46,7 @@ قسماں دی ڳول بچاؤ سجرا، تازہ کرو + فہرست جی پی ایس چلاؤ اڄݨ ککھ وی اپ لوڈ نی تھیا قسماں، زمرے @@ -109,7 +111,15 @@ لاگ آؤٹ ٹیٹوریل وکی ڈیٹا آئٹم + وکی پیڈیا دا مضمون اجازت ݙیوو آپݨے کھاتے وچ لاگ ان تھیوو لاگ فائل بھیجو + وکی ڈیٹا + وکی پیڈیا + عام + عام طور تے پچھے ونڄݨ آلے سوال + زباناں + اڳوں تے تھیوو + منسوخ diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 39fc19325..8a4135e2a 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -235,6 +235,6 @@ %1$s Вас је поменуо на страници %2$s. Пребаци приказ - Често постављана питања + Често постављана питања Прескочи туторијал diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index e7b16edca..5c456f9d2 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -59,6 +59,7 @@ Sök kategorier Spara Uppdatera + Lista GPS:en är inaktiverad på denna enhet. Vill du aktivera den? Aktivera GPS Inga uppladdningar ännu @@ -211,6 +212,7 @@ ingen beskrivning hittades Commons-filsida Wikidata-objekt + Wikipedia-artikel Fel uppstod när bilder cachelagras En unik beskrivande titel för filen, som kommer att fungera som ett filnamn. Du kan använda klarspråk med mellanslag. Ta inte med filändelsen Beskriv mediafilen så mycket som möjligt. Var togs den? Vad visar den? Vad är sammanhanget? Beskriv föremålen eller personerna. Ge information som inte kan gissas fram, t.ex. tidpunkten om det är ett landskap. Om mediafilen visar någonting ovanligt, förklara vad som gör den ovanlig. @@ -225,6 +227,8 @@ Ingen webbläsare hittades för att öppna webbadressen Fel! Webbadressen hittades inte Nominera för radering + Denna bild har nominerats för radering. + Visa i webbläsare Platsen har inte ändrats. Platsen är inte tillgänglig. @@ -236,7 +240,21 @@ Tack för att du gjorde en redigering %1$s nämnde dig på %2$s. Växla vy + VÄGBESKRIVNING + WIKIDATA + WIKIPEDIA + COMMONS - Vanliga frågor och svar + <u>Vanliga frågor</u> Hoppa över övning + Uppkopplingen bröts + Uppkopplingen återupprättades + Fel uppstod när aviseringar hämtades + Inga aviseringar hittades + + Språk + Välj språket som du vill skicka in översättningar för + Fortsätt + Avbryt + Försök igen diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index cf5aeede7..42c5dfa6c 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -45,6 +45,7 @@ Поділитися Відкрити у браузері Назва + Будь ласка, вкажіть назву цього файлу Опис Неможливо увійти — збій у мережі Неможливо увійти — будь ласка, перевірте своє ім\'я користувача @@ -60,6 +61,7 @@ Пошук категорій Зберегти Оновити + Список GPS вимкнено на Вашому пристрої. Бажаєте увімкнути його? Увімкнути GPS Ще нема завантажень @@ -133,10 +135,19 @@ Ваші зображення допомагають освіті людей по всьому світу! Будь ласка, завантажуйте зображення, повністю виконані або створені Вами: Природні об\'єкти (квіти, тварини, гори) \n• Корисні об\'єкти (велосипеди, залізничні вокзали) \n• Відомі люди (Ваш мер, олімпійські атлети, яких Ви зустрічали) + Природні об\'єкти (квіти, тварини, гори) + Корисні об\'єкти (велосипеди, залізничні станції) + Відомі люди (ваш мер, спортсмен-олімпієць, якого ви зустріли) Будь ласка, НЕ завантажуйте: u2022 Селфі або фото своїх друзів \nu2022 Зображення, які Ви завантажили з інтернету \nu2022 Скріншоти патентованих програм + Селфі чи фото ваших друзів + Зображення, які ви завантажили з інтернету + Знімки екрану пропрієтарних програм Приклад завантаження: - Назва: Сіднейський оперний театр \n- Опис: Вид на Сіднейський оперний театр з боку бухти \n- Категорії: Sydney Opera House, Sydney Opera House from the west, Sydney Opera House remote views + Назва: Сіднейський оперний театр + Опис: Сіднейський оперний театр, вид через затоку + Категорії: Sydney Opera House from the west, Sydney Opera House remote views Надсилайте Ваші зображення. Допоможіть оживити статті Вікіпедії! Зображення у Вікіпедії надходять з Вікісховища. Ваші зображення допомагають освіті людей у всьому світі. @@ -209,6 +220,7 @@ опис не знайдено Сторінка файлу у Вікісховищі Елемент Вікіданих + Стаття Вікіпедії Помилка кешування зображень Унікальна описова назва файлу. Ви можете використовувати простий текст з пробілами. Не вказуйте розширення файлу Будь ласка, докладно опишіть файл: де його було зроблено? що на ньому зображено? який контекст? Будь ласка, опишіть об\'єкти чи осіб. Додайте інформацію, яку не можна легко здогадатися, наприклад, пору доби для фотографії пейзажу. Якщо зображено щось незвичайне, постарайтеся пояснити, що робить його незвичайним. @@ -220,6 +232,10 @@ Увійдіть у свій обліковий запис Надіслати лог-файл Надіслати лог-файл розробникам електронною поштою + Не знайдено браузера, щоб відкрити посилання + Помилка! Посилання не знайдено + Номінувати на вилучення + Переглянути в браузері Розташування не змінено Місцезнаходження недоступне Потрібний дозвіл для показу списку місць поблизу @@ -230,4 +246,10 @@ Дякуємо за правку %1$s згадав вас на %2$s. Перемкнути режим перегляду + НАПРЯМКИ + ВІКІДАНІ + ВІКІПЕДІЯ + ВІКІСХОВИЩЕ + Часті запитання + Пропустити інструкцію diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index c41f82d81..198ddf74e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -226,7 +226,8 @@ 經由電子郵件寄送日誌檔案給開發人員 找不到可以打開 URL 的網頁瀏覽器 錯誤!查無 URL - 刪除指定 + 提名刪除 + 此圖片已被提名刪除。 於瀏覽器檢視 位置無法更改。 位置無效。 @@ -242,6 +243,16 @@ 維基數據 維基百科 維基共享資源 - 常見問題 + <u>為我們評分</u> + <u>常見問題</u> 跳過敎程 + 網路不可用 + 網路可用 + 索取通知時錯誤 + 查無通知 + <u>翻譯</u> + 語言 + 選擇您想要提交翻譯的語言 + 已進行 + 取消 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index aac4e06cc..271db95c2 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -59,6 +59,7 @@ 搜索分类 保存 刷新 + 列表 您的设备禁用了GPS。您是否要启用它? 启用GPS 尚无上传 @@ -211,6 +212,7 @@ 找不到描述 共享资源文件页面 维基数据项 + 维基百科条目 缓存图片时出错 用于文件的唯一描述性标题,它将作为文件名使用。您可以使用有空格的简明语言。请不要包含文件扩展名 请尽可能详细地描述媒体:拍摄在何地?显示什么?例文是什么?请描述对象或个人。透露一些不易猜想到的信息,例如这幅风景画的具体日期时间。如果媒体显示了一些不寻常的事物,请说明为什么它显得不寻常。 @@ -225,6 +227,7 @@ 找不到可以打开URL的网页浏览器 错误!找不到URL 提交删除 + 此图片已被提交删除。 在浏览器中预览 位置没有更新。 位置不可用。 @@ -236,6 +239,21 @@ 感谢您做出编辑 %1$s在%2$s提到了您。 切换视图 - 常见问题 + 方向 + 维基数据 + 维基百科 + 共享资源 + + <u>常见问题</u> 跳过指导 + 互联网不可用 + 互联网可用 + 检索通知时出错 + 找不到通知 + + 语言 + 选择您希望提交翻译的语言 + 已处理 + 取消 + 重试 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3a57a591a..810ddc65a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -86,8 +86,8 @@ The Wikimedia Commons app is an open-source app created and maintained by grantees and volunteers of the Wikimedia community. The Wikimedia Foundation is not involved in the creation, development, or maintenance of the app. Wikimedia Commons Create a new <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub issue</a> for bug reports and suggestions. - Privacy policy - Credits + Privacy policy]]> + Credits]]> About Send Feedback (via Email) No email client installed @@ -252,20 +252,17 @@ WIKIDATA WIKIPEDIA COMMONS - - Rate us - FAQ + Rate us]]> + FAQ]]> Skip Tutorial - Internet unavailable Internet available Error fetching notifications No notifications found - - Translate + Translate]]> Languages Select the language that you would like to submit translations for Proceed Cancel - + Retry From f8fb9f1ce9acb59b09af3406eed84770ecb59831 Mon Sep 17 00:00:00 2001 From: Balakrishnan S <97balakrishnan@gmail.com> Date: Mon, 16 Apr 2018 18:21:59 +0530 Subject: [PATCH 023/184] fixed typo in nearbyActivity (#1394) --- .../nrw/commons/nearby/NearbyActivity.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 36dee44a9..241cd845e 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -68,7 +68,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp @Inject NearbyController nearbyController; - private LatLng curLatLang; + private LatLng curLatLng; private Bundle bundle; private Disposable placesDisposable; private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed @@ -342,12 +342,12 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp locationManager.registerLocationManager(); LatLng lastLocation = locationManager.getLastLocation(); - if (curLatLang != null && curLatLang.equals(lastLocation)) { //refresh view only if location has changed + if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed return; } - curLatLang = lastLocation; + curLatLng = lastLocation; - if (curLatLang == null) { + if (curLatLng == null) { Timber.d("Skipping update of nearby places as location is unavailable"); return; } @@ -356,7 +356,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) { progressBar.setVisibility(View.VISIBLE); placesDisposable = Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLang)) + .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::populatePlaces); @@ -365,7 +365,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); - String gsonCurLatLng = gson.toJson(curLatLang); + String gsonCurLatLng = gson.toJson(curLatLng); bundle.putString("CurLatLng", gsonCurLatLng); updateMapFragment(true); } @@ -378,7 +378,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); String gsonPlaceList = gson.toJson(placeList); - String gsonCurLatLng = gson.toJson(curLatLang); + String gsonCurLatLng = gson.toJson(curLatLng); String gsonBoundaryCoordinates = gson.toJson(boundaryCoordinates); if (placeList.size() == 0) { @@ -457,20 +457,20 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp NearbyMapFragment nearbyMapFragment = getMapFragment(); - if (nearbyMapFragment != null && curLatLang != null) { + if (nearbyMapFragment != null && curLatLng != null) { hideProgressBar(); // In case it is visible (this happens, not an impossible case) /* * If we are close to nearby places boundaries, we need a significant update to * get new nearby places. Check order is south, north, west, east * */ if (nearbyMapFragment.boundaryCoordinates != null - && (curLatLang.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude() - || curLatLang.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude() - || curLatLang.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude() - || curLatLang.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) { + && (curLatLng.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude() + || curLatLng.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude() + || curLatLng.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude() + || curLatLng.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) { // populate places placesDisposable = Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLang)) + .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::populatePlaces); From d5f3fd58abcdb939d41c642c52cbb3680c2af7ab Mon Sep 17 00:00:00 2001 From: Jatin0312 Date: Mon, 16 Apr 2018 18:30:39 +0530 Subject: [PATCH 024/184] Fixes Issue #1358 Circle page indicator display improved (#1379) * Fixes Issue #1358 Circle page indicator * Build test checking and reformated code --- app/src/main/res/layout/activity_welcome.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml index 6fa7c7847..60e296fd0 100644 --- a/app/src/main/res/layout/activity_welcome.xml +++ b/app/src/main/res/layout/activity_welcome.xml @@ -14,6 +14,7 @@ android:id="@+id/welcomePagerIndicator" android:layout_height="@dimen/half_standard_height" android:layout_width="match_parent" - android:layout_gravity="bottom" /> + android:layout_gravity="bottom" + android:padding="5dp" /> \ No newline at end of file From d3071718b4d57b95567cf6701468af04e30e64ce Mon Sep 17 00:00:00 2001 From: Anubhav Gupta Date: Tue, 17 Apr 2018 18:22:53 +0530 Subject: [PATCH 025/184] Changes made (#1447) --- .../commons/upload/SingleUploadFragment.java | 20 ++++++------------- .../res/layout/fragment_single_upload.xml | 2 ++ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index 0fa98e530..a88d03c03 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -14,7 +14,9 @@ import android.support.annotation.NonNull; import android.support.v4.view.ViewCompat; import android.support.v7.app.AlertDialog; import android.text.Editable; +import android.text.Html; import android.text.TextWatcher; +import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -225,18 +227,6 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { .commit(); } - @OnTouch(R.id.share_license_summary) - boolean showLicence(View view, MotionEvent motionEvent) { - if (motionEvent.getActionMasked() == ACTION_DOWN) { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(licenseUrlFor(license))); - startActivity(intent); - return true; - } else { - return false; - } - } @OnClick(R.id.titleDescButton) void setTitleDescButton() { @@ -294,8 +284,10 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { @SuppressLint("StringFormatInvalid") private void setLicenseSummary(String license) { - licenseSummaryView.setText(getString(R.string.share_license_summary, getString(Utils.licenseNameFor(license)))); - } + String licenseHyperLink = ""+ getString(Utils.licenseNameFor(license)) + "
"; + licenseSummaryView.setMovementMethod(LinkMovementMethod.getInstance()); + licenseSummaryView.setText(Html.fromHtml(getString(R.string.share_license_summary, licenseHyperLink))); + } @Override public void onActivityCreated(Bundle savedInstanceState) { diff --git a/app/src/main/res/layout/fragment_single_upload.xml b/app/src/main/res/layout/fragment_single_upload.xml index a340e0213..7eb2ed38a 100644 --- a/app/src/main/res/layout/fragment_single_upload.xml +++ b/app/src/main/res/layout/fragment_single_upload.xml @@ -74,6 +74,8 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_gap" android:gravity="center" + android:clickable="true" + android:textColorLink="@color/button_blue" android:text="@string/share_license_summary" /> Date: Tue, 17 Apr 2018 09:12:04 -0400 Subject: [PATCH 026/184] Fix for issue #1436 list icon allows user only to show the list, but not to make it disappear (#1443) * Fixed by using a boolean variable "opened" that changes according to the current state of the list. It is false by default when you open the nearby activity. * Fixed by using bottomSheetBehavior.getState() to decide whether to expand or collapse the bottom list. --- .../free/nrw/commons/nearby/NearbyActivity.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index a56cdf791..ea88de341 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -10,17 +10,14 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; - import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; -import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; -import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -31,7 +28,6 @@ import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; - import fr.free.nrw.commons.R; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LocationServiceManager; @@ -39,13 +35,11 @@ import fr.free.nrw.commons.location.LocationUpdateListener; import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.UriSerializer; - import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; - import timber.log.Timber; @@ -136,11 +130,17 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp @Override public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection switch (item.getItemId()) { case R.id.action_display_list: - bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN); - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); + if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_COLLAPSED || bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_HIDDEN){ + bottomSheetBehaviorForDetails.setState(BottomSheetBehavior.STATE_HIDDEN); + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); + }else if(bottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED){ + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } + return true; default: return super.onOptionsItemSelected(item); From 3b129a6ea4d0e52fd6d47dcd44187b4d9a1721b5 Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Wed, 18 Apr 2018 21:30:13 +1000 Subject: [PATCH 027/184] Fix security exception (Nearby places not loading after permissions granted) (#1440) * Update changelog.md * Versioning for v2.7.0 * Add logging to onPermissionsRequestResult * Request location updates onStatusChanged * Copy onResume() actions into onPermissionsRequestResult * Added getLastKnownLocation method and hooked it up to refreshView * Remove unnecessary calls, add more logging * Add check to prevent NPE * Check that curLatLng exists before getting Mapbox instance * Moar logging * Make curLatLang clearer * Not a good hack - put curLatLang into the bundle separately * Add TODO * Rename variables for clarity * Check for Network Provider as well, tidy up getLKL() * Add Javadocs * Remove unnecessary method in onStatusChanged * Add checkGPS comment * Remove unnecessary logs * Add TODO * Call bundle.clear() before inserting CurLatLng --- .../location/LocationServiceManager.java | 20 ++++++++++- .../nrw/commons/nearby/NearbyActivity.java | 36 +++++++++++++------ .../commons/nearby/NearbyListFragment.java | 7 ++-- .../nrw/commons/nearby/NearbyMapFragment.java | 11 ++++-- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java index f9a171461..73ded852f 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java @@ -79,6 +79,23 @@ public class LocationServiceManager implements LocationListener { Manifest.permission.ACCESS_FINE_LOCATION); } + /** + * Gets the last known location in cases where there wasn't time to register a listener + * (e.g. when Location permission just granted) + * @return last known LatLng + */ + public LatLng getLKL() { + if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (lastKL == null) { + lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + } + return LatLng.from(lastKL); + } else { + return null; + } + } + public LatLng getLastLocation() { if (lastLocation == null) { return null; @@ -249,6 +266,7 @@ public class LocationServiceManager implements LocationListener { public enum LocationChangeType{ LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving - LOCATION_NOT_CHANGED + LOCATION_NOT_CHANGED, + PERMISSION_JUST_GRANTED } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 176c45c36..b75d179c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -13,14 +13,12 @@ import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; -import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; -import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -81,6 +79,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private BroadcastReceiver broadcastReceiver; + private LatLng lastKnownLocation; @Override protected void onCreate(Bundle savedInstanceState) { @@ -158,7 +157,11 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp switch (requestCode) { case LOCATION_REQUEST: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); + Timber.d("Location permission granted, refreshing view"); + //Still need to check if GPS is enabled + checkGps(); + lastKnownLocation = locationManager.getLKL(); + refreshView(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED); } else { //If permission not granted, go to page that says Nearby Places cannot be displayed hideProgressBar(); @@ -347,21 +350,33 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp } curLatLang = lastLocation; + if (locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) { + curLatLang = lastKnownLocation; + } + if (curLatLang == null) { Timber.d("Skipping update of nearby places as location is unavailable"); return; } - if (locationChangeType - .equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)) { + if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED) + || locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) { progressBar.setVisibility(View.VISIBLE); + + //TODO: This hack inserts curLatLng before populatePlaces is called (see #1440). Ideally a proper fix should be found + Gson gson = new GsonBuilder() + .registerTypeAdapter(Uri.class, new UriSerializer()) + .create(); + String gsonCurLatLng = gson.toJson(curLatLang); + bundle.clear(); + bundle.putString("CurLatLng", gsonCurLatLng); + placesDisposable = Observable.fromCallable(() -> nearbyController .loadAttractionsFromLocation(curLatLang)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::populatePlaces); - } else if (locationChangeType - .equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { + } else if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); @@ -384,14 +399,14 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp if (placeList.size() == 0) { ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby); } - - bundle.clear(); + bundle.putString("PlaceList", gsonPlaceList); - bundle.putString("CurLatLng", gsonCurLatLng); + //bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("BoundaryCoord", gsonBoundaryCoordinates); // First time to init fragments if (nearbyMapFragment == null) { + Timber.d("Init map fragment for the first time"); lockNearbyView(true); setMapFragment(); setListFragment(); @@ -399,6 +414,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp lockNearbyView(false); } else { // There are fragments, just update the map and list + Timber.d("Map fragment already exists, just update the map and list"); updateMapFragment(false); updateListFragment(); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java index 4a2be8476..1be2a8689 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java @@ -82,8 +82,11 @@ public class NearbyListFragment extends DaggerFragment { } public void updateNearbyListSignificantly() { - adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates), - (RVRendererAdapter) recyclerView.getAdapter()); + try { + adapterFactory.updateAdapterData(getPlaceListFromBundle(bundleForUpdates), (RVRendererAdapter) recyclerView.getAdapter()); + } catch (NullPointerException e) { + Timber.e("Null pointer exception from calling recyclerView.getAdapter()"); + } } private List getPlaceListFromBundle(Bundle bundle) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index a2ce12444..4b0ff5cc3 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -126,6 +126,7 @@ public class NearbyMapFragment extends DaggerFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Timber.d("Nearby map fragment created"); controller = new ContributionController(this); directUpload = new DirectUpload(this, controller); @@ -151,9 +152,11 @@ public class NearbyMapFragment extends DaggerFragment { getActivity()); boundaryCoordinates = gson.fromJson(gsonBoundaryCoordinates, gsonBoundaryCoordinatesType); } - Mapbox.getInstance(getActivity(), - getString(R.string.mapbox_commons_app_token)); - MapboxTelemetry.getInstance().setTelemetryEnabled(false); + if (curLatLng != null) { + Mapbox.getInstance(getActivity(), + getString(R.string.mapbox_commons_app_token)); + MapboxTelemetry.getInstance().setTelemetryEnabled(false); + } setRetainInstance(true); } @@ -161,7 +164,9 @@ public class NearbyMapFragment extends DaggerFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Timber.d("onCreateView called"); if (curLatLng != null) { + Timber.d("curLatLng found, setting up map view..."); setupMapView(savedInstanceState); } From f814d33de77d649ce0b28ecb811874492b9841ca Mon Sep 17 00:00:00 2001 From: Kaartic Sivaraam Date: Wed, 18 Apr 2018 17:12:31 +0530 Subject: [PATCH 028/184] Add CONTRIBUTING file (#879) * docs: add an initial version of commit message/contributors guideline The project has long evolved without a guideline for commit messages and a contributors guideline. This has led to a lot mysteries in the code base. To avoid such mysteries in the code base in the future, add an intial version of the commit message guideline in the form of a contributors guideline. The name 'CONTRIBUTING' is pretty common and also ensures that GitHub (the place where this project currnetly evolves) brings the document to notice to an user trying to create Pull Request. Further, the all caps ensure it catches the eyes of the gazing user. This initial version of guideline is based on the git project's guideline for submitting patches (Documentation/SubmittingPatches). * contributing: remove internal link Markdown doesn't seem to be supporting internal links(fragments) to other parts of the document. So, replace it with normal text to refer to the section. * contributing: fix typo and improve sentence * contributing: add link to related wiki page * contributing: fix typo * contributing: quote section name correectly Only part of the name of a section was quoted thus referring to an inexistent section and making the sentence meaningless. So, quote it completely. * contributing: use plural to refer to wiki pages A change might obsolete "multiple" Wiki pages, which have technical documentation about the app. So, use plural to refer to the wiki pages. * contributing: move the main contributing file to the wiki The document was based on Git project's guidelines for submitting patches (Documentation/SubmittingPatches). As it was licensed under GPLv2 while this porject is licensed under an Apache license a license conflict arose. To solve it move the main document which might be susceptible to license issues to the wiki while keeping a jist of it in the document itself. * contributing: use lenient wording for steps that might be optional It's not possible to write tests for all changes. For example, UI changes. Also, it's not the case that the Wiki pages become stale all the time. So, use lineant wordings for optional steps * contributing: correct grammar in a sentence "documented in" reads better than "documented at" (at least for me). If this is wrong then we can revert it. * contributing: add link to guidelines in the wiki page * contributing: replace 'jist' with 'gist' "Jist is a pronunciation spelling of the word just when spoken with an American Southern accent. Gist is a noun that means a quick summary or the main point of something." I intended to use the latter. So, .. --- CONTRIBUTING.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee7f42e06..0f1feeac7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,19 @@ -Please see our guidelines in the wiki: https://github.com/commons-app/apps-android-commons/wiki/Volunteers-welcome%21 +Thanks for considering to contribute to this project! A few guidelines for +people who want to contribute their code to this software are documented in +[this project's Wiki](https://github.com/commons-app/apps-android-commons/wiki/Contributing-Guidelines). +If you're not sure where to start head on to [this wiki page](https://github.com/commons-app/apps-android-commons/wiki/Volunteers-welcome!). + +Here's a gist of the guidelines, + +# Make separate commits for logically separate changes + +# Describe your changes well in the commit message + +The first line of the commit message should be a short description of what has +changed. It is also good to prefix the first line with "area: " where the "area" +is a filename or identifier for the general area of the code being modified. +The body should provide a meaningful commit message. + +# Write tests for your code (if possible) + +# Make sure the Wiki pages don't become stale by updating them (if needed) From 8b765109ca7611c5cfa67e02d35948259b2db542 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 19 Apr 2018 09:18:13 +0200 Subject: [PATCH 029/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-diq/error.xml | 3 +- app/src/main/res/values-fr/strings.xml | 18 ++--- app/src/main/res/values-hu/strings.xml | 11 +++- app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-qq/strings.xml | 2 + app/src/main/res/values-sr/strings.xml | 3 +- app/src/main/res/values-sv/strings.xml | 8 +-- app/src/main/res/values-th/strings.xml | 91 ++++++++++++++++++++++++-- app/src/main/res/values-uk/strings.xml | 14 +++- 9 files changed, 127 insertions(+), 24 deletions(-) diff --git a/app/src/main/res/values-diq/error.xml b/app/src/main/res/values-diq/error.xml index 9776fc6b2..a9cbfb85a 100644 --- a/app/src/main/res/values-diq/error.xml +++ b/app/src/main/res/values-diq/error.xml @@ -3,10 +3,11 @@ * 1917 Ekim Devrimi * Gorizon * Marmase +* Mirzali --> Commons lığiya Oops. Thebayo nigurweyino! Şıma se kerd bı, marê vacê. Dıma e-posta ra bırışê marê. Ney timar kerdışi de marê beno desteg! - Teşekur kena + Teşekur kenan! diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d5e587330..c4d238466 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -46,8 +46,8 @@ Le téléversement de %1$s a échoué Appuyer pour afficher - %1$d fichier en cours de téléchargement - %1$d fichiers en cours de téléchargement + %1$d fichier en cours de téléversement + %1$d fichiers en cours de téléversement Mes téléversements récents Mis en file d\'attente @@ -83,16 +83,16 @@ Encore aucun téléversement \@string/contributions_subtitle_zero - %1$d téléchargement - %1$d téléchargements + %1$d téléversement + %1$d téléversements - %1$d téléchargement démarré - %1$d téléchargements démarrés + %1$d téléversement démarré + %1$d téléversements démarrés - %1$d téléchargement - %1$d téléchargements + %1$d téléversement + %1$d téléversements Aucune catégorie correspondant à %1$s trouvée Ajoutez des catégories pour rendre vos images plus simples à trouver sur Wikimedia Commons. \nCommencer à ajouter des catégories. @@ -246,7 +246,7 @@ Erreur! URL non trouvée Proposer pour suppression Cette image a été citée pour suppression. - + Afficher dans le navigateur L\'emplacement n\'a pas changé. Emplacement non disponible. diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 82f1e3c96..e17c0991a 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -13,12 +13,16 @@ * ViDam --> + Visszajelzés + Helyszín Commons + Beállítások Felhasználónév Jelszó Jelentkezz be a Commons Béta fiókoddal Bejelentkezés + Elfelejtett jelszó: Regisztráció Belépés… Kérlek várj… @@ -65,6 +69,7 @@ Keresés a kategóriák között Mentés Frissítés + Lista A GPS le van tiltva az eszközén. Szeretné engedélyezni? GPS engedélyezése Még nincsenek feltöltések @@ -102,7 +107,7 @@ Ez a kép %1$s licenc alatt kerül feltöltésre A kép feltöltésével kijelentem, hogy ez a saját munkám és nem tartalmaz jogvédett anyagot, nem szelfi és megfelel a<a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Commons irányelveinek</a>. Letöltés - Licenc + Alapértelmezett licenc Előző cím/leírás használata Automatikusan megkapja a jelenlegi helyet Lekéri a jelenlegi helyet, hogy lehetőség legyen kategóriajavaslatokra a nem földrajzi címkézett képeknél. @@ -136,6 +141,7 @@ - Szelfiket vagy képeket a barátaidról\n- Internetröl letöltött képeket\n- Kereskedelmi alkalmazások képernyőképeit Példa feltöltés: - Cím: Sydney-i Operaház\n- Leírás: A Sydney-i Operaház az öböl túlpartjáról\n- Kategóriák: Sydney Opera House from the west, Sydney Opera House remote views + Cím: Sydney-i Operaház Tedd közzé a képeidet! Segíts életre kelteni a Wikipédia-szócikkeket! A Wikipédián található képek a Wikimédia Commonsből származnak. A képeid segítenek a világ minden táján élő emberek oktatásában. @@ -205,6 +211,7 @@ nincs leírás Commons leírólap Wikidata-elem + Wikipédia-cikk Hiba a képek gyorsítótárazásakor Egy egyedi, leíró cím a fájlnak, ami fájlnévként fog szolgálni. Egyszerű nyelvezetet használhatsz szóközökkel. Ne tedd bele a kiterjesztést. Kérlek a lehető legteljesebb módon írd le a fájlt: hol készült, mit ábrázol, mi a kontextus? Kérlek add meg az objektumokat vagy személyeket a képen, valamint a nehezen kitalálható információkat (például a kép készítésének dátumát, ha az egy tájkép). Amennyiben a média valami szokatlant ábrázol, kérlek fejtsd ki, hogy mi teszi szokatlanná. @@ -214,6 +221,8 @@ Bejelentkezés a fiókodba Naplófájlok küldése Naplófájlok küldése e-mailben a fejlesztőknek + Hiba! URL nem található. + Törlésre jelölés A hely nem változott. A hely nem érhető el. Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 294b2337d..4a455e484 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -240,6 +240,7 @@ Erro! Não foi possível encontrar o URL Nomear para eliminação Esta imagem foi nomeada para eliminação. + Ver no navegador A localização não foi alterada. A localização não está disponível. diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index baffd2a05..bb23e1759 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -127,7 +127,9 @@ {{Identical|Upload}} {{Identical|Nearby}} {{Identical|Tutorial}} + {{Identical|Notification}} \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' + {{Identical|Wikidata}} {{Identical|Wikipedia}} Link text with underline. Link text with underline.\n{{Identical|Translate}} diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 4b30c41ff..925b8a5ce 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -1,6 +1,7 @@ + การแสดงผล + ทั่วไป + คำติชม + ที่ตั้ง คอมมอนส์ + การตั้งค่า ชื่อผู้ใช้ รหัสผ่าน - เข้าสู่ระบบ + ลงชื่อเข้าระบบบัญชีคอมมอนส์บีตาของคุณ + ลงชื่อเข้า + ลืมรหัสผ่านหรือ? สมัครสมาชิก กำลังเข้าสู่ระบบ กรุณารอสักครู่… @@ -38,6 +45,7 @@ แชร์ ดูในเบราว์เซอร์ ชื่อเรื่อง + กรุณาระบุชืิ่อเรื่องของไฟล์นี้ คำอธิบาย ไม่สามารถเข้าสู่ระบบได้ - ความล้มเหลวของเครือข่าย ไม่สามารถเข้าสู่ระบบได้ - กรุณาตรวจสอบชื่อผู้ใช้ของคุณ @@ -53,6 +61,7 @@ ค้นหาหมวดหมู่ บันทึก รีเฟรช + รายการ GPS ถูกปิดใช้งานในอุปกรณ์ของคุณอยู่ คุณต้องการเปิดใช้งานหรือไม่? เปิดใช้งาน GPS ยังไม่มีการอัปโหลด @@ -73,8 +82,8 @@ เกี่ยวกับ แอปวิกิมีเดียคอมมอนส์เป็นแอปโอเพนซอร์สที่สร้างขึ้นและดูแลโดยผู้มีสิทธิและอาสาสมัครของชุมชนวิกิมีเดีย มูลนิธิวิกิมีเดียไม่มีส่วนเกี่ยวข้องในการสร้าง พัฒนา หรือการบำรุงรักษาแอปใดๆ ทั้งสิ้น สร้าง <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub issue</a> ใหม่เพื่อรายงานบั๊กและส่งข้อเสนอแนะ - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">นโยบายความเป็นส่วนตัว</a> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">เครดิต</a> + <u>นโยบายความเป็นส่วนตัว</u> + <u>เครดิต</u> เกี่ยวกับ ส่งคำติชม (ผ่านทางอีเมล) ไม่ได้ติดตั้งไคลเอนต์อีเมล @@ -86,20 +95,49 @@ รูปภาพนี้จะอนุญาตให้ใช้ได้ภายใต้สัญญาอนุญาต %1$s โดยการส่งรูปภาพนี้ ฉันยืนยันว่านี่เป็นงานของฉันเอง ซึ่งไม่ประกอบด้วยเนื้อหาที่ละเมิดลิขสิทธิ์หรือภาพเซลฟี หรืออื่นๆ ตามที่ระบุใน<a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">นโยบายของ Wikimedia Commons</a> ดาวน์โหลด - สัญญาอนุญาต + สัญญาอนุญาตปริยาย ใช้ชื่อเรื่อง/คำอธิบายก่อนหน้านี้ รับข้อมูลตำแหน่งที่ตั้งปัจจุบันโดยอัตโนมัติ ดึงข้อมูลตำแหน่งที่ตั้งปัจจุบันเพื่อรับข้อเสนอแนะเกี่ยวกับหมวดหมู่ถ้ารูปภาพไม่ได้ติดแท็กตำแหน่งที่ตั้งเอาไว้ โหมดกลางคืน ใช้ธีมสีเข้ม + Attribution-ShareAlike 4.0 + Attribution 4.0 + Attribution-ShareAlike 3.0 + Attribution 3.0 + CC0 + CC BY-SA 3.0 + CC BY-SA 3.0 (ออสเตรีย) + CC BY-SA 3.0 (เยอรมนี) + CC BY-SA 3.0 (เอสโตเนีย) + CC BY-SA 3.0 (สเปน) + CC BY-SA 3.0 (โครเอเชีย) + CC BY-SA 3.0 (ลักเซมเบิร์ก) + CC BY-SA 3.0 (เนเธอร์แลนด์) + CC BY-SA 3.0 (นอร์เวย์) + CC BY-SA 3.0 (โปแลนด์) + CC BY-SA 3.0 (โรมาเนีย) + CC BY 3.0 + CC BY-SA 4.0 + CC BY 4.0 + CC Zero วิกิมีเดียคอมมอนส์เก็บรูปภาพทั้งหมดที่ถูกใช้ในวิกิพีเดีย รูปภาพของคุณช่วยให้ความรู้แก่ผู้คนทั่วโลก! โปรดอัปโหลดรูปภาพที่ถ่ายหรือสร้างด้วยตัวคุณเองทั้งหมด: - - วัตถุธรรมชาติ (ดอกไม้ สัตว์ ภูเขา)\n- วัตถุที่สามารถใช้งานได้ (จักรยาน สถานีรถไฟ)\n- บุคคลที่มีชื่อเสียง (นายกเทศมนตรีของคุณ นักกีฬาโอลิมปิกที่คุณรู้จัก) + วัตถุธรรมชาติ (ดอกไม้ สัตว์ ภูเขา)\n• วัตถุที่สามารถใช้งานได้ (จักรยาน สถานีรถไฟ)\n• บุคคลที่มีชื่อเสียง (นายกเทศมนตรีของคุณ นักกีฬาโอลิมปิกที่คุณรู้จัก) + วัตถุธรรมชาติ (ดอกไม้ สัตว์ ภูเขา) + วัตถุที่สามารถใช้งานได้ (จักรยาน สถานีรถไฟ) + บุคคลที่มีชื่อเสียง (นายกเทศมนตรีของคุณ นักกีฬาโอลิมปิกที่คุณรู้จัก) โปรดอย่าอัปโหลด: - ภาพเซลฟีหรือภาพที่มีเพื่อนของคุณ\n- ภาพที่คุณดาวน์โหลดจากอินเทอร์เน็ต\n- ภาพหน้าจอแอปที่เป็นซอฟต์แวร์กรรมสิทธิ์ + ภาพเซลฟีหรือภาพที่มีเพื่อนของคุณ + ภาพที่คุณดาวน์โหลดจากอินเทอร์เน็ต + ภาพหน้าจอแอปที่เป็นซอฟต์แวร์กรรมสิทธิ์ ตัวอย่างการอัปโหลด: - ชื่อเรื่อง: โรงอุปรากรซิดนีย์\n- คำอธิบาย: โรงอุปรากรซิดนีย์เมื่อมองจากบริเวณอ่าวซิดนีย์\n- หมวดหมู่: โรงอุปรากรเมื่อมองจากทิศตะวันตก, ทิวทัศน์โรงอุปรากรซิดนีย์จากระยะไกล + ชื่อเรื่อง: โรงอุปรากรซิดนีย์ + คำอธิบาย: โรงอุปรากรซิดนีย์เมื่อมองจากบริเวณอ่าวซิดนีย์ + หมวดหมู่: โรงอุปรากรเมื่อมองจากทิศตะวันตก, ทิวทัศน์โรงอุปรากรซิดนีย์จากระยะไกล ลงรูปของคุณ ช่วยให้บทความวิกิพีเดียมีชีวิตชีวา! รูปภาพบนวิกิพีเดียมาจากวิกิพีเดียคอมมอนส์ รูปภาพของคุณช่วยให้การศึกษาแก่ผู้คนทั่วโลก @@ -112,8 +150,8 @@ ไม่มีคำอธิบาย สัญญาอนุญาตที่ไม่รู้จัก รีเฟรช - สิทธิที่ต้องการ: อ่านที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ - สิทธิที่ต้องการ: เขียนที่เก็บข้อมูลภายนอก แอปไม่สามารถทำงานได้โดยไม่มีสิทธินี้ + สิทธิที่ต้องการ: อ่านที่เก็บข้อมูลภายนอก แอปไม่สามารถเข้าถึงคลังภาพได้โดยไม่มีสิทธินี้ + สิทธิที่ต้องการ: เขียนที่เก็บข้อมูลภายนอก แอปไม่สามารถเข้าถึงกล้องของคุณได้โดยไม่มีสิทธินี้ สิทธิทางเลือก: รับข้อมูลตำแหน่งที่ตั้งปัจจุบันสำหรับข้อเสนอแนะหมวดหมู่ ตกลง สถานที่ใกล้เคียง @@ -142,14 +180,19 @@ โลโก้คอมมอนส์ เว็บไซต์คอมมอนส์ หน้าเฟซบุ๊กคอมมอนส์ + ซอร์สโค้ดคอมมอนส์บน GitHub ภาพพื้นหลัง + ภาพสื่อล้มเหลว ไม่พบรูปภาพ อัปโหลดรูปภาพ ภูเขาซะโอ ยามา สะพานสายรุ้ง ทิวลิป + ไม่มีภาพเซลฟี + ภาพกรรมสิทธิ์ ยินดีต้อนรับสู่วิกิพีเดีย + ลิขสิทธิ์ต้อนรับ โรงอุปรากรซิดนีย์ ยกเลิก เปิด @@ -165,16 +208,50 @@ การแจ้งเตือน ไม่สามารถแสดงสถานที่ใกล้เคียงได้โดยขาดสิทธิ์การเข้าถึงตำแหน่ง ไม่พบคำอธิบาย + หน้าไฟล์คอมมอนส์ รายการวิกิสนเทศ + บทความวิกิพีเดีย ข้อผิดพลาดขณะแคชภาพ ชื่อเรื่องที่อธิบายลักษณะเฉพาะของไฟล์ ซึ่งจะใช้เป็นชื่อไฟล์ คุณอาจใช้ภาษาธรรมดาที่มีเว้นวรรคก็ได้ อย่ารวมนามสกุลไฟล์ โปรดอธิบายสื่อดังกล่าวให้มากที่สุดเท่าที่จะได้: สื่อนี้ถูกถ่ายที่ไหน? สื่อนี้แสดงถึงอะไร? บริบทคืออะไร? โปรดอธิบายถึงวัตถุหรือบุคคล เปิดเผยข้อมูลที่ไม่อาจคาดเดาได้อย่างง่ายดาย เช่น เวลาที่ถ่าย หากเป็นภาพทิวทัศน์ หากสื่อแสดงถึงสิ่งที่ไม่ธรรมดา โปรดอธิบายว่าอะไรทำให้สื่อดังกล่าวไม่ธรรมดา + ภาพนี้มืดเกินไป คุณแน่ใจหรือว่าคุณต้องการอัปโหลดภาพนี้? วิกิมีเดียคอมมอนส์นั้นมีไว้สำหรับรูปภาพที่มีคุณค่าในทางสารานุกรมเท่านั้น + ภาพนี้มัว คุณแน่ใจหรือว่าคุณต้องการอัปโหลดภาพนี้? วิกิมีเดียคอมมอนส์นั้นมีไว้สำหรับรูปภาพที่มีคุณค่าในทางสารานุกรมเท่านั้น ให้สิทธิ์ ใช้ที่จัดเก็บข้อมูลภายนอก บันทึกรูปภาพที่ถ่ายด้วยกล้องในแอปบนอุปกรณ์ของคุณ ลงชื่อเข้าใช้บัญชีของคุณ ส่งไฟล์ปูม ส่งไฟล์ปูมไปยังนักพัฒนาผ่านทางอีเมล + ไม่พบเว็บเบราว์เซอร์ที่จะเปิด URL + ข้อผิดพลาด! ไม่พบ URL + เสนอการลบ + ภาพนี้ถูกเสนอการลบแล้ว + ดูในเบราว์เซอร์ ไม่ได้เปลี่ยนตำแหน่งที่ตั้ง ตำแหน่งที่ตั้งไม่พร้อมใช้งาน + ต้องการสิทธิเพื่อแสดงรายการสถานที่ใกล้เคียง + สอบถามเส้นทาง + อ่านบทความ + ยินดีต้อนรับสู่วิกิมีเดียคอมมอนส์ %1$s! เราดีใจที่คุณอยู่ที่นี่ + %1$s ส่งสารบนหน้าคุยของคุณ + ขอบคุณที่ร่วมแก้ไข + %1$s ได้กล่าวถึงคุณบน %2$s + สลับมุมมอง + เส้นทาง + วิกิสนเทศ + วิกิพีเดีย + คอมมอนส์ + <u>ให้คะแนนเรา</u> + <u>FAQ</u> + ข้ามบทช่วยสอน + อินเทอร์เน็ตไม่พร้อมใช้งาน + อินเทอร์เน็ตพร้อมใช้งาน + เกิดข้อผิดพลาดในการดึงข้อมูลการแจ้งความ + ไม่พบการแจ้งความ + <u>แปล</u> + ภาษา + เลือกภาษาที่คุณต้องการส่งการแปล + ดำเนินการต่อ + ยกเลิก + ลองใหม่ diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 195b83812..e6650d055 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -171,7 +171,7 @@ Невідома ліцензія Оновити Обов\'язковий дозвіл: читання зовнішньої пам\'яті. Без цього дозволу програма не зможе отримати доступ до вашої галереї. - Обов\'язковий дозвіл: записування на зовнішнє сховище. Програма не може працювати без цього. + Обов\'язковий дозвіл: записування на зовнішнє сховище. Програма не зможе отримати доступ до камери без цього дозволу. Додатковий дозвіл: отримувати поточне розташування для підказок категорій Гаразд Місця поблизу @@ -246,6 +246,7 @@ Помилка! Посилання не знайдено Номінувати на вилучення Цей файл номіновано на вилучення. + Переглянути в браузері Розташування не змінено Місцезнаходження недоступне @@ -261,6 +262,17 @@ ВІКІДАНІ ВІКІПЕДІЯ ВІКІСХОВИЩЕ + <u>Оцініть нас</u> Часті запитання Пропустити інструкцію + Інтернет недоступний + Інтернет доступний + Помилка при отриманні сповіщення + Сповіщень немає + <u>Перекласти</u> + Мови + Виберіть мову, переклади якою ви хочете відправити + Виконується + Скасувати + Повторити From 8b118b309cecf1dcb3d0a28c0d7492c5bbc0da8a Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Thu, 19 Apr 2018 15:22:58 +0530 Subject: [PATCH 030/184] Fix loading issue after upgrade from older version (#1454) --- .../fr/free/nrw/commons/auth/LoginActivity.java | 7 ++++--- .../fr/free/nrw/commons/auth/SessionManager.java | 14 ++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index 256c7e3b3..ef46869c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -19,7 +19,6 @@ import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatDelegate; import android.text.Editable; import android.text.TextWatcher; -import android.util.Log; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; @@ -28,7 +27,6 @@ import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; -import android.widget.Toast; import java.io.IOException; @@ -160,7 +158,10 @@ public class LoginActivity extends AccountAuthenticatorActivity { WelcomeActivity.startYourself(this); prefs.edit().putBoolean("firstrun", false).apply(); } - if (sessionManager.getCurrentAccount() != null) { + + if (sessionManager.getCurrentAccount() != null + && sessionManager.isUserLoggedIn() + && sessionManager.getCachedAuthCookie() != null) { startMainActivity(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java index a7e62c34e..ad9a0bda4 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/SessionManager.java @@ -61,13 +61,11 @@ public class SessionManager { } public String getAuthCookie() { - boolean isLoggedIn = sharedPreferences.getBoolean("isUserLoggedIn", false); - - if (!isLoggedIn) { + if (!isUserLoggedIn()) { Timber.e("User is not logged in"); return null; } else { - String authCookie = sharedPreferences.getString("getAuthCookie", null); + String authCookie = getCachedAuthCookie(); if (authCookie == null) { Timber.e("Auth cookie is null even after login"); } @@ -75,6 +73,14 @@ public class SessionManager { } } + public String getCachedAuthCookie() { + return sharedPreferences.getString("getAuthCookie", null); + } + + public boolean isUserLoggedIn() { + return sharedPreferences.getBoolean("isUserLoggedIn", false); + } + public Completable clearAllAccounts() { AccountManager accountManager = AccountManager.get(context); Account[] allAccounts = accountManager.getAccountsByType(ACCOUNT_TYPE); From 108ca26967a1f7dc0a6fb8c166ada144908697f2 Mon Sep 17 00:00:00 2001 From: kamilya35231 <35804101+kamilya35231@users.noreply.github.com> Date: Mon, 16 Apr 2018 17:37:04 +0600 Subject: [PATCH 031/184] Fix for #1437 :Button that opens Google Maps shows always only the coordinates of the first chosen mark (#1446) --- .../main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 4b0ff5cc3..431132436 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -671,7 +671,7 @@ public class NearbyMapFragment extends DaggerFragment { directionsButton.setOnClickListener(view -> { //Open map app at given position - Intent mapIntent = new Intent(Intent.ACTION_VIEW, place.location.getGmmIntentUri()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, this.place.location.getGmmIntentUri()); if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) { startActivity(mapIntent); } From 533297dce7b591a5021553fdb63e0688a0c258bb Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Fri, 20 Apr 2018 15:28:42 +1000 Subject: [PATCH 032/184] Versioning and changelog for v2.7.1 (#1457) * Versioning * Update changelog.md --- CHANGELOG.md | 6 ++++++ app/build.gradle | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f3dfc30a..7c77174cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Wikimedia Commons for Android +## v2.7.1 +- Fixed UI and permission issues with Nearby +- Fixed issue with My Recent Uploads being empty +- Fixed blank category issue when uploading directly from Nearby +- Various crash fixes + ## v2.7.0 - New Nearby Places UI with direct uploads (and associated category suggestions) - Added two-factor authentication login diff --git a/app/build.gradle b/app/build.gradle index b1ee9aef9..cbdc83468 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -91,8 +91,8 @@ android { defaultConfig { applicationId 'fr.free.nrw.commons' - versionCode 83 - versionName '2.7.0' + versionCode 84 + versionName '2.7.1' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion project.minSdkVersion From 970704334b08941f92a5fd897a7ad32d54fed0af Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 23 Apr 2018 08:51:06 +0200 Subject: [PATCH 033/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ast/strings.xml | 4 +- app/src/main/res/values-bn/strings.xml | 3 + app/src/main/res/values-cs/strings.xml | 6 +- app/src/main/res/values-de/strings.xml | 4 + app/src/main/res/values-el/strings.xml | 4 + app/src/main/res/values-es/strings.xml | 3 + app/src/main/res/values-fr/strings.xml | 4 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-iw/strings.xml | 25 ++++- app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-ji/strings.xml | 3 + app/src/main/res/values-ko/strings.xml | 5 + app/src/main/res/values-lb/strings.xml | 3 + app/src/main/res/values-li/strings.xml | 113 +++++++++++++++++++++ app/src/main/res/values-mk/strings.xml | 4 + app/src/main/res/values-pms/strings.xml | 4 + app/src/main/res/values-pt-rBR/strings.xml | 4 + app/src/main/res/values-pt/strings.xml | 4 + app/src/main/res/values-qq/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 14 ++- app/src/main/res/values-sk/strings.xml | 40 +++++++- app/src/main/res/values-sv/strings.xml | 4 + app/src/main/res/values-th/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 4 + app/src/main/res/values-zh-rTW/strings.xml | 4 + app/src/main/res/values-zh/strings.xml | 4 + 26 files changed, 253 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/values-li/strings.xml diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index a04003e1e..532a4897e 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -155,8 +155,8 @@ Ensin descripción Llicencia desconocida Refrescar - Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. - Permisu riquíu: escritura d\'almacenamientu esternu. L\'aplicación nun puede funcionar ensin él. + Permisu riquíu: llectura d\'almacenamientu esternu. L\'aplicación nun puede entrar na to galería ensin él. + Permisu necesariu: Escritura n\'almacenamientu esternu. L\'aplicación nun puede aportar a la cámara ensin él. Permisu opcional: llograr l\'allugamientu actual pa suxerir categoríes Aceutar Llugares cercanos diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index e308e69a7..679c50803 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -92,6 +92,7 @@ বিষয়শ্রেণীসমূহ সেটিং নিবন্ধন করুন + নির্বাচিত ছবি পরিচিতি উইকিমিডিয়া কমন্স অ্যাপ হচ্ছে একটি উন্মুক্ত উৎস সম্বলিত অ্যাপ যা উইকিমিডিয়া সম্প্রদায়ের ব্যবহারকারী ও সেচ্ছাসেবকবৃন্দ কর্তৃক তৈরিকৃত এবং পরিচালিত। উইকিমিডিয়া ফাউন্ডেশন এই অ্যাপ তৈরি, উন্নয়ন বা রক্ষণাবেক্ষণে জড়িত নয়। কোন সমস্যা ও পরামর্শের জন্য <a href=\"https://github.com/commons-app/apps-android-commons/issues\">গিটহাব ইস্যু</a> তৈরি করুন। @@ -176,6 +177,7 @@ মিডিয়ার শিরোনাম বিবরণ মিডিয়ার বিবরণ এখানে যাবে। এই মোটামুটি দীর্ঘ হতে পারে এবং একাধিক লাইনে লিখতে হতে পারে। আমরা আশা করি এটি দেখতে সুন্দর হবে। + স্রষ্টা আপলোডের তারিখ লাইসেন্স স্থানাঙ্কসমূহ @@ -218,6 +220,7 @@ প্রস্থান ভূমিকা বিজ্ঞপ্তি + নির্বাচিত অবস্থানের অনুমতি ছাড়া কাছাকাছি জায়গাগুলি প্রদর্শন করা যাবে না কোন বিবরণ পাওয়া যায়নি কমন্সে ফাইলের পাতা diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 454517c16..6e2453d6d 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -167,8 +167,8 @@ Bez popisu Neznámá licence Obnovit - Požadované oprávnění: Čtení externího úložiště. Aplikace bez toho nemůže pracovat. - Požadované oprávnění: Zapisování do externího úložiště. Aplikace bez toho nemůže pracovat. + Požadované oprávnění: Čtení externího úložiště. Bez něj nemůže aplikace číst vaši galerii. + Požadované oprávnění: Zapisování do externího úložiště. Bez něj nemůže aplikace používat vaši kameru. Volitelně: Umožněte aplikaci, aby získávala aktuální polohu a nabízela na jejím základě kategorie OK Místa v okolí @@ -243,7 +243,7 @@ Chyba! URL nenalezeno Navrhnout na smazání Tento obrázek byl nominován na smazání. - . + Zobrazit v prohlížeči Vaše umístění se nezměnilo. Umístění není dostupné. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3550010b8..60339308c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -88,6 +88,7 @@ Kategorien Einstellungen Registrieren + Vorgestellte Bilder Über Die Wikimedia-Commons-App ist eine Open-Source-App, entwickelt und gewartet von Freiwilligen der Wikimedia-Gemeinschaft. Die Wikimedia Foundation ist nicht bei der Erstellung, Entwicklung oder Wartung der App beteiligt. Einen neuen <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-Eintrag</a> für Fehlerberichte und Vorschläge erstellen. @@ -173,6 +174,8 @@ Titel des Mediums Beschreibung Hier folgt die Beschreibung des Mediums. Diese kann möglicherweise ziemlich lang sein und erfordert dann einen Umbruch auf mehreren Zeilen. Wir hoffen, dass sie dennoch gut aussieht. + Autor + Hier steht der Benutzername des Autors des vorgestellten Bildes. Hochgeladen am Lizenz Koordinaten @@ -215,6 +218,7 @@ Abmelden Anleitung Benachrichtigungen + Vorgestellt Orte in der Nähe können ohne Berechtigung zur Standortbestimmung nicht ermittelt werden Keine Beschreibung gefunden Commons-Dateiseite diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index d98f093dc..759c44920 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -92,6 +92,7 @@ Κατηγορίες Ρυθμίσεις Εγγραφή + Προβεβλημμένες εικόνες Σχετικά Λογισμικό ανοικτού κωδικού που κυκλοφορεί υπό την <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Άδεια Apache v2</a>. Το Wikimedia Commons και το λογότυπο είναι εμπορικά σήματα του Ιδρύματος Wikimedia και χρησιμοποιούνται με άδεια από το Ίδρυμα Wikimedia. Δεν συμμετέχουμε στην δημιουργία, ανάπτυξη ή συντήρηση του Ιδρύματος Wikimedia. Δημιουργήστε ένα νέο <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub θέμα</a> για αναφορές σφαλμάτων και προτάσεις. @@ -177,6 +178,8 @@ Τίτλος πολυμέσου Περιγραφή Η περιγραφή του πολυμέσου μπαίνει εδώ. Αυτή μπορεί να είναι σχετικά μεγάλη, και θα χρειαστεί να αναδιπλωθεί σε πολλές γραμμές. Ελπίζουμε ωστόσο ότι θα φαίνεται όμορφα. + Συγγραφέας + Το όνομα χρήστη του συγγραφέα της επιλεγμένης εικόνας πάει εδώ. Ημερομηνία φόρτωσης Άδεια Συντεταγμένες @@ -219,6 +222,7 @@ Αποσύνδεση Σεμινάριο Ενημερώσεις + Επιλεγμένο Οι κοντινές τοποθεσίες δεν μπορούν να προβληθούν δίχως τις άδειες τοποθεσίας δεν βρέθηκε περιγραφή Σελίδα φακέλλου κοινής χρήσης diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ff4e246c1..c1a45b309 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -92,6 +92,7 @@ Categorías Ajustes Regístrate + Imágenes en destaque Acerca de La aplicación de código abierto Wikimedia Commons fue creada por, y recibe mantenimiento de, cesionarios y voluntarios de la comunidad de Wikimedia. La Fundación Wikimedia no está involucrada en la creación, el desarrollo ni el mantenimiento de la aplicación. Notifica de problemas y sugerencias en <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub</a>. @@ -177,6 +178,7 @@ Título del multimedia Descripción Aquí va la descripción del archivo multimedia. Esta puede ser muy extensa, en cuyo caso deberá ajustarse en varios renglones. No obstante, esperamos que se vea bien. + Autor Fecha de subida Licencia Coordenadas @@ -219,6 +221,7 @@ Salir Tutorial Notificaciones + En destaque Los sitios cercanos no pueden mostrarse sin los permisos de ubicación no se encontró ninguna descripción Página del archivo en Commons diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c4d238466..8494a7a36 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -99,6 +99,7 @@ Catégories Paramètres S’inscrire + Images en vedette À propos L’application Wikimedia Commons est une application open source créée et tenue à jour par les bénéficiaires et volontaires de la communauté Wikimedia. La fondation Wikimedia n’est pas associée à la création, le développement ou l’entretien de l’application. Créer un nouveau <a href=\"https://github.com/commons-app/apps-android-commons/issues\">signalement GitHub</a> pour signaler des bogues ou des suggestions. @@ -184,6 +185,8 @@ Titre du média Description La description du média vient ici. Cela peut être potentiellement assez long, et devra être réparti sur plusieurs lignes. Nous espérons que cela restera joli néanmoins. + Auteur + Le nom de l’utilisateur auteur d’une image en vedette va ici. Date de téléversement Licence Coordonnées @@ -226,6 +229,7 @@ Déconnexion Tutoriel Notifications + Mis en vedette Les endroits proches ne peuvent pas être affichés si vous ne partagez pas votre position géographique. aucune description trouvée Page des fichiers de Commons diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 379e20449..27968b8d7 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -160,6 +160,7 @@ Titolo Titolo del file multimediale Descrizione + Autore Data di caricamento Licenza Coordinate diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 898778d98..186df118a 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -70,6 +70,7 @@ חיפוש קטגוריות שמירה רענון + רשימה ה־GPS במכשיר שלך אינו מופעל. האם להפעיל אותו? הפעלת GPS לא הועלה עדיין שום דבר @@ -91,6 +92,7 @@ קטגוריות הגדרות רישום + תמונות מומלצות אודות יישום ויקישיתוף (Wikimedia Commons app) הוא יישום קוד פתוח שמפותח ומתוחזק על־ידי מקבלי מלגות ומתנדבים של קהילת ויקימדיה. קרן ויקימדיה אינה מעורבת ביצירה, פיתוח, או תחזוקה של היישום. נא ליצור <a href=\"https://github.com/commons-app/apps-android-commons/issues\">דיווח בגיטהאב</a> בשביל באגים והצעות. @@ -176,6 +178,8 @@ כותרת המדיה תיאור תיאור המדיה יהיה כאן. זה יכול להיות ארוך למדי, ולהתפרס על מספר שורות. אנחנו מקווים שזה נראה טוב. + יוצר + שם המשתמש של יוצר התמונה המומלצת. תאריך העלאה רישיון נקודות ציון @@ -217,6 +221,7 @@ יציאה מדריך הודעות + מומלץ אי־אפשר להציג מקומות בסביבה ללא הרשאות מיקום לא נמצא תיאור דף קובץ בוויקישיתוף @@ -233,6 +238,9 @@ שליחת קובץ יומן שליחת קובץ יומן למפתחים בדואר אלקטרוני לא נמצא דפדפן שיוכל לפתוח את הכתובת + להציע מחיקה + התמונה הזאת מועמדת למחיקה + הצגה בדפדפן המיקום לא השתנה. המיקום אינו זמין. נדרשת הרשאה כדי להציג רשימה של מקומות בסביבה @@ -243,6 +251,21 @@ תודה לך על העריכה אוזכרת על ידי %2$s ב{{GRAMMAR:תחילית|%1$s}}. החלפת מצב תצוגה - שאלות נפוצות + כיוונים + ויקינתונים + ויקיפדיה + ויקישיתוף + <u>תנו לנו ציון</u> + <u>שאלות נפוצות</u> לדלג על ההדרכה + האינטרנט אינו זמין + האינטרנט זמין + שגיאה באחזור התראות + לא נמצאו התראות + <u>תרגום</u> + שפות + נא לבחור את השפה שבה תשלחו את התרגומים + המשך + ביטול + לנסות שוב diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 711987324..e34c98432 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -157,6 +157,7 @@ メディアのタイトル 記述 ここにメディアの説明が入ります。かなり長文になる場合には数行にわたることがあります。それでも見栄えがよいと願っています。 + 作者 アップロード日時 ライセンス 緯度経度 diff --git a/app/src/main/res/values-ji/strings.xml b/app/src/main/res/values-ji/strings.xml index bc3af8a30..9122cc710 100644 --- a/app/src/main/res/values-ji/strings.xml +++ b/app/src/main/res/values-ji/strings.xml @@ -59,6 +59,7 @@
קאַטעגאריעס איינשטעלונגען + רעקאמענדירטע בילדער וועגן וועגן שיקן פֿידבעק (דורך בליצפאסט) @@ -95,6 +96,7 @@ ווארענונג יא ניין + מחבר ליצענץ קאארדינאטן טולפאן @@ -108,4 +110,5 @@ איינשטעלונגען פֿידבעק אַרויסלאָגירן + רעקאמנדירט diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 573ca9933..11faee9c6 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,6 +1,7 @@ + + Uterlik + Algemein + Feedback + Locatie + Commons + + Instèllinge + Gebroekersnaam + Wachwaord + Meld dich aan mit diene Commons-Bètakonto + Melj dich aan + Wachwaord vergaete? + Teiken dich in + Aan \'nt melje... + Wach estebleef... + Aanmelje gelök! + Aanmelje mislök! + Bestandj neet gevónje. Perbeer \'n anger bestandj. + Verificatie mislök! + Upload begós! + %1$s upgeloadj! + Wies aan veur dienen upload te betrachte + Upload van %1$s aan \'nt vange + %1$s up \'nt loade + d\'n Upload van %1$s is vaerdig + d\'n Upload van %1$s is mislök + Wies aan veur te betrachte + + %1$d bestandj up \'nt loade + %1$d bestenj up \'nt loade + + Mien recènte uploads + Inne wachrie + Mislök + %1$d%% vaerdig + Up \'nt loade + Oete gallerie + Trèk foto aaf + Kórtbie + Mien uploads + Deil + Tuin in browser + Titel + Gaef estebleef \'ne naam veur dit bestandj + Besjrieving + Kan zich neet aanmelde - netwirkfout + Kan zich neet aanmelde - controleer de gebroekersnaam + Kan zich neet aanmelde - controleer die wachwaord + Te väöl mislökde kieëre geperbeerd. Perbeer estebleef oppernuuj euver e paar menuut. + Deze gebroeker is geblokkeerd op Commons + Doe mós diene twieëfaktorische bevestigingscode opgaeve. + Aanmelje mislök + Upload + Gaef dees verzameling \'ne naam + Aanpassinge + Upload + Zeuk categorieje + Slaon op + Vernuuj + Lies + GPS steit oet op die toestèl. Wils se \'t aanzètte? + Zèt GPS aan + Nag gein uploads + + \@string/contributions_subtitle_zero + %1$d upload + %1$d uploads + + + Beginnendj mit %1$d upload + Beginnendj mit %1$d uploads + + + %1$d upload + %1$d uploads + + Gein categorieje die euvereinkómme mit %1$s gevónje + Veug categorieje toe veur dien plaetjes mekkeliker te kinne vinje op Wikimedia Commons.\nBegin mit tikke veur categorieje toe te veuge. + Categorieje + Instèllinge + Registreer + Oetgeleechde plaetjes + Euver + Naamsvermeljing-GeliekDeile 4.0 + Naamsvermeljing 4.0 + Naamsvermeljing-GeliekDeile 3.0 + Naamsvermeljing 3.0 + CC0 + CC BY-SA 3.0 + CC BY-SA 3.0 (Oeësteriek) + CC BY-SA 3.0 (Duutsjlandj) + CC BY-SA 3.0 (Eslandj) + CC BY-SA 3.0 (Spaanje) + CC BY-SA 3.0 (Kroatië) + CC BY-SA 3.0 (Luxemburg) + CC BY-SA 3.0 (Nederlandj) + CC BY-SA 3.0 (Noorwaeg) + CC BY-SA 3.0 (Pole) + CC BY-SA 3.0 (Roemenië) + CC BY 3.0 + CC BY-SA 4.0 + CC BY-4.0 + CC Zero + Op Wikimedia Commons staon de meiste plaetjes die waere gebroek op Wikipedia. + Dien plaetjes helpe luuj oppe ganse werreld mit \'t opdoon van kènnis! + Vernuuj + diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 7171f2738..dd1e6f03e 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -84,6 +84,7 @@ Категории Нагодувања Регистрација + Избрани слики За извршникот Прилогот на Ризницата има отворен код. Негови творци и одржувачи се примателите на наменските средства од Викимедиината заедница како и членовите на заедницата. Фондацијата Викимедија нема учество во нејзиното создавање, разработка и одржување. Создајте нов <a href=\"https://github.com/commons-app/apps-android-commons/issues\">проблем на GitHub</a> за пријавување на грешки и давање предлози. @@ -169,6 +170,8 @@ Наслов на податотеката Опис Тука оди описот на податотеката. Ова потенцијално може да биде прилично долго, и ќе треба да се преломи во неколку реда. Се надеваме дека ќе изгледа добро. + Автор + Тука оди корисничкото име на авторот на избраната слика. Датум на подигање Лиценца Координати @@ -211,6 +214,7 @@ Одјава Упатства Известувања + Избрана Местата во близина не можат да се прикажат без дозволи за местоположба. не најдов описи Податотечна страница diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index b5f49a1e2..0cd748031 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -84,6 +84,7 @@ Categorìe Paràmeter Marchesse + Plance an evidensa A propòsit L\'aplicassion Wikimedia Commons a l\'é n\'aplicassion a sorgiss duverta creà e mantnùa da \'d përson-e pagà e da \'d volontari ëd la comunità Wikimedia. La Fondassion Wikimedia a l\'é nen amplicà ant la creassion, ël dësvlup, o la manutension dl\'aplicassion. Creé na neuva <a href=\"https://github.com/commons-app/apps-android-commons/issues\">signalassion GitHub</a> për signalé dij givo e dij sugeriment. @@ -169,6 +170,8 @@ Tìtol dël mojen Descrission La descrission dël mojen a va ambelessì. Sòn a podrìa esse potensialman longh, e a dovrà esse spantià su vàire linie. I speroma comsëssìa ch\'a ven-a grassios. + Autor + Lë stranòm ëd l\'autor ëd na plancia an evidensa a va ambelessì. Dàita ëd cariament Licensa Coordinà @@ -211,6 +214,7 @@ Seurte dal sistema Cors d\'antrodussion Notìfiche + Butà an evidensa Ij pòst ant j\'anviron a peulo nen esse smonù sensa ij përmess ëd localisassion gnun-a descrission trovà Pàgina dj\'archivi ëd Comun diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 067a5329c..4bc478527 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -96,6 +96,7 @@ Categorias Configurações Criar conta + Imagens destacadas Sobre O Wikimedia Commons é um aplicativo de código aberto criado e mantido por beneficiários e voluntários da comunidade Wikimedia. A Wikimedia Foundation não está envolvida na criação, desenvolvimento ou manutenção do aplicativo. Criar uma nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">publicação no GitHub</a> para informar erros e sugestões. @@ -181,6 +182,8 @@ Título da mídia Descrição Descrição da mídia aqui. Isso pode ser potencialmente longo e precisará envolver múltiplas linhas. Esperamos que seja agradável. + Autor + O nome de usuário do autor da imagem destacada fica aqui. Data de envio. Licença Coordenadas @@ -223,6 +226,7 @@ Sair Tutorial Notificações + Destacado Os locais próximos não podem ser exibidos sem permissões de localização Nenhuma descrição encontrada Página de arquivo do Commons diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 4a455e484..5e4862ecb 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -93,6 +93,7 @@ Categorias Configurações Registar-se + Imagens destacadas Sobre A aplicação do Wikimedia Commons é uma aplicação de código aberto criada e mantida por bolseiros e voluntários da comunidade Wikimedia. A Wikimedia Foundation não está envolvida na criação, desenvolvimento ou manutenção da aplicação. Criar uma nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidência no GitHub</a> para reportar erros e sugestões. @@ -178,6 +179,8 @@ Título do ficheiro multimédia Descrição A descrição do ficheiro multimédia é colocada aqui. Ela pode ser bastante longa e precisar de ser dividida em várias linhas. No entanto, esperamos que tenha bom aspeto. + Autor + O nome de utilizador do autor da imagem destacada fica aqui. Data de carregamento Licença Coordenadas @@ -220,6 +223,7 @@ Sair Tutorial Notificações + Destacadas Os sítios aqui perto não podem ser apresentados sem permissões de localização não foi encontrada nenhuma descrição Página do ficheiro no Commons diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index bb23e1759..37c2978bf 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -110,6 +110,7 @@ {{Identical|No}} {{Identical|Title}} {{Identical|Description}} + {{Identical|Author}} {{Identical|License}} {{Identical|Coordinate}} Describes \"coordinates\". diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e382169cd..c649398bb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -104,6 +104,7 @@ Категории Настройки Зарегистрироваться + Избранные изображения О приложении Приложение «Викисклад» - это программа с открытым кодом, которую создали волонтёры и участники грантов Викимедиа. Фонд Викимедиа не участвует в создании, разработке или обслуживании этого приложения. Вы можете создать <a href=\"https://github.com/commons-app/apps-android-commons/issues\">запрос на GitHub</a>, чтобы сообщить об ошибке или внести предложение. @@ -146,7 +147,7 @@ CC BY-SA 4.0 CC BY 4.0 CC Zero - Викисклад содержит большую часть изображений, которые используются в Википедии. + Викисклад содержит бо́льшую часть изображений, которые используются в Википедии. Ваши изображения помогают образованию людей во всём мире! Пожалуйста, загрузите фотографии, которые были сняты или созданы исключительно вами: Природные объекты (например, цветы, животные, горы)\n• Полезные предметы (например, велосипеды, вокзалы)\n• Известные люди (например, ваш мэр, спортсмены-олимпийцы, которых вы встретили) @@ -186,9 +187,11 @@ Да Нет Название - Заголовок носителя информации + Заголовок медиафайла Описание - Здесь располагается описание носителя информации. Оно потенциально может быть весьма длинным и даже располагаться в несколько строк. Однако мы надеемся, что это выглядит симпатично + Здесь располагается описание медиафайла. Оно может быть весьма длинным и даже располагаться в несколько строк. Однако, надеемся, будет выглядеть приемлемо. + Автор + Здесь указывается имя автора избранного изображения Дата загрузки Лицензия Координаты @@ -214,7 +217,7 @@ Ламы Радужный мост Тюльпан - Нет сэлфи + Без селфи Несвободное изображение Добро пожаловать в Википедию Добро пожаловать — авторские права @@ -231,6 +234,7 @@ Выйти Руководство Уведомления + Избранное Места поблизости не могут быть отображены без разрешения на геолокацию описание не найдено Страница файла на Викискладе @@ -276,7 +280,7 @@ Уведомлений нет <u>Перевести</u> Языки - Выберите язык, переводы на который вы хотели бы видеть + Выберите язык локализации, на который сможете перевести элементы интерфейса приложения Выполняется Отмена Повторить diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 20fe02f20..90fac7f16 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -5,11 +5,18 @@ * Sudo77(new) --> + Vzhľad + Všeobecné + Spätná väzba + Poloha Commons + Nastavenia Používateľské meno Heslo + Prihláste sa do svojho účtu Commons Beta Prihlásiť sa + Zabudli ste heslo? Zaregistrovať sa Prihlasovanie Čakajte prosím… @@ -41,6 +48,7 @@ Zdieľať Otvoriť v prehliadači Názov + Prosím, dajte tomuto súboru názov Opis prihlásenie zlyhalo - zlyhanie siete Prihlásenie zlyhalo - skontrolujte vaše používateľské meno @@ -64,7 +72,7 @@ O aplikácii Open Source softvér dostupný za podmienok <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache License v2</a> Zdroj na <a href=\"https://github.com/commons-app/apps-android-commons\">GitHub</a>. Bugy na <a href=\" https://github.com/commons-app/apps-android-commons/issues\">Github</a>. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Zásady ochrany súkromia</a> + <u>Zásady ochrany súkromia</u> O aplikácii Odoslať spätnú väzbu (emailom) Nemáte nainštalovaného žiadneho e-mailového klienta @@ -75,7 +83,7 @@ Zrušiť Tento obrázok bude licencovaný podľa %1$s Stiahnuť - Licencia + Predvolená licencia Použiť predchádzajúci názov/popis Automaticky získať súčasnú polohu Nočný režim @@ -103,11 +111,20 @@ Na Wikimedia Commons sa nachádza väčšina obrázkov, ktoré sa používajú na Wikipédii. Váš obrázok pomáha vzdelávať ľudí po celom svete! Prosím, nahrávajte obrázky, ktoré ste odfotili alebo vytvorili vy: - - Prírodu (kvety, zvieratá, hory)\n- Užitočné objekty (bicykle, železničné stanice)\n- Slávni ľudia (starosta, olympionici, s ktorými ste sa stretli) + Prírodu (kvety, zvieratá, hory)\n• Užitočné objekty (bicykle, železničné stanice)\n• Slávnych ľudí (starosta, olympionici, s ktorými ste sa stretli) + Prírodu (kvety, zvieratá, hory) + Užitočné objekty (bicykle, železničné stanice) + Slávnych ľudí (starosta, olympionici, s ktorými ste sa stretli) Prosím NENAHRÁVAJTE: - Selfies alebo fotky vašich priateľov\n- Obrázky prevzaté z internetu\n- Snímky obrazovky proprietárnych aplikácii + Selfies alebo fotky vašich priateľov + Obrázky prevzaté z internetu + Snímky obrazovky proprietárnych aplikácii Príklad nahratia: - Názov: Opera v Sydney\n- Opis: Opera v Sydney - pohľad spoza zátoky\n- Kategórie: Sydney Opera House from the west, Sydney Opera House remote views + Názov: Opera v Sydney + Popis: Opera v Sydney - pohľad spoza zátoky + Kategórie: Sydney Opera House from the west, Sydney Opera House remote views Prispejte svojimi obrázkami. Pomôžte oživiť články na Wikipédií. Obrázky na Wikipédií pochádzajú z Wikimedia Commons. Vaše obrázky pomáhajú vzdelávať ľudí po celom svete. @@ -130,14 +147,20 @@ Názov Názov média Popis + Autor + Dátum nahrania Licencia Súradnice neposkytnuté Staňte sa beta testerom Naozaj sa chcete odhlásiť? Logo Commons + Webová stránka Commons + Facebooková stránka Commons + Zdrojový kód Commons na Githube Obrázok pozadia Nenašiel sa žiaden obrázok + Nahrať obrázok Hora Zaó Lamy Dúhový most @@ -157,4 +180,15 @@ Návod Upozornenia nenašiel sa žiaden popis + Otvoriť v prehliadači + WIKIÚDAJE + WIKIPÉDIA + COMMONS + <u>Ohodnoťte nás</u> + <u>FAQ</u> + <u>Preložiť</u> + Jazyky + Pokračovať + Zrušiť + Obnoviť diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 542699399..fa5174ced 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -90,6 +90,7 @@ Kategorier Inställningar Registrera + Utvalda bild Om Wikimedia Commons är en app med öppen källkod som skapas och underhålls av frivilliga från Wikimedias gemenskap. Wikimedia Foundation är inte involverad i skapandet, utvecklingen eller underhållet av appen. Skapa ett nytt <a href=\"https://github.com/commons-app/apps-android-commons/issues\">ärende på GitHub</a> för att rapportera buggar och förslag. @@ -175,6 +176,8 @@ Mediatitel Beskrivning Beskrivningen för mediafilen ska vara här. Den kan vara riktig lång och kommer att behöva sträcka sig över flera rader. Vi hoppas i alla fall att det kommer se bra ut. + Skapare + Användarnamnet för den utvalda bildens skapare ska stå här. Uppladdningsdatum Licens Koordinater @@ -217,6 +220,7 @@ Logga ut Guide Meddelanden + Utvald Platser i närheten kan inte visas utan platsbehörigheter ingen beskrivning hittades Commons-filsida diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 0143d93eb..29b29d804 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -164,6 +164,7 @@ ชื่อเรื่องสื่อ คำอธิบาย ป้อนคำอธิบายสื่อที่นี่ คำอธิบายที่มีความยาวมากอาจมีหลายบรรทัด เราหวังว่ามันจะดูดี + ผู้สร้างสรรค์ วันที่อัปโหลด สัญญาอนุญาต พิกัด diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index e6650d055..a4ed20320 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -99,6 +99,7 @@ Категорії Налаштування Зареєструватися + Вибрані зображення Про програму Додаток «Вікісховище» — це програма з відкритим кодом, яку створили отримувачі грантів та волонтери спільноти Вікімедіа. Фонд Вікімедіа не брав участі у створенні, розробці чи обслуговуванні цього додатка. Ви можете створити новий <a href=\"https://github.com/commons-app/apps-android-commons/issues\">запит на GitHub</a>, щоб повідомити про помилки, або висловити пропозиції. @@ -184,6 +185,8 @@ Назва медіафайлу Опис Сюди потрапляє опис медіафайлу. Він потенційно може бути досить довгим і розтягнутися на декілька рядків. Однак ми сподіваємось, що він виглядатиме гарно. + Автор + Тут вказується ім\'я автора вибраного зображеня Дата завантаження Ліцензія Координати @@ -226,6 +229,7 @@ Вийти Посібник Сповіщення + Вибране Місця поблизу неможливо показати без дозволу на визначення місця розташування. опис не знайдено Сторінка файлу у Вікісховищі diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index a0af7d8de..4966d9c08 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -92,6 +92,7 @@ 分類 設定 註冊 + 特色圖片 關於 維基共享資源應用程式是透過維基媒體社群上的受讓人,與志願者們所建立及維護的開放原始碼應用程式。維基媒體基金會並不涉及此應用程式的建立、開發,與維護方面。 建立新的<a href=\"https://github.com/commons-app/apps-android-commons/issues\"> GitHub 問題</a>來回報程式錯誤和提出建議。 @@ -177,6 +178,8 @@ 媒體標題 說明 本媒體的說明。若內容很長,請換行,會好看一些。 + 作者 + 特色圖片作者使用者名稱於此。 上傳日期 授權協議 座標 @@ -219,6 +222,7 @@ 登出 教程 通知 + 特色 附近地點需要位置權限才可顯示 找不到說明 共享資源檔案頁面 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 1c29a92ed..83650b408 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -90,6 +90,7 @@ 分类 设置 注册 + 特色图片 关于 维基共享资源应用程序是由维基媒体社区的受助者和志愿者创建和维护的开源应用程序。维基媒体基金会不参与该应用程序的创立,开发或维护。 创建新的<a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub问题</a>以发送错误报告和建议。 @@ -175,6 +176,8 @@ 媒体的标题 说明 在此填写媒体的说明。这可能会相当长,并将需要包裹在多行中。我们希望它看起来很好。 + 作者 + 这里有特色图片作者的用户名。 上传日期 许可协议 坐标 @@ -217,6 +220,7 @@ 退出 教程 通知 + 特色 附近地点不能在没有位置权限的情况下显示 找不到描述 共享资源文件页面 From d252275b7cf0651aeb31013efd765a0ba079a5aa Mon Sep 17 00:00:00 2001 From: misaochan Date: Mon, 23 Apr 2018 21:56:48 +1000 Subject: [PATCH 034/184] Fix error during merge conflict resolution --- .../main/java/fr/free/nrw/commons/nearby/NearbyActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index d1c6ae717..2a423de93 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -369,7 +369,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); - String gsonCurLatLng = gson.toJson(curLatLang); + String gsonCurLatLng = gson.toJson(curLatLng); bundle.clear(); bundle.putString("CurLatLng", gsonCurLatLng); From fab3d32a8c5f8fbfbc4e7e4858b56680a83db367 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 24 Apr 2018 01:31:24 +1000 Subject: [PATCH 035/184] Remove author Javadocs for FeaturedImagesListFragment.java As mentioned at #1451 . Travis will fail prior to merge of #1460 --- .../nrw/commons/featured/FeaturedImagesListFragment.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java index 3e5c37bd6..19e33b0ee 100644 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java @@ -16,11 +16,6 @@ import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.Media; import fr.free.nrw.commons.R; - -/** - * Created by root on 09.01.2018. - */ - public class FeaturedImagesListFragment extends DaggerFragment { private GridView gridView; private MockGridViewAdapter gridAdapter; From 9c91d7a799e332cf4d98dca6bb3fc9dc0f95189b Mon Sep 17 00:00:00 2001 From: Tanvi Dadu Date: Thu, 26 Apr 2018 03:18:58 +0530 Subject: [PATCH 036/184] Zoom (#1300) * Basic Zoom feature added along with button to control it * Pinch Zoom added * Merge Conflicts Resolved * Icons Changed * Compressed the high resolution images * Fixed null pointer exception * Fixed null pointer exception * Fixed exception * Fixed error * Fixed Resource availability issue --- app/build.gradle | 1 + .../upload/MultipleUploadListFragment.java | 1 - .../nrw/commons/upload/ShareActivity.java | 223 ++++++++++++++++++ .../commons/upload/SingleUploadFragment.java | 3 + .../drawable-hdpi/ic_zoom_in_white_24dp.png | Bin 0 -> 422 bytes .../drawable-hdpi/ic_zoom_out_white_24dp.png | Bin 0 -> 412 bytes .../drawable-mdpi/ic_zoom_in_white_24dp.png | Bin 0 -> 257 bytes .../drawable-mdpi/ic_zoom_out_white_24dp.png | Bin 0 -> 249 bytes .../drawable-xhdpi/ic_zoom_in_white_24dp.png | Bin 0 -> 486 bytes .../drawable-xhdpi/ic_zoom_out_white_24dp.png | Bin 0 -> 470 bytes .../drawable-xxhdpi/ic_zoom_in_white_24dp.png | Bin 0 -> 737 bytes .../ic_zoom_out_white_24dp.png | Bin 0 -> 731 bytes .../ic_zoom_in_white_24dp.png | Bin 0 -> 954 bytes .../ic_zoom_out_white_24dp.png | Bin 0 -> 925 bytes .../res/drawable/ic_zoom_in_white_24dp.png | Bin 0 -> 422 bytes .../res/drawable/ic_zoom_out_white_24dp.png | Bin 0 -> 412 bytes app/src/main/res/layout/activity_share.xml | 31 ++- .../res/layout/fragment_single_upload.xml | 1 + .../main/res/layout/layout_upload_item.xml | 1 + 19 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_zoom_out_white_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_zoom_out_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_zoom_out_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_zoom_out_white_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_zoom_out_white_24dp.png create mode 100644 app/src/main/res/drawable/ic_zoom_in_white_24dp.png create mode 100644 app/src/main/res/drawable/ic_zoom_out_white_24dp.png diff --git a/app/build.gradle b/app/build.gradle index 5bafd3f15..3a7547d58 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,6 +10,7 @@ dependencies { implementation 'com.github.nicolas-raoul:Quadtree:ac16ea8035bf07' implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar' implementation 'in.yuvi:http.fluent:1.3' + implementation 'com.github.chrisbanes:PhotoView:2.0.0' implementation 'com.android.volley:volley:1.0.0' implementation 'ch.acra:acra:4.9.2' implementation 'org.mediawiki:api:1.3' diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index 5b39b92f7..34fe1d0cb 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -11,7 +11,6 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.DisplayMetrics; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index aca17601c..aea703f5e 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -2,33 +2,50 @@ package fr.free.nrw.commons.upload; import android.Manifest; import android.app.Activity; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapRegionDecoder; +import android.graphics.Point; +import android.graphics.Rect; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.RequiresApi; +import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.BitmapCompat; import android.support.v7.app.AlertDialog; +import android.util.Log; import android.view.MenuItem; import android.view.View; +import android.view.WindowManager; +import android.view.animation.DecelerateInterpolator; +import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import android.widget.Toast; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; +import com.github.chrisbanes.photoview.PhotoView; + import java.io.File; import java.io.FileNotFoundException; @@ -63,8 +80,11 @@ import fr.free.nrw.commons.utils.ImageUtils; import fr.free.nrw.commons.mwapi.MediaWikiApi; import timber.log.Timber; + + import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; +import static java.lang.Long.min; /** * Activity for the title/desc screen after image is selected. Also starts processing image @@ -120,6 +140,12 @@ public class ShareActivity private boolean haveCheckedForOtherImages = false; private boolean isNearbyUpload = false; + private Animator CurrentAnimator; + private long ShortAnimationDuration; + private FloatingActionButton zoomInButton; + private FloatingActionButton zoomOutButton; + + /** * Called when user taps the submit button. */ @@ -257,6 +283,18 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } + zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); + try { + zoomInButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + zoomImageFromThumb(backgroundImageView, mediaUri); + } + }); + } catch (Exception e){ + Log.i("exception", e.toString()); + } + zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); if (savedInstanceState != null) { contribution = savedInstanceState.getParcelable("contribution"); @@ -690,4 +728,189 @@ public class ShareActivity } } } + + private void zoomImageFromThumb(final View thumbView, Uri imageuri ) { + // If there's an animation in progress, cancel it + // immediately and proceed with this one. + if (CurrentAnimator != null) { + CurrentAnimator.cancel(); + } + hideKeyboard(ShareActivity.this); + InputStream input = null; + Bitmap scaled = null; + try { + input = this.getContentResolver().openInputStream(imageuri); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + BitmapRegionDecoder decoder = null; + try { + decoder = BitmapRegionDecoder.newInstance(input, false); + } catch (IOException e) { + e.printStackTrace(); + } + Bitmap bitmap = decoder.decodeRegion(new Rect(10, 10, 50, 50), null); + try { + //Compress the Image + System.gc(); + Runtime rt = Runtime.getRuntime(); + long maxMemory = rt.freeMemory(); + bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageuri); + int bitmapByteCount= BitmapCompat.getAllocationByteCount(bitmap); + long height = bitmap.getHeight(); + long width = bitmap.getWidth(); + long calHeight = (long) ((height * maxMemory)/(bitmapByteCount * 1.1)); + long calWidth = (long) ((width * maxMemory)/(bitmapByteCount * 1.1)); + scaled = Bitmap.createScaledBitmap(bitmap,(int) Math.min(width,calWidth), (int) Math.min(height,calHeight), true); + } catch (IOException e) { + } catch (NullPointerException e){ + scaled = bitmap; + } + // Load the high-resolution "zoomed-in" image. + PhotoView expandedImageView = (PhotoView) findViewById( + R.id.expanded_image); + expandedImageView.setImageBitmap(scaled); + + + + // Calculate the starting and ending bounds for the zoomed-in image. + // This step involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, + // and the final bounds are the global visible rectangle of the container + // view. Also set the container view's offset as the origin for the + // bounds, since that's the origin for the positioning animation + // properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + findViewById(R.id.container) + .getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final + // bounds using the "center crop" technique. This prevents undesirable + // stretching during the animation. Also calculate the start scaling + // factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation + // begins, it will position the zoomed-in view in the place of the + // thumbnail. + thumbView.setAlpha(0f); + expandedImageView.setVisibility(View.VISIBLE); + zoomOutButton.setVisibility(View.VISIBLE); + zoomInButton.setVisibility(View.GONE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations + // to the top-left corner of the zoomed-in view (the default + // is the center of the view). + expandedImageView.setPivotX(0f); + expandedImageView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and + // scale properties (X, Y, SCALE_X, and SCALE_Y). + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(expandedImageView, View.X, + startBounds.left, finalBounds.left)) + .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, + startBounds.top, finalBounds.top)) + .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, + startScale, 1f)) + .with(ObjectAnimator.ofFloat(expandedImageView, + View.SCALE_Y, startScale, 1f)); + set.setDuration(ShortAnimationDuration); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + CurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + CurrentAnimator = null; + } + }); + set.start(); + CurrentAnimator = set; + + // Upon clicking the zoomed-in image, it should zoom back down + // to the original bounds and show the thumbnail instead of + // the expanded image. + final float startScaleFinal = startScale; + zoomOutButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (CurrentAnimator != null) { + CurrentAnimator.cancel(); + } + zoomOutButton.setVisibility(View.GONE); + zoomInButton.setVisibility(View.VISIBLE); + + // Animate the four positioning/sizing properties in parallel, + // back to their original values. + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator + .ofFloat(expandedImageView, View.X, startBounds.left)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.Y,startBounds.top)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_Y, startScaleFinal)); + set.setDuration(ShortAnimationDuration); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + thumbView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + thumbView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + }); + set.start(); + CurrentAnimator = set; + + } + + }); + } + public static void hideKeyboard(Activity activity) { + View view = activity.findViewById(R.id.titleEdit | R.id.descEdit); + if (view != null) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index a88d03c03..d0e38dafe 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -11,6 +11,7 @@ import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; import android.support.v4.view.ViewCompat; import android.support.v7.app.AlertDialog; import android.text.Editable; @@ -61,6 +62,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { @BindView(R.id.share_license_summary) TextView licenseSummaryView; @BindView(R.id.licenseSpinner) Spinner licenseSpinner; + @Inject @Named("default_preferences") SharedPreferences prefs; @Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs; @@ -346,6 +348,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { } } + private void showInfoAlert (int titleStringID, int messageStringID){ new AlertDialog.Builder(getContext()) .setTitle(titleStringID) diff --git a/app/src/main/res/drawable-hdpi/ic_zoom_in_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_zoom_in_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..637329408a28249f61fd4aee845891b153a466ac GIT binary patch literal 422 zcmV;X0a^ZuP)_r!kZa!Q5tM<9G1lvl#Np6PVfYXTMr9oR$7- zJ+I)+m7cE3mSYcqne|dAIk1q=42;!fP_k_T0N}-$b--Po%Ifx9y0_4n8#`TI@fdKc z4xpeqS!x9+soeo?)FBj5w|OdAo%*2;ppd!&^kXQdf)kZf{Z;QMs1GQvUxpAwAFi^H QT>t<807*qoM6N<$f(6mHd;kCd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_zoom_out_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_zoom_out_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7772ceea714619719877d3bab5fb286a9e0979bb GIT binary patch literal 412 zcmV;N0b~A&P)I|w$@3Bq7y zv4zOu7Z|26$(1wN+VeM;!_UX%!X13hqGQFL6Jv+AWCn3k%N>%*!0ksx1-Of$6L8j^zd3!Mb~ggE7#f4JJ)Z&q?JfiJ7&-)#kBZho6GL0z z!BV>D08C>j^91&j#mqf8ilKoLG*%PEAK=+nG31L!P}}_THXXxp-@jIP0k19;Ml$OT z+yiRMG1SGbne^0PDi5J98!CU#vt!GEn>3ZwZ98{oX09=H)IISOa4ip@Aj2e;fa2tC z09W!53aIN86+i*?QyxMAbp;s5P)zl|Q9z9seWM_sP@LbDcsnH${Es030000P#jd(6VUXdS7krMY%m884WHAk4%peJ{CfmfjuxI(qY* z|C!miR-0v*4NhJZ6P1+~b%t2twOExuG4=E>f{ z*|(j?#1}qQ8B668jgqlc8Z=7AQfcs^WGqGFL&1nK00z(x^&Ee&XK3jnD0nN2y@!K)v3ewzpR#T-|!dGh9lY1-Lgkp@eAr=1H*8jNvDI}Z#JPl+LZ(#{1{ z8oc0~cDDFPgHLSI&I~tidGhX#NxE3!W@&8b#iu*I(#^<9(-)4abTjqs@P)DsU(V<-p+}yyASTR^cTolit=r#Oy)H?{uUPBaF?GfD_%%#Bt=$ye8=Gow- zC>p1&eM>6q=N}f-4{Ca(sVQyDb3%t6B_%y_j+sMjt3O)h4}*GO_YXeTuE|6M4cZGIj13GAHL0|*z#s>7zCWF8<+KUY+ z(T4oRl|0l!dy4~x{~LIZd!nh}6V0H#+JGEwJqT=~3L?J@{lqqS|o9Ik~=fu-0# zn(%;DFpAV{jAyhv#0sq7x~(C`=%DraX$ORJTm_3CPM3Jbb&A9Q8C`r=Y%ooW7Bg&e zjjv=P4iLua5~@Tyi~)pKE50nE(I)07*qoM6N<$f=v0>=Kufz literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_zoom_out_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_zoom_out_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..8c6ccea7b868ef0e31882985e38a4b3d7ae6bd64 GIT binary patch literal 470 zcmV;{0V)28P)@ECRS1d$?5Z6Jtjf0}N2MKW-LS$%#nZ{n4xBz+$j-($m{mq*< zk)tQ?nRyqJ^m(L#fvA|{m?j-kQaUs^VpjhOYy2R~1FQO5jBrjrXOvYO-*_ZXi*Xgh z2#+{jE?8%hA%>Y^gG;;?Wfj3W&J*+cgaz6-rwYd!&UZ$YfeN=cD+R(`88cNc)+x& z=nIVTjJZ=NR&j2rC<9|OFED4j(_l$%%=Iii(Q*hv*{DA|)<)rp_}JN-U70 z6QecWj}Ea-4fkqnG5D6CehzrOAN0Ki=p6;TX0b$~xu6V3_^V91d7w{R;lB#m=72IT zoI48S$kIxTRJLdNn}@NW97slD&OB&=B@kd@L+tZ$JyQjdbODcK~qt`~x>g8#~U+;}c|9MVi+Dm5_1)K%+=I8lX$0YyeOX(uD@- z8L71a;hF>2hV-NXsw2e$fMQ5>!vBUyBE4vUD*xLZDk0?qfX0w^H9!kU%K<=ZNOKyX z9MXM&m--QDL<7`G4QawBXbP!Hy9UUxg>+5Q2dJG}q)m(tXb^kfeJotZ-WM&9;V1T{ zJ+7O<-X2B|)Q5#+c_PhVA=UY;2{L@cS<&?_$=zAU*(^pEl%R~W8zxD(o}A(qXNSbK zL54IHoWTRDjM76JF_QE!#u|?_R-{EAWXK9BQ0HWHL54JC{B=kX>5Pmn$dF(O3vbn# zB~A_4fY!&~cJT>w#nj*r1AgRW=>3@_BHQ!OwIs%se|>@I;*#F4$#` zk%qs}kHJZX=1hh&oSl$X1}TtI;edp6>Yro?ffOFdkZvFylL`kUq>~0xw*p9;6eh@! z@=h{@Mfyc|I3OV%tAO-L!U-E>=;l~BA%lb@oKQhR5>ChWf5+zFT&`y>)@|;qnM3Dk{ zX35aj2$@%Ga7X3bvCcp}WnS=!f9C^z^^keQ0)BJPJc-)sbn_Xv?9o*_ooAfko&xDw ztxmblHx|f{rkNPcq{*_#Wd)^9eVxZ;n{~!0@d`8JjB#GJaoT68>?pq_S!H&L70>*6 z?Tc>To=G1}j(dyg)fBS(&ZJK&XHh$vUD?_!2h!fSel4L5>nJB3$R}I~c2!5G-FmY| z9qDnw-qNZel(qU!+>uUjCHO%Np*c}-AppN5_!$kMyeOCnzz++4Q$y%f6b$ex(Ifa1 z4WXha*eu4YM$Ai!;cE?{k|-DpAQThBr7)~eN(|p<2o=J1hU6{F2H-~ozoj8GD+(?K z;FkqIts#^V1up}1>hFRd(hzF1-m)=Adcu0kT8u_m7e&uWIgl-U73`YP2?N%Re&;~G zx5$@9D}1yH=X_GHEo$57g+9;sEHO+ENn)hvVT5I?@BCTMCZiwH6_i|ZOt=0j?Kw*9 zT0e!3^pz6KTeqiLN=y-_$r?LUS2BiPc6{h;|GMa&@xz+@V?;lz-2O%7mNnUxIj)P6 zF|;zs44a&AO^F*$*kYO??-Rj(yV<3Zdbq)4r$c^k8ejnCpjGa zaG0aB-2rj_Ac(hE?F@L%2ZE}SZCAi|ToHyE-?k&*xyQ#pVV+@+ zJi$Tr56Kn}9haya(k24#ap>~#AGExU<&sb|5ip4A6G>kiWvHR**B?+s_1gDVBdGRt z2RuTx;&C+q;Bmzos)u?5W{}mnA1EM>jcihHzy-1eM4$k{60$R$0SQ!30|)e?vh)Rv zB0E6@4iJ=(z0nttM>Zck!2Pf43fMw697@1TWb66@%E*$T1f-Fb^aWIqbs?l_jvCaB z?7hB#Yh)dv1jLYizUu+@UH=MwG+HyK`0pv=wc44DoP^id;x`bm zVF=U&a{+=FvpD!+GeHc2pwVx-1LVn2q*c5Bdu$PIg1=?`?9r?p<;>&mR}%s9JY7>3Mim} c0tyJ;AK9!R=?G29w*UYD07*qoM6N<$g1^0>_y7O^ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_zoom_out_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_zoom_out_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d85e242b97041c9907ee8e2c94417645c034edbd GIT binary patch literal 925 zcmV;O17iG%P)KhH-uTH!aML{-J?H`c7zwK5;MQKT|Me!dHL3}|J zrHG>2rCTGSAXQR9T#9YNcNB@0)2v7A(pEqx3sh-Em5X$0bCKqE z!gxlY&BK1)6V@s@Z4Q27jdm#WqoT)t)~M$>^Bkd|(cwG(z~ve{^bG`D$K@$0MTG@wedL51#4nVobwSZ!4^?b$=v5QQ zvVyHjR{pV#$JpNRy_!V83brNr$02MV=~WBpr;P1@d}9gQ3AKnJY!BoYJF#6;2;9Kd zBcC{rX@eaKfix9NXXF#FFVa%`9cBHyxM>Q zrg{0o9ZW~m1{}k5Q@&8d)T=fii)mTDP{PzD0}YaaZcOjw3+tFVWS~JZkizsyzOas| zLk1co11U@u`9cX(mkcyW2D&kQkS`Q5^{EZ$$5fOr+{ScNZNPC%cjXHOObcoQ7BMZ# z7ltwYsWza9X-K}1#{RpwVUh*PXl>$IXmC(m%X!4LWdGTg%D2`NQ~fK^;7Twy?UkmD*dhE#RXHijVUge#BEe@!6a@YiVG%i8&O;^fm>d2!8mSt#RX%y_r!kZa!Q5tM<9G1lvl#Np6PVfYXTMr9oR$7- zJ+I)+m7cE3mSYcqne|dAIk1q=42;!fP_k_T0N}-$b--Po%Ifx9y0_4n8#`TI@fdKc z4xpeqS!x9+soeo?)FBj5w|OdAo%*2;ppd!&^kXQdf)kZf{Z;QMs1GQvUxpAwAFi^H QT>t<807*qoM6N<$f(6mHd;kCd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/ic_zoom_out_white_24dp.png b/app/src/main/res/drawable/ic_zoom_out_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7772ceea714619719877d3bab5fb286a9e0979bb GIT binary patch literal 412 zcmV;N0b~A&P)I|w$@3Bq7y zv4zOu7Z|26$(1wN+VeM;!_UX%!X13hqGQFL6Jv+AWCn3k%N>%*!0ksx1-Of$6L8j^zd3!Mb~ggE7#f4JJ)Z&q?JfiJ7&-)#kBZho6GL0z z!BV>D08C>j^91&j#mqf8ilKoLG*%PEAK=+nG31L!P}}_THXXxp-@jIP0k19;Ml$OT z+yiRMG1SGbne^0PDi5J98!CU#vt!GEn>3ZwZ98{oX09=H)IISOa4ip@Aj2e;fa2tC z09W!53aIN86+i*?QyxMAbp;s5P)zl|Q9z9seWM_sP@LbDcsnH${Es030000 + android:background="?attr/mainBackground" + android:id="@+id/container"> + + + + + + + + diff --git a/app/src/main/res/layout/layout_upload_item.xml b/app/src/main/res/layout/layout_upload_item.xml index fb552560a..155664d91 100644 --- a/app/src/main/res/layout/layout_upload_item.xml +++ b/app/src/main/res/layout/layout_upload_item.xml @@ -34,6 +34,7 @@ android:textColor="#FFFFFFFF" style="?android:textAppearanceSmall" /> + \ No newline at end of file From 8a06aa5c14fa49ca49787fd6e7e718bf2b1e30be Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 26 Apr 2018 07:51:15 +0200 Subject: [PATCH 037/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-hu/strings.xml | 30 ++++++++++++++-- app/src/main/res/values-ji/strings.xml | 6 +++- app/src/main/res/values-lb/strings.xml | 2 +- app/src/main/res/values-li/strings.xml | 47 +++++++++++++++++++++++++ app/src/main/res/values-lv/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-skr/strings.xml | 2 ++ 7 files changed, 84 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index e17c0991a..5524afb0e 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -13,6 +13,7 @@ * ViDam --> + Általános Visszajelzés Helyszín Commons @@ -54,6 +55,7 @@ Megosztás Megtekintés böngészőben Cím + Kérlek, adj címet a fájlnak Leírás Nem lehet bejelentkezni - hálózati hiba Nem lehet bejelentkezni - ellenőrizd a felhasználóneved @@ -91,11 +93,12 @@ Kategóriák Beállítások Regisztráció + Kiemelt képek Névjegy A Wikimedia Commons applikáció egy nyílt forráskódú szoftver, amit a Wikimedia-közösség önkéntesei készítettek és tartanak karban. A Wikimédia Alapítvány nem vesz részt az applikáció megalkotásában, fejlesztésében és üzemeltetésében. Nyiss egy új <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-problémát</a> hibabejelentéssel vagy fejlesztési javaslattal. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Adatvédelmi irányelvek</a> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Köszönetnyilvánítás</a> + <u>Adatvédelmi irányelvek</u> + <u>Köszönetnyilvánítás</u> Névjegy Visszajelzés küldése (e-mailben) Nincs telepített levelezőprogram @@ -136,7 +139,10 @@ A Wikimédia Commons tárolja a Wikipédián használt képek többségét. A képeid segítik az ismeretterjesztést az egész világon! Kérjük, tölts fel képeket, amelyeket teljes mértékben te fotóztál vagy készítettél: - - Természeti tárgyak (virágok, állatok, hegyek)\n- Hasznos tárgyak (kerékpárok, vasútállomások)\n- Híres emberek (a polgármestered, olimpikonok, akikkel találkoztál) + Természeti tárgyak (virágok, állatok, hegyek)\n• Hasznos tárgyak (kerékpárok, vasútállomások)\n• Híres emberek (a polgármestered, olimpikonok, akikkel találkoztál) + Természeti tárgyak (virágok, állatok, hegyek) + Hasznos tárgyak (kerékpárok, vasútállomások) + Híres emberek (a polgármestered, olimpikonok, akikkel találkoztál) Kérjük, NE tölts fel: - Szelfiket vagy képeket a barátaidról\n- Internetröl letöltött képeket\n- Kereskedelmi alkalmazások képernyőképeit Példa feltöltés: @@ -168,6 +174,7 @@ Média címe Leírás A média leírása kerül ide. Ez akár egészen hosszú is lehet, és több sorba fog kerülni. Azért reméljük, jól néz majd ki. + Szerző Feltöltési dátum Licenc Koordináták @@ -207,6 +214,7 @@ Kijelentkezés Bevezető Értesítések + Kiemelt Közeli helyek nem megjeleníthetőek a helyadatokhoz való hozzáférés engedélyezése nélkül nincs leírás Commons leírólap @@ -221,10 +229,26 @@ Bejelentkezés a fiókodba Naplófájlok küldése Naplófájlok küldése e-mailben a fejlesztőknek + Nem található böngésző az URL megnyitásához Hiba! URL nem található. Törlésre jelölés + Ezt a képet törlésre jelölték. + Megtekintés böngészőben A hely nem változott. A hely nem érhető el. + Közeli helyek listájának megtekintéséhez engedély szükséges Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. Köszönjük a szerkesztésedet! + WIKIDATA + WIKIPÉDIA + COMMONS + <u>Értékelj minket</u> + <u>GYIK</u> + Útmutató átugrása + Internet nem elérhető + Internet elérhető + Nincs értesítés + Nyelvek + Mégse + Újra diff --git a/app/src/main/res/values-ji/strings.xml b/app/src/main/res/values-ji/strings.xml index 9122cc710..6bcb88760 100644 --- a/app/src/main/res/values-ji/strings.xml +++ b/app/src/main/res/values-ji/strings.xml @@ -3,6 +3,9 @@ * פוילישער --> + אַלגעמיין + פֿידבעק + לאקאציע קאמאנס איינשטעלונגען באַניצער־נאָמען @@ -48,6 +51,7 @@ זוכן קאטעגאריעס אויפֿהיטן דערפֿרישן + ליסטע \@string/contributions_subtitle_zero איין ארויפֿלאד @@ -66,7 +70,7 @@ לעצטיק־געניצטע קאטעגאריעס אַנולירן אראָפלאָדן - ליצענץ + סטאנדארט־ליצענץ Attribution-ShareAlike 3.0 Attribution 3.0 CC0 diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index 321d2a189..5abca6562 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -89,7 +89,7 @@ D\'App Wikimedia Commons ass eng \'Open-Source-App\' déi vu Fräiwëllege vun der Wikimedia Foundation entwéckelt gouf an och vun hinnen ënnerhal gëtt. D\'Wikimedia Foundation ass net an d\'Entwécklung oder den Ënnerhalt vun der App implizéiert. Leet w.e.g. <a href=\"https://github.com/commons-app/apps-android-commons/issues\"> e GitHub Problem</a> fir Problemer ze mellen a Proposen ze maachen. <u>Dateschutzrichtlinn</u> - <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/CREDITS\">Merci</a> + <u>Merci</u> Iwwer Feedback schécken (per E-Mail) Keen E-Mail-Client installéiert diff --git a/app/src/main/res/values-li/strings.xml b/app/src/main/res/values-li/strings.xml index 59dc53188..0699d80cd 100644 --- a/app/src/main/res/values-li/strings.xml +++ b/app/src/main/res/values-li/strings.xml @@ -87,6 +87,27 @@ Registreer Oetgeleechde plaetjes Euver + De Wikimedia Commons-app is \'nen app op aope brónne, gemaak en óngerhaje door gerechtigde en vriewilligers vanne Wikimedia-gemeinsjap. De Wikimedia Foundation is neet betróch inne maak, óntwikkeling of \'t óngerhawd vannen app. + Maak e nuuj <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-perbleem</a> veur fouteverslaag en veurstèlle. + <u>Privaatbeleid</u> + <u>Toesjrif</u> + Euver + Sjik feedback (mitten e-mail) + Geine e-mailcliënt geïnstalleerd + Recèntelik gebroekde categorieje + Oppe ieëste synchronisatie \'nt wachte... + Doe höbs nag gein plaetjes geüpload. + Perbeer oppernuuj + Braek aaf + Dit plaetje weurt gelicenseerd ónger %1$s + Door dit plaetje toe te veuge verklaor ich det dit mien eige werk is en det \'t gein auteursrechtelik besjurmp matterjaal of selfies bevatj en angeszins instump mit \'t <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">beleid op Wikimedia Commons</a>. + Download + Standerdlicentie + Gebroek veurige naam/besjrieving + Haol autematis de hujige locatie op + Haol de hujige locatie op veur categorieveurstèlle te make wen \'t bild gein geotags haet + Nachmodus + Gebroeker duuster thema Naamsvermeljing-GeliekDeile 4.0 Naamsvermeljing 4.0 Naamsvermeljing-GeliekDeile 3.0 @@ -109,5 +130,31 @@ CC Zero Op Wikimedia Commons staon de meiste plaetjes die waere gebroek op Wikipedia. Dien plaetjes helpe luuj oppe ganse werreld mit \'t opdoon van kènnis! + Upload estebleef allein plaetjes die gans door dichzelf zint gemaak: + Netuurobjekte (blome, bieëster, berg)\n• Henjige veurwerpe (fietsje, treinstaasjes)\n• Bekandje luuj (de börgermeisters, Olumpische atlete die se kins) + Netuurobjekte (blome, bieëster, berg) + Henjige veurwerpe (fietsje, treinstaasjes) + Bekandje luuj (de börgermeisters, Olumpische atlete die se kins) + Upload estebleef NEET: + - Selfies of foto\'s van dien vrunj\n- Foto\'s die se höbs downgeload van \'t internet\n- Sjermplaetjes van eige apps + Selfies of foto\'s van dien vrunj + Foto\'s die se höbs downgeload van \'t internet + Sjermplaetjes van eige apps + Uploadveurbild: + - Titel: Operahoes in Sydney\n- Besjrieving: Operahoes in Sydney gezeen vanaaf d\'n euverkantj vanne bej\n- Categorieje: Operahoes in Sydney vanoet \'t wèste, Operahoes in Sydney van wied aaf + Titel: Operahoes in Sydney + Besjrieving: Operahoes in Sydney gezeen vanaaf d\'n euverkantj vanne bej + Categorieje: Operahoes in Sydney vanoet \'t wèste, Operahoes in Sydney van wied aaf + Draag dien plaetjes bie. Help Wikipedia-artikel toet laeve te kómme! + Plaetjes op Wikipedia kómme van Wikimedia Commons. + Dien plaetjes helpe luuj van euver de ganse werreld mit lieëre. + Verkóm auteursrechtelik besjurmp matterjaal det se op internet höbs gevónje wie plaetjes van poeasters, beuk en zo wiejer. + Versteis se \'t? + Jao! + Categorieje + \'nt laje... + Geine gekaoze + Gein besjrieving + Ónbekande licentie Vernuuj diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index d73312361..1eba570d2 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -79,6 +79,7 @@ Nosaukums Apraksts + Autors Augšupielādēšanas datums Licence Koordinātas diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index d19dfc7c8..77cdb547d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -172,6 +172,7 @@ Tytuł pliku Opis Tu jest miejsce na opis pliku. Mogą być dość długie i wymagać przewijania podczas czytania. Chcemy, by wszystko wyglądało dobrze. + Autor Data przesłania Licencja Współrzędne diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index d1d1d5d87..796ae8555 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -89,6 +89,7 @@ عنوان میڈیا دا عنوان تفصیل + مصنف اپ لوڈ تھیوݨ دی تاریخ لائیسنس کوآرڈینیٹ @@ -113,6 +114,7 @@ تہاڈی رائے لاگ آؤٹ ٹیٹوریل + خاص وکی ڈیٹا آئٹم وکی پیڈیا دا مضمون اجازت ݙیوو From 5ebaa7418eb25d297e128395f5a08065f125950f Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 30 Apr 2018 08:19:57 +0200 Subject: [PATCH 038/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-fi/strings.xml | 23 ++++++++++++++++++--- app/src/main/res/values-is/strings.xml | 4 ++++ app/src/main/res/values-it/strings.xml | 4 ++++ app/src/main/res/values-iw/strings.xml | 5 +++++ app/src/main/res/values-ku/strings.xml | 1 + app/src/main/res/values-li/strings.xml | 10 +++++++++ app/src/main/res/values-tr/strings.xml | 28 ++++++++++++++++++++++++-- 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index dd1d37993..e833932a8 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -71,6 +71,7 @@ Etsi luokkia Tallenna Päivitä + Lista GPS ei ole käytössä. Haluatko ottaa sen käyttöön? Ota GPS käyttöön Ei tallennuksia vielä @@ -161,8 +162,8 @@ Ei kuvausta Tuntematon lisenssi Päivitä - Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei toimi ilman tätä oikeutta. - Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Sovellus ei voi toimia ilman tätä. + Vaadittu oikeus: Ulkoisen tallennustilan luku. Appi ei voi päästä galleriaasi ilman tätä oikeutta. + Vaadittava lupa: Kirjoita ulkoiseen tallennustilaan. Appi ei voi päästä kameraasi ilman tätä oikeutta. Valinnainen lupa: Saada tämänhetkinen sijainti loukkasuosituksia varten. OK Lähellä olevat paikat @@ -175,6 +176,7 @@ Median otsikko Kuvaus Median kuvaus menee tänne. Tämä voi mahdollisesti olla melko pitkä, ja sen täytyy kääriä poikittain useita rivejä. Toivomme, että se näyttää silti hyvältä. + Tekijä Tallennuspäivämäärä Lisenssi Koordinaatit @@ -221,6 +223,7 @@ kuvausta ei löytynyt Commons-tiedostosivu Wikidata-kohde + Wikipedia-artikkeli Virhe varastoidessa kuvia Tiedoston yksilöllinen ja kuvaava otsikko, jota käytetään tiedostonimenä. Voit käyttää tavallista kieltä välilyönnein. Älä sisällytä tiedoston päätettä. Kuvaile mediaa niin paljon kuin mahdollista: Missä se otettiin? Mitä se esittää? Mikä on asiayhteys? Kuvaile esineitä tai henkilöitä. Tuo ilmi tietoja, joita ei ole helppo arvailla, esimerkiksi vuorokaudenaika, jos se on maisema. Jos media esittää jotain epätavallista, selitä, mikä tekee siitä epätavallisen. @@ -233,6 +236,9 @@ Lähetä lokitiedosto Lähetä lokitiedosto kehittäjille sähköpostin kautta Virhe! URL-osoitetta ei löytynyt + Ehdotettu poistettavaksi + Tätä kuvaa on ehdotettu poistettavaksi. + Näytä selaimessa Sijainti ei ole muuttunut. Sijainti ei käytettävissä. Lupa vaaditaan läheisten paikkojen luettelon näyttämiseen @@ -243,6 +249,17 @@ Kiitos muokkaamisestasi %1$s mainitsi sinut %2$s. Vaihda näkymä - Usein Kysytyt Kysymykset + WIKIDATA + WIKIPEDIA + COMMONS + <u>Arvostele meidät</u> + <u>UKK</u> Ohita opetus + Internet ei saatavissa + Internet saatavana + <u>Käännä</u> + Kielet + Jatka + Peruuta + Yritä uudelleen diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 3985a654b..ba5bdfe42 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -84,6 +84,7 @@ Flokkar Stillingar Nýskrá + Áberandi myndir Um Wikimedia Commons forritið er opinn og frjáls hugbúnaður sem gerður er og viðhaldið af stuðningsaðilum og sjálfboðaliðum Wikimedia samfélagsins. Wikimedia Foundation sjálfseignarstofnunin kemur ekki að gerð, forritun eða viðhaldi forritsins. \ Útbúðu nýjar <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub tilkynningar (issue)</a> til að koma villum og uppástungum á framfæri. @@ -169,6 +170,8 @@ Titill þessa gagnamiðils Lýsing Lýsing á gagnamiðlinum kemur hér. Þetta má vera nokkuð langt og mun þurfa að skríða yfir nokkrar línur. Við vonum að þetta líti samt þokkalega út. + Höfundur + Nafn höfundar myndarinnar kemur hér. Sent inn þann Notkunarleyfi Hnit @@ -211,6 +214,7 @@ Útskráning Kennsla Tilkynningar + Efst á baugi Ekki er hægt að birta nálæga staði an heimildar til að ná í hnattstaðsetningu engin lýsing fannst Síða Commons-skrár diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 27968b8d7..306a1e3a4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -5,6 +5,7 @@ * Davio * Nemo bis * S4b1nuz E.656 +* Sarah Bernabei * Una giornata uggiosa '94 * Wim b --> @@ -87,6 +88,7 @@ Categorie Impostazioni Registrati + Immagini in evidenza Informazioni L\'app di Wikimedia Commons è un\'applicazione open source creata e mantenuta da beneficiari e volontari della comunità Wikimedia. La Fondazione Wikimedia non è coinvolta nella creazione, sviluppo o manutenzione dell\'applicazione. Crea una nuova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">segnalazione GitHub</a> per riportare errori e suggerimenti. @@ -161,6 +163,7 @@ Titolo del file multimediale Descrizione Autore + Il nome dell\'autore dell\'immagine in evidenza va scritto qui. Data di caricamento Licenza Coordinate @@ -194,6 +197,7 @@ Esci Tutorial Notifiche + In evidenza nessuna descrizione trovata Pagina di Commons del file Elemento Wikidata diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 186df118a..48750daf9 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -17,6 +17,7 @@ משוב מיקום ויקישיתוף + הגדרות שם משתמש ססמה @@ -208,6 +209,7 @@ בלי תמונות סלפי תמונה קניינית ברוך בואך ויקיפדיה + הודעה לגבי זכויות יוצרים בית האופרה של סידני ביטול פתיחה @@ -226,6 +228,7 @@ לא נמצא תיאור דף קובץ בוויקישיתוף פריט ויקינתונים + ערך בוויקיפדיה שגיאה במשירת תמונות במטמון כותרת מתארת ייחודית לקובץ, שתשמש שם קובץ. אפשר להשתמש בשפה פשוטה עם רווחים. אין לכלול סיומת קובץ נא לתאר את המדיה כמה שיותר: איפה היא נוצרה? מה היא מראה? מה ההקשר? נא לתאר את העצמים או את האנשים. נא לחשוף מידע שאי־אפשר לנחש בקלות, למשל, הזמן ביום אם זאת תמונת נוף. אם המדיה מציגה משהו בלתי־רגיל, נא להסביר מה מיוחד בה. @@ -238,8 +241,10 @@ שליחת קובץ יומן שליחת קובץ יומן למפתחים בדואר אלקטרוני לא נמצא דפדפן שיוכל לפתוח את הכתובת + שגיאה! כתובת ה־URL לא נמצאה להציע מחיקה התמונה הזאת מועמדת למחיקה + הצגה בדפדפן המיקום לא השתנה. המיקום אינו זמין. diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml index 16ba9fe2f..aac473c92 100644 --- a/app/src/main/res/values-ku/strings.xml +++ b/app/src/main/res/values-ku/strings.xml @@ -69,6 +69,7 @@ Hişyarî Erê Na + Xwedî Koordînat Betal bike Veke diff --git a/app/src/main/res/values-li/strings.xml b/app/src/main/res/values-li/strings.xml index 0699d80cd..a14add497 100644 --- a/app/src/main/res/values-li/strings.xml +++ b/app/src/main/res/values-li/strings.xml @@ -157,4 +157,14 @@ Gein besjrieving Ónbekande licentie Vernuuj + Klaor + Plaatse in de buurt + Gein plaatse in de buurt gevónje + Waorsjoewing + Dit bestandj besteit al op Commons. Wèts se zeker det se door wils gaon? + Jao + Nae + Titel + Bestandjstitel + Besjrieving diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 94d383ff9..95548b662 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -16,6 +16,7 @@ Geri bildirim Konum Commons + Ayarlar Kullanıcı adı Parola @@ -91,6 +92,7 @@ Kategoriler Ayarlar Kaydol + Seçkin Resimler Hakkında Wikimedia Commons uygulaması, Wikimedia topluluğunun imtiyaz sahibi ve gönüllüleri tarafından oluşturulmuş ve sürdürülmüş açık kaynak kodlu bir uygulamadır. Vikipedi Vakfı, uygulamanın oluşturulması, geliştirilmesi veya bakımına dahil değildir. GitHub üzerinde <a href=\"https://github.com/commons-app/apps-android-commons\">Kaynak</a> ve <a href=\"https://commons-app.github.io/\">website</a>. Hata raporları ve önerileri için yeni bir <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub sorunu</a> oluştur. @@ -149,6 +151,7 @@ - Başlık: Sydney Opera Binası\n- Tanım: Körfezin genelinden bakıldığında Sydney Opera Binası\n- Kategoriler: Sydney Opera Binası, batıdan Sydney Opera Binası Başlık: Sidney Opera Binası Açıklama: Sidney Opera Binası\'nın körfezin karşısından görünümü + Kategoriler: Batıdan Sidney Opera Binası, Sidney Opera Binası uzaktan manzaraları Resimleriniz ile Vikipedi maddelerinin canlandırılmasına katkıda bulunabilirsiniz! Vikipedi\'ye Wikimedia Commons\'tan gelen görüntüler. Görüntüler dünya insanlarının eğitiminde yardımcı olur. @@ -161,8 +164,8 @@ Açıklama yok Bilinmeyen lisans Yenile - Gerekli izinler: Harici depolama biriminin okunması. Uygulama buna izin verilmeden çalışmaz. - Gerekli izin: Harici depolama birimi üzerine yazma. Uygulama buna izin verilmeden çalışmaz. + Gerekli izin: Harici belleği oku. Uygulama, galerinize bu olmadan erişemez. + Gerekli izin: Harici depolama yazın. Uygulama kameranıza bu olmadan erişemez. İsteğe bağlı izin: Kategori önerileri için geçerli konum alma Tamam Yakındaki yerler @@ -175,6 +178,8 @@ Medyanın başlığı Açıklama Medya için yapılan tanımı/açıklamayı buraya yazınız. Açıklamanız uzun olabilir ve birden fazla satıra sığabilir. Umuyoruz ki güzel ve bilgilendirici olacaktır. + Yazar + Seçkin resim yazarının kullanıcı adı buraya eklenir. Yükleme tarihi Lisans Koordinatlar @@ -217,6 +222,7 @@ Çıkış Eğitim Bildirimler + Seçkin Yakındaki yerler, konum izinleri olmadan görüntülenemez hiçbir açıklama bulunamadı Commons dosya sayfası @@ -244,7 +250,25 @@ TALİMATLAR MADDE OKU Wikimedia Commons\'a hoşgedin %1$s! Burada olduğun için mutluyuz. + %1$s mesaj sayfasınıza bir mesaj bıraktı. Düzenlemeniz için teşekkürler %1$s , %2$s \'de senden bahsetti + Görünümü değiştir YOL TARİFİ + VİKİVERİ + VİKİPEDİ + COMMONS + <u>Bizi oyla</u> + <u>SSS</u> + Eğiticiyi Atla + İnternet kullanılamıyor + İnternet kullanılabilir + Bildirim alınırken hata oluştu + Bildirim bulunamadı + <u>Çevir</u> + Diller + Çevirileri göndermek istediğiniz dili seçin + İlerle + Vazgeç + Tekrar Deneyin From b017d1c99a5c3cad8adef4cf843c20048bd4f034 Mon Sep 17 00:00:00 2001 From: Ujjwal Agrawal Date: Mon, 30 Apr 2018 14:54:37 +0530 Subject: [PATCH 039/184] Changed webview to Custom Tabs in Settings Page (#1328) * Changed Webview to Custoom tabs in Settings Page * Get COntext changed to getActivity --- .../java/fr/free/nrw/commons/settings/SettingsFragment.java | 5 +++++ app/src/main/res/xml/preferences.xml | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 037f0d792..02b1dc29f 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -102,6 +102,11 @@ public class SettingsFragment extends PreferenceFragment { return true; }); + Preference betaTesterPreference = findPreference("becomeBetaTester"); + betaTesterPreference.setOnPreferenceClickListener(preference -> { + Utils.handleWebUrl(getActivity(),Uri.parse(getResources().getString(R.string.beta_opt_in_link))); + return true; + }); Preference sendLogsPreference = findPreference("sendLogFile"); sendLogsPreference.setOnPreferenceClickListener(preference -> { //first we need to check if we have the necessary permissions diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index baf1a760e..49720b247 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -52,10 +52,10 @@ - - Date: Mon, 30 Apr 2018 16:19:03 +0530 Subject: [PATCH 040/184] fixed crash while uploadiing certain images (#1388) --- app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java index 13056ad4b..612b86458 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java @@ -59,7 +59,7 @@ public class FileUtils { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + Uri.parse("content://downloads/document"), Long.valueOf(id)); returnPath = getDataColumn(context, contentUri, null, null); } else if (isMediaDocument(uri)) { // MediaProvider From 3c2cc26d3b82625bb2e2737eb54e97cc9dd318fa Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 30 Apr 2018 14:05:47 +0300 Subject: [PATCH 041/184] Fix conflicts from #1366 fixing lint issues (#1470) * lint issue #171 - added Locale.getDefault() * lint issue #171 - added Locale.getDefault() * lint issue #171 - added %d * lint issue #171 - Changed version * lint issue #171 - added singleLine="true" * lint issue #171 - changed commit to apply * lint issue #171 - added Locale.getDefault() * lint issue #171 - added Locale.getDefault() * Codacy issues #778 - nested if loop * Codacy issues #778 - nested if loop * Revert "lint issue #171 - added %d" since we dont edit translated string files This reverts commit e4917cddcf7e88b7cdcc570ea9ed8452d33ceea2. --- app/build.gradle | 2 +- .../java/fr/free/nrw/commons/auth/LoginActivity.java | 9 +++++---- .../main/java/fr/free/nrw/commons/delete/DeleteTask.java | 2 +- .../fr/free/nrw/commons/media/MediaDetailFragment.java | 2 +- .../fr/free/nrw/commons/settings/SettingsFragment.java | 4 ++-- .../free/nrw/commons/upload/MultipleShareActivity.java | 4 ++-- .../fr/free/nrw/commons/upload/SingleUploadFragment.java | 2 +- .../fr/free/nrw/commons/utils/StringSortingUtils.java | 5 +++-- .../res/layout/light_simple_spinner_dropdown_item.xml | 2 +- 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3a7547d58..535f58143 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,7 +35,7 @@ dependencies { implementation "com.jakewharton:butterknife:$BUTTERKNIFE_VERSION" kapt "com.jakewharton:butterknife-compiler:$BUTTERKNIFE_VERSION" - implementation 'com.squareup.okhttp3:okhttp:3.8.1' + implementation 'com.squareup.okhttp3:okhttp:3.9.1' implementation 'com.squareup.okio:okio:1.13.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index ef46869c4..dfdc6d7e4 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -29,6 +29,7 @@ import android.widget.EditText; import android.widget.TextView; import java.io.IOException; +import java.util.Locale; import javax.inject.Inject; import javax.inject.Named; @@ -267,18 +268,18 @@ public class LoginActivity extends AccountAuthenticatorActivity { if (result.equals("NetworkFailure")) { // Matches NetworkFailure which is created by the doInBackground method showMessageAndCancelDialog(R.string.login_failed_network); - } else if (result.toLowerCase().contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) { + } else if (result.toLowerCase(Locale.getDefault()).contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) { // Matches nosuchuser, nosuchusershort, noname showMessageAndCancelDialog(R.string.login_failed_username); emptySensitiveEditFields(); - } else if (result.toLowerCase().contains("wrongpassword".toLowerCase())) { + } else if (result.toLowerCase(Locale.getDefault()).contains("wrongpassword".toLowerCase())) { // Matches wrongpassword, wrongpasswordempty showMessageAndCancelDialog(R.string.login_failed_password); emptySensitiveEditFields(); - } else if (result.toLowerCase().contains("throttle".toLowerCase())) { + } else if (result.toLowerCase(Locale.getDefault()).contains("throttle".toLowerCase())) { // Matches unknown throttle error codes showMessageAndCancelDialog(R.string.login_failed_throttled); - } else if (result.toLowerCase().contains("userblocked".toLowerCase())) { + } else if (result.toLowerCase(Locale.getDefault()).contains("userblocked".toLowerCase())) { // Matches login-userblocked showMessageAndCancelDialog(R.string.login_failed_blocked); } else if (result.equals("2FA")) { diff --git a/app/src/main/java/fr/free/nrw/commons/delete/DeleteTask.java b/app/src/main/java/fr/free/nrw/commons/delete/DeleteTask.java index 0cce496f0..37b9a7a82 100644 --- a/app/src/main/java/fr/free/nrw/commons/delete/DeleteTask.java +++ b/app/src/main/java/fr/free/nrw/commons/delete/DeleteTask.java @@ -83,7 +83,7 @@ public class DeleteTask extends AsyncTask { String logPageString = "\n{{Commons:Deletion requests/" + media.getFilename() + "}}\n"; - SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()); String date = sdf.format(calendar.getTime()); String userPageString = "\n{{subst:idw|" + media.getFilename() + diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 5acfb218e..037f92e56 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -458,7 +458,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (date == null || date.toString() == null || date.toString().isEmpty()) { return "Uploaded date not available"; } - SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy"); + SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy", Locale.getDefault()); return formatter.format(date); } diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 02b1dc29f..6dd6056f7 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -133,8 +133,8 @@ public class SettingsFragment extends PreferenceFragment { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + { sendAppLogsViaEmail(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java index 5525f1ba7..510076ce8 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java @@ -221,8 +221,8 @@ public class MultipleShareActivity extends AuthenticatedActivity //TODO: 15/10/17 should location permission be explicitly requested if not provided? //check if location permission is enabled - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + { locationPermitted = true; } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index d0e38dafe..e93ac12d6 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -226,7 +226,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { setLicenseSummary(license); prefs.edit() .putString(Prefs.DEFAULT_LICENSE, license) - .commit(); + .apply(); } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java index 03b1469e0..e409b856d 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.utils; import java.util.Comparator; +import java.util.Locale; import info.debatty.java.stringsimilarity.Levenshtein; @@ -28,8 +29,8 @@ public class StringSortingUtils { } private static double calculateSimilarity(String firstString, String secondString) { - String longer = firstString.toLowerCase(); - String shorter = secondString.toLowerCase(); + String longer = firstString.toLowerCase(Locale.getDefault()); + String shorter = secondString.toLowerCase(Locale.getDefault()); if (firstString.length() < secondString.length()) { longer = secondString; diff --git a/app/src/main/res/layout/light_simple_spinner_dropdown_item.xml b/app/src/main/res/layout/light_simple_spinner_dropdown_item.xml index be4e086e4..11f95bf2e 100644 --- a/app/src/main/res/layout/light_simple_spinner_dropdown_item.xml +++ b/app/src/main/res/layout/light_simple_spinner_dropdown_item.xml @@ -2,7 +2,7 @@ Date: Mon, 30 Apr 2018 16:52:50 +0530 Subject: [PATCH 042/184] Fix issue #1332 : Contribution Image auto/manual refresh if fetching fails --- .../commons/contributions/ContributionsActivity.java | 1 - .../contributions/ContributionsListFragment.java | 10 ++++++++++ app/src/main/res/layout/fragment_contributions.xml | 7 ++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java index ad6cff606..312839a24 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsActivity.java @@ -144,7 +144,6 @@ public class ContributionsActivity if(!BuildConfig.FLAVOR.equalsIgnoreCase("beta")){ setUploadCount(); } - } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index ff400a8dd..2b6c56c43 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -7,6 +7,7 @@ import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.Menu; @@ -47,6 +48,8 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment { TextView waitingMessage; @BindView(R.id.loadingContributionsProgressBar) ProgressBar progressBar; + @BindView(R.id.swipeRefreshLayout) + SwipeRefreshLayout swipeRefreshLayout; @Inject @Named("prefs") @@ -64,6 +67,13 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment { ButterKnife.bind(this, v); contributionsList.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + ((ContributionsListAdapter)contributionsList.getAdapter()).notifyDataSetChanged(); + swipeRefreshLayout.setRefreshing(false); + } + }); if (savedInstanceState != null) { Timber.d("Scrolling to %d", savedInstanceState.getInt("grid-position")); contributionsList.setSelection(savedInstanceState.getInt("grid-position")); diff --git a/app/src/main/res/layout/fragment_contributions.xml b/app/src/main/res/layout/fragment_contributions.xml index fa53d9721..d089c7053 100644 --- a/app/src/main/res/layout/fragment_contributions.xml +++ b/app/src/main/res/layout/fragment_contributions.xml @@ -24,6 +24,11 @@ android:id="@+id/loadingContributionsProgressBar" /> + + - + \ No newline at end of file From 0223c5ab767d5d62953f82c71c4c6449bdd90d4e Mon Sep 17 00:00:00 2001 From: Abhishek Poonia Date: Mon, 30 Apr 2018 16:57:35 +0530 Subject: [PATCH 043/184] Error messages in LoginActivity persist after orientation change. (#1407) --- .../fr/free/nrw/commons/auth/LoginActivity.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index dfdc6d7e4..75be2adde 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -84,6 +84,10 @@ public class LoginActivity extends AccountAuthenticatorActivity { private LoginTextWatcher textWatcher = new LoginTextWatcher(); private Boolean loginCurrentlyInProgress = false; + private Boolean errorMessageShown = false; + private String resultantError; + private static final String RESULTANT_ERROR = "resultantError"; + private static final String ERROR_MESSAGE_SHOWN = "errorMessageShown"; private static final String LOGING_IN = "logingIn"; @Override @@ -217,6 +221,8 @@ public class LoginActivity extends AccountAuthenticatorActivity { handlePassResult(username, password); } else { loginCurrentlyInProgress = false; + errorMessageShown = true; + resultantError = result; handleOtherResults(result); } } @@ -343,15 +349,22 @@ public class LoginActivity extends AccountAuthenticatorActivity { protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(LOGING_IN, loginCurrentlyInProgress); + outState.putBoolean(ERROR_MESSAGE_SHOWN, errorMessageShown); + outState.putString(RESULTANT_ERROR, resultantError); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); loginCurrentlyInProgress = savedInstanceState.getBoolean(LOGING_IN, false); + errorMessageShown = savedInstanceState.getBoolean(ERROR_MESSAGE_SHOWN, false); if(loginCurrentlyInProgress){ performLogin(); } + if(errorMessageShown){ + resultantError = savedInstanceState.getString(RESULTANT_ERROR); + handleOtherResults(resultantError); + } } public void askUserForTwoFactorAuth() { @@ -363,7 +376,9 @@ public class LoginActivity extends AccountAuthenticatorActivity { public void showMessageAndCancelDialog(@StringRes int resId) { showMessage(resId, R.color.secondaryDarkColor); - progressDialog.cancel(); + if(progressDialog != null){ + progressDialog.cancel(); + } } public void showSuccessAndDismissDialog() { From 6d2c41b91efc163756a5a407cf442d5275dea51d Mon Sep 17 00:00:00 2001 From: Balakrishnan S <97balakrishnan@gmail.com> Date: Mon, 30 Apr 2018 17:01:27 +0530 Subject: [PATCH 044/184] Help button (#1415) * Help button added to tutorial * debug typo removed * Help changed to more info * More option moved to bottom * Alignment changes made --- .../free/nrw/commons/WelcomePagerAdapter.java | 14 ++++++++ .../main/res/layout-land/welcome_final.xml | 32 ++++++++++++++++--- app/src/main/res/layout/welcome_final.xml | 30 ++++++++++++++--- app/src/main/res/values/strings.xml | 1 + 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.java b/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.java index 705de23da..bca548632 100644 --- a/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/WelcomePagerAdapter.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons; +import android.net.Uri; import android.support.annotation.Nullable; import android.support.v4.view.PagerAdapter; import android.view.LayoutInflater; @@ -9,6 +10,7 @@ import android.widget.TextView; import butterknife.ButterKnife; import butterknife.OnClick; +import butterknife.Optional; public class WelcomePagerAdapter extends PagerAdapter { static final int[] PAGE_LAYOUTS = new int[]{ @@ -20,6 +22,7 @@ public class WelcomePagerAdapter extends PagerAdapter { }; private static final int PAGE_FINAL = 4; private Callback callback; + private ViewGroup container; /** * Changes callback to provided one @@ -53,6 +56,7 @@ public class WelcomePagerAdapter extends PagerAdapter { @Override public Object instantiateItem(ViewGroup container, int position) { + this.container=container; LayoutInflater inflater = LayoutInflater.from(container.getContext()); ViewGroup layout = (ViewGroup) inflater.inflate(PAGE_LAYOUTS[position], container, false); if( BuildConfig.FLAVOR == "beta"){ @@ -102,5 +106,15 @@ public class WelcomePagerAdapter extends PagerAdapter { } } + @Optional + @OnClick(R.id.welcomeInfo) + void onHelpClicked () { + try { + Utils.handleWebUrl(container.getContext(),Uri.parse("https://commons.wikimedia.org/wiki/Help:Contents" )); + } catch (Exception e) { + e.printStackTrace(); + } + } + } } diff --git a/app/src/main/res/layout-land/welcome_final.xml b/app/src/main/res/layout-land/welcome_final.xml index 0b99b481f..d44339647 100644 --- a/app/src/main/res/layout-land/welcome_final.xml +++ b/app/src/main/res/layout-land/welcome_final.xml @@ -1,13 +1,33 @@ - + > + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/welcome_final.xml b/app/src/main/res/layout/welcome_final.xml index 7f323253b..561e660aa 100644 --- a/app/src/main/res/layout/welcome_final.xml +++ b/app/src/main/res/layout/welcome_final.xml @@ -1,14 +1,18 @@ - + - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 28ecaeb8f..efdeeec7e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -149,6 +149,7 @@ Avoid copyrighted materials you found from the Internet as well as images of posters, book covers, etc. You think you got it? Yes! + More Information Categories Loading… None selected From 35f05be8df4e5bfea09baac6683a0eab83ae092a Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 30 Apr 2018 14:42:19 +0300 Subject: [PATCH 045/184] fix memory leaks (they happened due to hiding keyboard) and lint null pointer warnings in the same code (#1471) --- .../free/nrw/commons/auth/LoginActivity.java | 10 +++++--- .../category/CategorizationFragment.java | 11 +++++--- .../commons/upload/MultipleShareActivity.java | 3 ++- .../upload/MultipleUploadListFragment.java | 25 ++++++++++--------- .../commons/upload/SingleUploadFragment.java | 22 ++++++++-------- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index 75be2adde..7b2b0a97f 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -128,7 +128,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { forgotPasswordText.setOnClickListener(view -> forgotPassword()); - if(BuildConfig.FLAVOR == "beta"){ + if(BuildConfig.FLAVOR.equals("beta")){ loginCredentials.setText(getString(R.string.login_credential)); } else { loginCredentials.setVisibility(View.GONE); @@ -145,8 +145,12 @@ public class LoginActivity extends AccountAuthenticatorActivity { } public void hideKeyboard(View view) { - InputMethodManager inputMethodManager =(InputMethodManager)this.getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } } diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index a41a52139..101d4b21e 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -10,7 +10,6 @@ import android.support.v7.widget.RecyclerView; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; -import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -43,7 +42,6 @@ import fr.free.nrw.commons.R; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.upload.MwVolleyApi; -import fr.free.nrw.commons.upload.SingleUploadFragment; import fr.free.nrw.commons.utils.StringSortingUtils; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -131,8 +129,13 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { } public void hideKeyboard(View view) { - InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java index 510076ce8..9c31e2b4d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java @@ -166,7 +166,8 @@ public class MultipleShareActivity extends AuthenticatedActivity View target = getCurrentFocus(); if (target != null) { InputMethodManager imm = (InputMethodManager) target.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(target.getWindowToken(), 0); + if (imm != null) + imm.hideSoftInputFromWindow(target.getWindowToken(), 0); } getSupportFragmentManager().beginTransaction() .add(R.id.uploadsFragmentContainer, categorizationFragment, "categorization") diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index 34fe1d0cb..c7f3c39c0 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -88,9 +88,9 @@ public class MultipleUploadListFragment extends Fragment { if (view == null) { view = LayoutInflater.from(getContext()).inflate(R.layout.layout_upload_item, viewGroup, false); holder = new UploadHolderView(); - holder.image = (SimpleDraweeView) view.findViewById(R.id.uploadImage); - holder.title = (TextView) view.findViewById(R.id.uploadTitle); - holder.overlay = (RelativeLayout) view.findViewById(R.id.uploadOverlay); + holder.image = view.findViewById(R.id.uploadImage); + holder.title = view.findViewById(R.id.uploadTitle); + holder.overlay = view.findViewById(R.id.uploadOverlay); holder.image.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, photoSize.y)); holder.image.setHierarchy(GenericDraweeHierarchyBuilder @@ -128,11 +128,8 @@ public class MultipleUploadListFragment extends Fragment { super.onStop(); // FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next - View target = getView().findFocus(); - if (target != null) { - InputMethodManager imm = (InputMethodManager) target.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(target.getWindowToken(), 0); - } + View target = getActivity().getCurrentFocus(); + hideKeyboard(target); } // FIXME: Wrong result type @@ -168,8 +165,8 @@ public class MultipleUploadListFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_multiple_uploads_list, container, false); - photosGrid = (GridView) view.findViewById(R.id.multipleShareBackground); - baseTitle = (EditText) view.findViewById(R.id.multipleBaseTitle); + photosGrid = view.findViewById(R.id.multipleShareBackground); + baseTitle = view.findViewById(R.id.multipleBaseTitle); photosAdapter = new PhotoDisplayAdapter(); photosGrid.setAdapter(photosAdapter); @@ -189,8 +186,12 @@ public class MultipleUploadListFragment extends Fragment { } public void hideKeyboard(View view) { - InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index e93ac12d6..56d443d08 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -3,22 +3,20 @@ package fr.free.nrw.commons.upload; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; -import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; import android.support.v4.view.ViewCompat; import android.support.v7.app.AlertDialog; + import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; -import android.util.Log; + import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -186,9 +184,12 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { } public void hideKeyboard(View view) { - Log.i("hide", "hideKeyboard: "); - InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } } @Override @@ -303,11 +304,8 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { super.onStop(); // FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next - View target = getView().findFocus(); - if (target != null) { - InputMethodManager imm = (InputMethodManager) target.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(target.getWindowToken(), 0); - } + View target = getActivity().getCurrentFocus(); + hideKeyboard(target); } @NonNull From dcd767351bf45524d8d8c994b47aa0184f615f31 Mon Sep 17 00:00:00 2001 From: Anubhav Date: Tue, 1 May 2018 17:03:59 +0530 Subject: [PATCH 046/184] Deprecation removed --- app/quality.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/quality.gradle b/app/quality.gradle index 7ea20916a..1afdf0d68 100644 --- a/app/quality.gradle +++ b/app/quality.gradle @@ -18,7 +18,7 @@ task checkstyle(type: Checkstyle) { reports { html { enabled true - destination "${project.buildDir}/reports/checkstyle/checkstyle.html" + destination file("${project.buildDir}/reports/checkstyle/checkstyle.html") } } } @@ -36,10 +36,10 @@ task pmd(type: Pmd) { xml.enabled = false html.enabled = true xml { - destination "${project.buildDir}/reports/pmd/pmd.xml" + destination file("${project.buildDir}/reports/pmd/pmd.xml") } html { - destination "${project.buildDir}/reports/pmd/pmd.html" + destination file("${project.buildDir}/reports/pmd/pmd.html") } } } From d3597b80a684e7bd306be6ee53ef0e5a29fcb4cc Mon Sep 17 00:00:00 2001 From: Ujjwal Agrawal Date: Thu, 3 May 2018 02:47:56 +0530 Subject: [PATCH 047/184] Added hideKeyboard in ViewUtil (#1488) --- .../free/nrw/commons/auth/LoginActivity.java | 15 +++---------- .../category/CategorizationFragment.java | 15 ++----------- .../upload/MultipleUploadListFragment.java | 14 +++--------- .../nrw/commons/upload/ShareActivity.java | 10 ++------- .../commons/upload/SingleUploadFragment.java | 22 ++++--------------- .../fr/free/nrw/commons/utils/ViewUtil.java | 11 ++++++++++ 6 files changed, 25 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index 7b2b0a97f..d0fb628e3 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -47,6 +47,7 @@ import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.ui.widget.HtmlTextView; +import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -109,14 +110,14 @@ public class LoginActivity extends AccountAuthenticatorActivity { usernameEdit.addTextChangedListener(textWatcher); usernameEdit.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); passwordEdit.addTextChangedListener(textWatcher); passwordEdit.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); @@ -144,16 +145,6 @@ public class LoginActivity extends AccountAuthenticatorActivity { Utils.handleWebUrl(this,Uri.parse("https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\\")); } - public void hideKeyboard(View view) { - if (view != null) { - InputMethodManager inputMethodManager = (InputMethodManager) this.getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - } - - @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index 101d4b21e..e804189ab 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -1,7 +1,6 @@ package fr.free.nrw.commons.category; -import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; @@ -16,7 +15,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; @@ -43,6 +41,7 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.upload.MwVolleyApi; import fr.free.nrw.commons.utils.StringSortingUtils; +import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -116,7 +115,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { categoriesFilter.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); @@ -128,16 +127,6 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { return rootView; } - public void hideKeyboard(View view) { - - if (view != null) { - InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - } - @Override public void onDestroyView() { categoriesFilter.removeTextChangedListener(textWatcher); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index c7f3c39c0..4390bcef4 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -33,6 +33,7 @@ import dagger.android.support.AndroidSupportInjection; import fr.free.nrw.commons.R; import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.media.MediaDetailPagerFragment; +import fr.free.nrw.commons.utils.ViewUtil; public class MultipleUploadListFragment extends Fragment { @@ -129,7 +130,7 @@ public class MultipleUploadListFragment extends Fragment { // FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next View target = getActivity().getCurrentFocus(); - hideKeyboard(target); + ViewUtil.hideKeyboard(target); } // FIXME: Wrong result type @@ -178,22 +179,13 @@ public class MultipleUploadListFragment extends Fragment { baseTitle.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); return view; } - public void hideKeyboard(View view) { - if (view != null) { - InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - } - @Override public void onDestroyView() { baseTitle.removeTextChangedListener(textWatcher); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index aea703f5e..77f76fbed 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -78,6 +78,7 @@ import fr.free.nrw.commons.modifications.TemplateRemoveModifier; import fr.free.nrw.commons.utils.ImageUtils; import fr.free.nrw.commons.mwapi.MediaWikiApi; +import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; @@ -735,7 +736,7 @@ public class ShareActivity if (CurrentAnimator != null) { CurrentAnimator.cancel(); } - hideKeyboard(ShareActivity.this); + ViewUtil.hideKeyboard(ShareActivity.this.findViewById(R.id.titleEdit | R.id.descEdit)); InputStream input = null; Bitmap scaled = null; try { @@ -905,12 +906,5 @@ public class ShareActivity }); } - public static void hideKeyboard(Activity activity) { - View view = activity.findViewById(R.id.titleEdit | R.id.descEdit); - if (view != null) { - InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java index 56d443d08..a32fb7b42 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SingleUploadFragment.java @@ -1,8 +1,6 @@ package fr.free.nrw.commons.upload; import android.annotation.SuppressLint; -import android.app.Activity; - import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; @@ -11,12 +9,10 @@ import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.view.ViewCompat; import android.support.v7.app.AlertDialog; - import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.text.method.LinkMovementMethod; - import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -24,7 +20,6 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; @@ -47,9 +42,9 @@ import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.settings.Prefs; +import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; -import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; public class SingleUploadFragment extends CommonsDaggerSupportFragment { @@ -168,13 +163,13 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { titleEdit.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); descEdit.setOnFocusChangeListener((v, hasFocus) -> { if(!hasFocus){ - hideKeyboard(v); + ViewUtil.hideKeyboard(v); } }); @@ -183,15 +178,6 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { return rootView; } - public void hideKeyboard(View view) { - if (view != null) { - InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - } - } - @Override public void onDestroyView() { titleEdit.removeTextChangedListener(textWatcher); @@ -305,7 +291,7 @@ public class SingleUploadFragment extends CommonsDaggerSupportFragment { // FIXME: Stops the keyboard from being shown 'stale' while moving out of this fragment into the next View target = getActivity().getCurrentFocus(); - hideKeyboard(target); + ViewUtil.hideKeyboard(target); } @NonNull diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java index b4b26746b..1c45e8178 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -5,6 +5,7 @@ import android.content.Context; import android.support.design.widget.Snackbar; import android.view.Display; import android.view.View; +import android.view.inputmethod.InputMethodManager; import android.widget.Toast; public class ViewUtil { @@ -27,4 +28,14 @@ public class ViewUtil { } } + public static void hideKeyboard(View view){ + if (view != null) { + InputMethodManager manager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + view.clearFocus(); + if (manager != null) { + manager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + } + } From bcb90db16c89087e6bda308633ff173bebc54111 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 3 May 2018 09:21:58 +0200 Subject: [PATCH 048/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-diq/strings.xml | 3 +- app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-gl/strings.xml | 4 ++ app/src/main/res/values-ml/strings.xml | 94 ++++++++++++++++++++++--- app/src/main/res/values-ru/strings.xml | 1 + 6 files changed, 94 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 60339308c..f265e7ebd 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -154,6 +154,7 @@ Vermeide urheberrechtlich geschütztes Material, das du im Internet gefunden hast wie Bilder von Postern, Buchcovern etc. Verstanden? Ja! + Kategorien Lade … Keine ausgewählt diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index b88e412e7..2b66709f0 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -83,7 +83,7 @@ Peyd rışten bırış (E-posta ra) E-posta eyar nêbi Karıyaye Kategoriyê peyêni - Fına + Anciya bıcerrebne Bıtexelne Ron Lisans @@ -129,4 +129,5 @@ Keye Bar ke Veciyayış + Anciya bıcerrebne diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 759c44920..58aa93860 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -158,6 +158,7 @@ Αποφύγετε προστατευμένο υλικό που βρήκατε από το Internet, καθώς και εικόνες, αφίσες, εξώφυλλα βιβλίων, κλπ. Τι λες, μπορείς; Ναι! + Κατηγορίες Φόρτωση… Καμία επιλεγμένη diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index e7c3a37c2..630311db4 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -90,6 +90,7 @@ Categorías Configuracións Rexistrarse + Imaxes destacadas Acerca de A aplicación Wikimedia Commons é unha aplicación de código aberto creada e mantida polos cesionarios e voluntarios da comunidade de Wikimedia. A Fundación Wikimedia non está involucrada na creación, desenvolvemento ou mantemento da aplicación. Crear unha nova <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia</a> para informar de problemas e suxestións. @@ -175,6 +176,8 @@ Título do ficheiro multimedia Descrición Aquí vai a descrición do ficheiro multimedia. Potencialmente, pode ser bastante longo, e necesitará agruparse en múltiples liñas. De tódolos xeitos esperamos que se vexa ben. + Autor + O nome de usuario do autor da imaxe destacada vai aquí. Data de suba Licenza Coordenadas @@ -217,6 +220,7 @@ Saír Titorial Notificacións + Destacados Os sitios situados preto non poden visualizarse sen permisos de localización non se atopou descrición Páxina do ficheiro en Commons diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 485e66acc..632cc0265 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -5,15 +5,23 @@ * Santhosh.thottingal --> - വിക്കിമീഡിയ കോമൺസ് + ദൃശ്യരൂപം + സാർവത്രികം + പ്രതികരണം + സ്ഥലം + കോമൺസ് സജ്ജീകരണങ്ങൾ ഉപയോക്തൃനാമം രഹസ്യവാക്ക് + താങ്കളുടെ കോമൺസ് ബീറ്റ അംഗത്വത്തിൽ പ്രവേശിക്കുക പ്രവേശിക്കുക + രഹസ്യവാക്ക് മറന്നോ? + അംഗത്വമെടുക്കുക പ്രവേശിക്കുന്നു ദയവായി കാത്തിരിക്കുക… പ്രവേശനം വിജയകരം! പ്രവേശനം പരാജയപ്പെട്ടു! + പ്രമാണം കണ്ടെത്താനായില്ല. ദയവായി മറ്റൊരു പ്രമാണം നോക്കുക. സാധുതാനിർണ്ണയം പരാജയപ്പെട്ടു! അപ്‌ലോഡ് തുടങ്ങി! %1$s അപ്‌ലോഡ് ചെയ്തിരിക്കുന്നു! @@ -23,27 +31,30 @@ %1$s അപ്‌ലോഡിങ് പൂർത്തിയാക്കുന്നു %1$s അപ്‌ലോഡിങ് പരാജയപ്പെട്ടു കാണാനായി ടാപ് ചെയ്യുക - - 1 പ്രമാണം അപ്‌ലോഡ് ചെയ്യുന്നു + + ഒരു പ്രമാണം അപ്‌ലോഡ് ചെയ്യുന്നു %1$d പ്രമാണങ്ങൾ അപ്‌ലോഡ് ചെയ്യുന്നു - എന്റെ അപ്‌ലോഡുകൾ + എന്റെ സമീപകാല അപ്‌ലോഡുകൾ നിരയായി വെച്ചു പരാജയപ്പെട്ടു %1$d%% പൂർണ്ണം അപ്‌ലോഡ് ചെയ്തുകൊണ്ടിരിക്കുന്നു ചിത്രശാല ചിത്രം എടുക്കുക + സമീപസ്ഥം എന്റെ അപ്‌ലോഡുകൾ പങ്ക് വെയ്ക്കുക ബ്രൗസറിൽ കാണുക തലക്കെട്ട് + ഈ പ്രമാണത്തിന് ഒരു തലക്കെട്ട് നൽകുക. വിവരണം പ്രവേശിക്കാനായില്ല - നെറ്റ്‌വർക്ക് പരാജയപ്പെട്ടു പ്രവേശിക്കാനായില്ല - ദയവായി താങ്കളുടെ ഉപയോക്തൃനാമം പരിശോധിക്കുക പ്രവേശിക്കാനായില്ല - ദയവായി താങ്കളുടെ രഹസ്യവാക്ക് പരിശോധിക്കുക - നിരവധി വിജയകരമല്ലാത്ത ശ്രമങ്ങൾ നടന്നിരിക്കുന്നു. വീണ്ടും ശ്രമിക്കുന്നതിനു മുമ്പ് ഏതാനം മിനിറ്റുകൾ വിശ്രമിക്കുക + നിരവധി വിജയകരമല്ലാത്ത ശ്രമങ്ങൾ നടന്നിരിക്കുന്നു. വീണ്ടും ശ്രമിക്കുന്നതിനു മുമ്പ് ഏതാനം മിനിറ്റുകൾ വിശ്രമിക്കുക. ക്ഷമിക്കുക, ഈ ഉപയോക്താവ് കോമൺസിൽ നിന്ന് തടയപ്പെട്ടിരിക്കുകയാണ് + താങ്കളുടെ ദ്വി-ഘടക സാധൂകരണ കോഡ് നൽകുക. പ്രവേശനം പരാജയപ്പെട്ടു അപ്‌ലോഡ് ഈ ഗണത്തിന് പേരിടുക @@ -51,6 +62,11 @@ അപ്‌ലോഡ് വർഗ്ഗങ്ങളിൽ തിരയുക സേവ് ചെയ്യുക + പുതുക്കുക + പട്ടിക + താങ്കളുടെ ഉപകരണത്തിൽ ജി.പി.എസ്. പ്രവർത്തനരഹിതമാണ്. അത് പ്രവർത്തനസജ്ജമാക്കണോ? + ജി.പി.എസ്. സജ്ജമാക്കുക + ഇതുവരെ അപ്‌ലോഡുകൾ ഒന്നുമില്ല ഒരു അപ്‌ലോഡും ചെയ്തില്ല ഒരു അപ്‌ലോഡ് @@ -68,6 +84,8 @@ താങ്കളുടെ ചിത്രങ്ങൾ വിക്കിമീഡിയ കോമൺസിൽ കൂടുതൽ എളുപ്പത്തിൽ കണ്ടെത്തപ്പെടാനായി വർഗ്ഗങ്ങൾ ചേർക്കുക.\n\nവർഗ്ഗങ്ങൾ ചേർക്കാനായി ടൈപ്പ് ചെയ്ത് തുടങ്ങുക.\nഈ ഘട്ടം ഒഴിവാക്കാൻ ടാപ് ചെയ്യുക (അല്ലെങ്കിൽ പിന്നോട്ട് പോവുക). വർഗ്ഗങ്ങൾ സജ്ജീകരണങ്ങൾ + അംഗത്വമെടുക്കുക + തിരഞ്ഞെടുത്ത ചിത്രങ്ങൾ വിവരണം <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">അപാച്ചേ അനുമതിപത്രം പതിപ്പ് 2</a> പ്രകാരം പുറത്തിറക്കപ്പെട്ട ഓപ്പൺ സോഴ്സ് സോഫ്റ്റ്‌വേർ സ്രോതസ്സ് രൂപം <a href=\"https://github.com/commons-app/apps-android-commons\">ജിറ്റ്ഹബിൽ</a> ലഭ്യമാണ്.\nപ്രശ്നങ്ങൾ <a href=\" https://github.com/commons-app/apps-android-commons/issues\">ബഗ്സില്ലയിൽ</a> അറിയിക്കുക. @@ -81,9 +99,11 @@ റദ്ദാക്കുക ചിത്രം %1$s പ്രകാരം അനുമതി നൽകപ്പെടുന്നതാണ് ഡൗൺലോഡ് - അനുമതി - സി.സി. ആട്രിബ്യൂഷൻ-ഷെയർ‌എലൈക് 3.0 - സി.സി. ആട്രിബ്യൂഷൻ 3.0 + സ്വതേയുള്ള ഉപയോഗാനുമതി + ആട്രിബ്യൂഷൻ-ഷെയർ‌എലൈക് 4.0 + ആട്രിബ്യൂഷൻ 4.0 + ആട്രിബ്യൂഷൻ-ഷെയർ‌എലൈക് 3.0 + ആട്രിബ്യൂഷൻ 3.0 സി.സി.0 സി.സി. ബൈ-എസ്.എ. 3.0 സി.സി. ബൈ-എസ്.എ. 3.0 (ഓസ്ട്രിയ) @@ -97,6 +117,8 @@ സി.സി. ബൈ-എസ്.എ. 3.0 (പോളണ്ട്) സി.സി. ബൈ-എസ്.എ. 3.0 (റൊമേനിയ) സി.സി. ബൈ 3.0 + സി.സി. ബൈ-എസ്.എ. 4.0 + സി.സി. ബൈ 4.0 സി.സി. സീറോ താങ്കളെടുക്കുന്ന ചിത്രങ്ങൾ സംഭാവന ചെയ്യുക. വിക്കിപീഡിയ ലേഖനങ്ങൾ ജീവസ്സുറ്റതാക്കിത്തീർക്കുക! വിക്കിപീഡിയയിലുള്ള ചിത്രങ്ങൾ വിക്കിമീഡിയ കോമൺസിൽ നിന്നാണ് @@ -105,9 +127,63 @@ മനസ്സിലായോ? ശരി! വർഗ്ഗങ്ങൾ - ശേഖരിക്കുന്നു… + ശേഖരിക്കുന്നു… ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല വിവരണമൊന്നുമില്ല അജ്ഞാതമായ അനുമതി പുതുക്കുക + ശരി + സമീപ സ്ഥലങ്ങൾ + മുന്നറിയിപ്പ് + ഈ പ്രമാണം കോമൺസിൽ നിലവിലുണ്ട്. തുടരണം എന്ന് താങ്കൾക്കുറപ്പാണോ? + അതെ + അല്ല + ശീർഷകം + മീഡിയയുടെ തലക്കെട്ട് + വിവരണം + സ്രഷ്ടാവ് + അപ്‌ലോഡ് ചെയ്ത തീയതി + ഉപയോഗാനുമതി + നിർദ്ദേശാങ്കങ്ങൾ + ഒന്നും നൽകിയിട്ടില്ല + കോമൺസ് ലോഗോ + കോമൺസ് വെബ്‌സൈറ്റ് + പശ്ചാത്തല ചിത്രം + ചിത്രം അപ്‌ലോഡ് ചെയ്യുക + സാവോ പർവ്വതം + ലാമകൾ + മഴവിൽ പാലം + തുലിപ് + സെൽഫികൾ വേണ്ട + പകർപ്പവകാശ സംരക്ഷിത ചിത്രം + സിഡ്നി ഓപെറാ ഹൗസ് + റദ്ദാക്കുക + തുറക്കുക + അടയ്ക്കുക + പ്രധാനം + അപ്‌ലോഡ് + സമീപസ്ഥം + വിവരണം + സജ്ജീകരണങ്ങൾ + പ്രതികരണം + ലോഗൗട്ട് + സഹായം + അറിയിപ്പുകൾ + തിരഞ്ഞെടുക്കപ്പെട്ടത് + വിവരണങ്ങൾ ഒന്നും കണ്ടെത്തിയില്ല + കോമൺസ് പ്രമാണ താൾ + വിക്കിഡേറ്റാ ഇനം + വിക്കിപീഡിയ ലേഖനം + അനുമതി നൽകുക + താങ്കളുടെ അംഗത്വത്തിൽ പ്രവേശിക്കുക + ബ്രൗസറിൽ കാണുക + വിക്കിഡേറ്റാ + വിക്കിപീഡിയ + കോമൺസ് + <u>പതിവുചോദ്യങ്ങൾ</u> + <u>പരിഭാഷപ്പെടുത്തുക</u> + ഭാഷകൾ + തുടരുക + റദ്ദാക്കുക + വീണ്ടും ശ്രമിക്കുക diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c649398bb..4dc90489d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -170,6 +170,7 @@ Избегайте материалов, защищённых авторским правом, например, найденных в Интернете, изображений плакатов, книжных обложек и т.п. Вам это понятно? Да! + * Категории Загрузка… Ничего не выбрано From 693c37f2ece841e6a306113d76d900213f99b22e Mon Sep 17 00:00:00 2001 From: Ujjwal Agrawal Date: Fri, 4 May 2018 15:26:13 +0530 Subject: [PATCH 049/184] Updated share feature (#1474) --- app/src/main/java/fr/free/nrw/commons/AboutActivity.java | 3 ++- app/src/main/res/drawable/ic_share_black_24dp.xml | 4 ++-- app/src/main/res/menu/menu_about.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java index e6bf34736..65cba7531 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java @@ -135,9 +135,10 @@ public class AboutActivity extends NavigationBaseActivity { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.share_app_icon: + String shareText = "Upload photos to Wikimedia Commons on your phone\nDownload the Commons app: http://play.google.com/store/apps/details?id=fr.free.nrw.commons"; Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, "http://play.google.com/store/apps/details?id=fr.free.nrw.commons"); + sendIntent.putExtra(Intent.EXTRA_TEXT, shareText); sendIntent.setType("text/plain"); startActivity(Intent.createChooser(sendIntent, "Share app via...")); return true; diff --git a/app/src/main/res/drawable/ic_share_black_24dp.xml b/app/src/main/res/drawable/ic_share_black_24dp.xml index 01c81322d..203b1d84c 100644 --- a/app/src/main/res/drawable/ic_share_black_24dp.xml +++ b/app/src/main/res/drawable/ic_share_black_24dp.xml @@ -1,5 +1,5 @@ - + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/menu/menu_about.xml b/app/src/main/res/menu/menu_about.xml index e56fc3af2..fdd7ff6fd 100644 --- a/app/src/main/res/menu/menu_about.xml +++ b/app/src/main/res/menu/menu_about.xml @@ -7,7 +7,7 @@ Proceed Cancel Retry + Share App From d3057979d1b657332897f7540a1a170b08c7e800 Mon Sep 17 00:00:00 2001 From: Ashish Date: Fri, 4 May 2018 16:04:14 +0530 Subject: [PATCH 050/184] Implemented butterknife in MediaDetailFragment [issue #1491] --- .../commons/media/MediaDetailFragment.java | 96 ++++++++++++------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index e078a3d0e..29667c026 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -14,6 +14,9 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -48,24 +51,35 @@ public class MediaDetailFragment extends Fragment { return mf; } - private MediaWikiImageView image; - private MediaDetailSpacer spacer; private int initialListTop = 0; - private TextView title; - private TextView desc; - private TextView license; - private TextView coordinates; - private TextView uploadedDate; - private LinearLayout categoryContainer; - private ScrollView scrollView; + //Changed the access specifiers of these view as well [ButterKnife wont let us bind private variables] + @BindView(R.id.mediaDetailImage) + MediaWikiImageView image; + @BindView(R.id.mediaDetailSpacer) + MediaDetailSpacer spacer; + @BindView(R.id.mediaDetailTitle) + TextView title; + @BindView(R.id.mediaDetailDesc) + TextView desc; + @BindView(R.id.mediaDetailLicense) + TextView license; + @BindView(R.id.mediaDetailCoordinates) + TextView coordinates; + @BindView(R.id.mediaDetailuploadeddate) + TextView uploadedDate; + @BindView(R.id.mediaDetailCategoryContainer) + LinearLayout categoryContainer; + @BindView(R.id.mediaDetailScrollView) + ScrollView scrollView; + private ArrayList categoryNames; private boolean categoriesLoaded = false; private boolean categoriesPresent = false; private ViewTreeObserver.OnGlobalLayoutListener layoutListener; // for layout stuff, only used once! private ViewTreeObserver.OnScrollChangedListener scrollListener; DataSetObserver dataObserver; - private AsyncTask detailFetchTask; + private AsyncTask detailFetchTask; private LicenseList licenseList; @Override @@ -100,17 +114,7 @@ public class MediaDetailFragment extends Fragment { final View view = inflater.inflate(R.layout.fragment_media_detail, container, false); - image = (MediaWikiImageView) view.findViewById(R.id.mediaDetailImage); - scrollView = (ScrollView) view.findViewById(R.id.mediaDetailScrollView); - - // Detail consists of a list view with main pane in header view, plus category list. - spacer = (MediaDetailSpacer) view.findViewById(R.id.mediaDetailSpacer); - title = (TextView) view.findViewById(R.id.mediaDetailTitle); - desc = (TextView) view.findViewById(R.id.mediaDetailDesc); - license = (TextView) view.findViewById(R.id.mediaDetailLicense); - coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates); - uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate); - categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer); + ButterKnife.bind(this, view); licenseList = new LicenseList(getActivity()); @@ -271,22 +275,10 @@ public class MediaDetailFragment extends Fragment { private View buildCatLabel(String cat) { final String catName = cat; - final View item = getLayoutInflater(null).inflate(R.layout.detail_category_item, null, false); - final TextView textView = (TextView)item.findViewById(R.id.mediaDetailCategoryItemText); - - textView.setText(cat); - if (categoriesLoaded && categoriesPresent) { - textView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - String selectedCategoryTitle = "Category:" + catName; - Intent viewIntent = new Intent(); - viewIntent.setAction(Intent.ACTION_VIEW); - viewIntent.setData(Utils.uriForWikiPage(selectedCategoryTitle)); - startActivity(viewIntent); - } - }); - } + final View item = getLayoutInflater(null) + .inflate(R.layout.detail_category_item, null, false); + CategoryItemViewHolder categoryItemViewHolder = new CategoryItemViewHolder(item); + categoryItemViewHolder.init(catName); return item; } @@ -343,4 +335,34 @@ public class MediaDetailFragment extends Fragment { private String prettyCoordinates(Media media) { return media.getCoordinates(); } + + /** + * Holds the individual category item views + */ + + public class CategoryItemViewHolder { + + @BindView(R.id.mediaDetailCategoryItemText) + TextView mediaDetailCategoryItemText; + + private String categoryTitle; + + public CategoryItemViewHolder(View item) { + ButterKnife.bind(this, item); + } + + public void init(String categoryName) { + this.categoryTitle = categoryName; + mediaDetailCategoryItemText.setText(categoryName); + } + + @OnClick(R.id.mediaDetailCategoryItemText) + public void onCategoryItemClicked() { + String selectedCategoryTitle = "Category:" + categoryTitle; + Intent viewIntent = new Intent(); + viewIntent.setAction(Intent.ACTION_VIEW); + viewIntent.setData(Utils.uriForWikiPage(selectedCategoryTitle)); + startActivity(viewIntent); + } + } } From f7ad2cbf8f28420958d83e4ec88266b44dbf54c2 Mon Sep 17 00:00:00 2001 From: Ashish Date: Fri, 4 May 2018 19:05:35 +0530 Subject: [PATCH 051/184] Implemented butterknife in MediaDetailPagerFragment [[issue #1491]] --- .../free/nrw/commons/media/MediaDetailPagerFragment.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index c7e06cefa..7f061eba2 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -27,6 +27,8 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import butterknife.BindView; +import butterknife.ButterKnife; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.EventLog; import fr.free.nrw.commons.Media; @@ -35,7 +37,8 @@ import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.contributions.ContributionsActivity; public class MediaDetailPagerFragment extends Fragment implements ViewPager.OnPageChangeListener { - private ViewPager pager; + @BindView(R.id.mediaDetailsPager) + ViewPager pager; private Boolean editable; private CommonsApplication app; @@ -86,7 +89,7 @@ public class MediaDetailPagerFragment extends Fragment implements ViewPager.OnPa @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_media_detail_pager, container, false); - pager = (ViewPager) view.findViewById(R.id.mediaDetailsPager); + ButterKnife.bind(this,view); pager.addOnPageChangeListener(this); final MediaDetailAdapter adapter = new MediaDetailAdapter(getChildFragmentManager()); From f9989ba1a3dc545f227171cdf6230aefe03cc931 Mon Sep 17 00:00:00 2001 From: Ashish Date: Sat, 5 May 2018 14:03:59 +0530 Subject: [PATCH 052/184] post merge upstream master wip [[issue #1491]] --- .../commons/media/MediaDetailFragment.java | 196 ++++++++++-------- .../media/MediaDetailPagerFragment.java | 7 +- 2 files changed, 110 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 037f92e56..1bc165704 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -9,6 +9,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.TypedValue; import android.view.LayoutInflater; @@ -22,6 +23,9 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -74,23 +78,37 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Inject MediaWikiApi mwApi; - - private MediaWikiImageView image; - private MediaDetailSpacer spacer; private int initialListTop = 0; - private TextView title; - private TextView desc; - private TextView author; - private TextView license; - private TextView coordinates; - private TextView uploadedDate; - private TextView seeMore; - private LinearLayout nominatedforDeletion; - private LinearLayout categoryContainer; - private LinearLayout authorLayout; - private Button delete; - private ScrollView scrollView; + @BindView(R.id.mediaDetailImage) + MediaWikiImageView image; + @BindView(R.id.mediaDetailSpacer) + MediaDetailSpacer spacer; + @BindView(R.id.mediaDetailTitle) + TextView title; + @BindView(R.id.mediaDetailDesc) + TextView desc; + @BindView(R.id.mediaDetailAuthor) + TextView author; + @BindView(R.id.mediaDetailLicense) + TextView license; + @BindView(R.id.mediaDetailCoordinates) + TextView coordinates; + @BindView(R.id.mediaDetailuploadeddate) + TextView uploadedDate; + @BindView(R.id.seeMore) + TextView seeMore; + @BindView(R.id.nominatedDeletionBanner) + LinearLayout nominatedForDeletion; + @BindView(R.id.mediaDetailCategoryContainer) + LinearLayout categoryContainer; + @BindView(R.id.authorLinearLayout) + LinearLayout authorLayout; + @BindView(R.id.nominateDeletion) + Button delete; + @BindView(R.id.mediaDetailScrollView) + ScrollView scrollView; + private ArrayList categoryNames; private boolean categoriesLoaded = false; private boolean categoriesPresent = false; @@ -100,6 +118,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private AsyncTask detailFetchTask; private LicenseList licenseList; + //Had to make this class variable, to implement various onClicks, which access the media, also I fell why make separate variables when one can serve the purpose + private Media media; + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -136,22 +157,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { final View view = inflater.inflate(R.layout.fragment_media_detail, container, false); - image = (MediaWikiImageView) view.findViewById(R.id.mediaDetailImage); - scrollView = (ScrollView) view.findViewById(R.id.mediaDetailScrollView); - - // Detail consists of a list view with main pane in header view, plus category list. - spacer = (MediaDetailSpacer) view.findViewById(R.id.mediaDetailSpacer); - title = (TextView) view.findViewById(R.id.mediaDetailTitle); - desc = (TextView) view.findViewById(R.id.mediaDetailDesc); - author = (TextView) view.findViewById(R.id.mediaDetailAuthor); - license = (TextView) view.findViewById(R.id.mediaDetailLicense); - coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates); - uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate); - seeMore = (TextView) view.findViewById(R.id.seeMore); - nominatedforDeletion = (LinearLayout) view.findViewById(R.id.nominatedDeletionBanner); - delete = (Button) view.findViewById(R.id.nominateDeletion); - categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer); - authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); + ButterKnife.bind(this,view); if (isFeaturedMedia){ authorLayout.setVisibility(View.VISIBLE); @@ -195,7 +201,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Override public void onResume() { super.onResume(); - Media media = detailProvider.getMediaAtPosition(index); + media = detailProvider.getMediaAtPosition(index); if (media == null) { // Ask the detail provider to ping us when we're ready Timber.d("MediaDetailFragment not yet ready to display details; registering observer"); @@ -208,17 +214,18 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { Timber.d("MediaDetailFragment ready to display delayed details!"); detailProvider.unregisterDataSetObserver(dataObserver); dataObserver = null; - displayMediaDetails(detailProvider.getMediaAtPosition(index)); + media=detailProvider.getMediaAtPosition(index); + displayMediaDetails(); } }; detailProvider.registerDataSetObserver(dataObserver); } else { Timber.d("MediaDetailFragment ready to display details"); - displayMediaDetails(media); + displayMediaDetails(); } } - private void displayMediaDetails(final Media media) { + private void displayMediaDetails() { //Always load image from Internet to allow viewing the desc, license, and cats image.setMedia(media); @@ -255,7 +262,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (success) { extractor.fill(media); setTextFields(media); - setOnClickListeners(media); } else { Timber.d("Failed to load photo details."); } @@ -309,70 +315,77 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { checkDeletion(media); } - private void setOnClickListeners(final Media media) { - if (licenseLink(media) != null) { - license.setOnClickListener(v -> openWebBrowser(licenseLink(media))); + @OnClick(R.id.mediaDetailLicense) + public void onMediaDetailLicenceClicked(){ + if (!TextUtils.isEmpty(licenseLink(media))) { + openWebBrowser(licenseLink(media)); } else { Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); toast.show(); } + } + + @OnClick(R.id.mediaDetailCoordinates) + public void onMediaDetailCoordinatesClicked(){ if (media.getCoordinates() != null) { - coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); + openMap(media.getCoordinates()); } - if (delete.getVisibility() == View.VISIBLE) { - enableDeleteButton(true); + } - delete.setOnClickListener(v -> { + @OnClick(R.id.nominateDeletion) + public void onDeleteButtonClicked(){ + //Reviewer correct me if i have misunderstood something over here + //But how does this if (delete.getVisibility() == View.VISIBLE) { + // enableDeleteButton(true); makes sense ? + AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); + alert.setMessage("Why should this file be deleted?"); + final EditText input = new EditText(getActivity()); + alert.setView(input); + input.requestFocus(); + alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + String reason = input.getText().toString(); + DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); + deleteTask.execute(); + enableDeleteButton(false); + } + }); + alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }); + AlertDialog d = alert.create(); + input.addTextChangedListener(new TextWatcher() { + private void handleText() { + final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); + if (input.getText().length() == 0) { + okButton.setEnabled(false); + } else { + okButton.setEnabled(true); + } + } - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); - alert.setMessage("Why should this file be deleted?"); - final EditText input = new EditText(getActivity()); - alert.setView(input); - input.requestFocus(); - alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String reason = input.getText().toString(); - DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); - deleteTask.execute(); - enableDeleteButton(false); - } - }); - alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }); - AlertDialog d = alert.create(); - input.addTextChangedListener(new TextWatcher() { - private void handleText() { - final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); - if (input.getText().length() == 0) { - okButton.setEnabled(false); - } else { - okButton.setEnabled(true); - } - } + @Override + public void afterTextChanged(Editable arg0) { + handleText(); + } - @Override - public void afterTextChanged(Editable arg0) { - handleText(); - } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + }); + d.show(); + d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }); - d.show(); - d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - }); - } - if (nominatedforDeletion.getVisibility() == View.VISIBLE){ - seeMore.setOnClickListener(v -> { - openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); - }); + @OnClick(R.id.seeMore) + public void onSeeMoreClicked(){ + if(nominatedForDeletion.getVisibility()==View.VISIBLE) { + openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); } } @@ -477,11 +490,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private void checkDeletion(Media media){ if (media.getRequestedDeletion()){ delete.setVisibility(View.GONE); - nominatedforDeletion.setVisibility(View.VISIBLE); + nominatedForDeletion.setVisibility(View.VISIBLE); } else{ delete.setVisibility(View.VISIBLE); - nominatedforDeletion.setVisibility(View.GONE); + enableDeleteButton(true);//I believe this is to enable delete button and set its text color resemblance accordingly + nominatedForDeletion.setVisibility(View.GONE); } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index c0564c603..62d1261cf 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -26,6 +26,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; import javax.inject.Inject; import javax.inject.Named; @@ -53,7 +55,8 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple @Named("default_preferences") SharedPreferences prefs; - private ViewPager pager; + @BindView(R.id.mediaDetailsPager) + ViewPager pager; private Boolean editable; private boolean isFeaturedImage; @@ -72,7 +75,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_media_detail_pager, container, false); - pager = (ViewPager) view.findViewById(R.id.mediaDetailsPager); + ButterKnife.bind(this,view); pager.addOnPageChangeListener(this); final MediaDetailAdapter adapter = new MediaDetailAdapter(getChildFragmentManager()); From 228aa2129012a73fcedfd5271901d7102f9c763f Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Mon, 7 May 2018 04:05:55 +1000 Subject: [PATCH 053/184] Update contributing.md (#1477) --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0f1feeac7..5a8e7af19 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,14 @@ changed. It is also good to prefix the first line with "area: " where the "area" is a filename or identifier for the general area of the code being modified. The body should provide a meaningful commit message. +# Write Javadocs + +We require contributors to include Javadocs for all new methods and classes submitted via PRs (after 1 May 2018). This is aimed at making it easier for new contributors to dive into our codebase, especially those who are new to Android development. A few things to note: + +- This should not replace the need for code that is easily-readable in and of itself +- Please make sure that your Javadocs are reasonably descriptive, not just a copy of the method name +- Please do not use `@author` tags - we aim for collective code ownership, and if needed, GitHub allows us to see who wrote something without needing to add these tags + # Write tests for your code (if possible) # Make sure the Wiki pages don't become stale by updating them (if needed) From 96eae8c0a6dd2550aa9dc11dc9f330e24328438f Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 7 May 2018 07:54:16 +0200 Subject: [PATCH 054/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hu/strings.xml | 8 ++++++++ app/src/main/res/values-iw/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-pms/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 2 ++ app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + 13 files changed, 21 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f265e7ebd..36e013976 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -269,4 +269,5 @@ Fortfahren Abbrechen Erneut versuchen + App teilen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 58aa93860..0dae5c65e 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -273,4 +273,5 @@ Συνέχεια Ακύρωση Ξαναπροσπαθήστε + Κοινοποίηση εφαρμογής diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8494a7a36..442fc6bc5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -279,4 +279,5 @@ Continuer Annuler Réessayer + Partager les applications diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 5524afb0e..81e655b95 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -13,6 +13,7 @@ * ViDam --> + Megjelenés Általános Visszajelzés Helyszín @@ -145,6 +146,7 @@ Híres emberek (a polgármestered, olimpikonok, akikkel találkoztál) Kérjük, NE tölts fel: - Szelfiket vagy képeket a barátaidról\n- Internetröl letöltött képeket\n- Kereskedelmi alkalmazások képernyőképeit + Az Internetről letöltött képek Példa feltöltés: - Cím: Sydney-i Operaház\n- Leírás: A Sydney-i Operaház az öböl túlpartjáról\n- Kategóriák: Sydney Opera House from the west, Sydney Opera House remote views Cím: Sydney-i Operaház @@ -191,6 +193,7 @@ Commons Logo Commons weboldal Commons Facebook-oldal + Commons Github forráskód Háttérkép Nem található kép Kép feltöltése @@ -223,6 +226,8 @@ Hiba a képek gyorsítótárazásakor Egy egyedi, leíró cím a fájlnak, ami fájlnévként fog szolgálni. Egyszerű nyelvezetet használhatsz szóközökkel. Ne tedd bele a kiterjesztést. Kérlek a lehető legteljesebb módon írd le a fájlt: hol készült, mit ábrázol, mi a kontextus? Kérlek add meg az objektumokat vagy személyeket a képen, valamint a nehezen kitalálható információkat (például a kép készítésének dátumát, ha az egy tájkép). Amennyiben a média valami szokatlant ábrázol, kérlek fejtsd ki, hogy mi teszi szokatlanná. + Ez a fénykép túl sötét, biztos fel akarod tölteni? A Wikimédia Commons csak enciklopédikus értékkel bíró képeket tart meg. + Ez a fénykép homályos, biztos fel akarod tölteni? A Wikimédia Commons csak enciklopédikus értékkel bíró képeket tart meg. Engedély adása Külső tárhely használata Az alkalmazáson belüli kamerával készült képek mentése az eszközre @@ -238,6 +243,7 @@ A hely nem érhető el. Közeli helyek listájának megtekintéséhez engedély szükséges Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. + %1$s üzenetet hagyott a vitalapodon Köszönjük a szerkesztésedet! WIKIDATA WIKIPÉDIA @@ -249,6 +255,8 @@ Internet elérhető Nincs értesítés Nyelvek + Folytatás Mégse Újra + Alkalmazás megosztása diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 48750daf9..762a3be31 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -273,4 +273,5 @@ המשך ביטול לנסות שוב + שיתוף היישום diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 11faee9c6..d0e1c21ed 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -266,4 +266,5 @@ 진행 취소 다시 시도 + 앱 공유 diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index dd1e6f03e..4e44dad60 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -263,4 +263,5 @@ Продолжи Откажи Пробај пак + Сподели прилог diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 0cd748031..30115f1ad 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -263,4 +263,5 @@ Andé anans Anulé Prové torna + Partagé j\'aplicassion diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 4bc478527..6722ae4bb 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -275,4 +275,5 @@ Avançar Cancelar Tentar novamente + Compartilhar o aplicativo diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 5e4862ecb..b0717f3dc 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -159,6 +159,7 @@ Evite materiais protegidos por direitos de autor que tenham sido encontrados na Internet, bem como imagens de cartazes, capas de livros, etc. Acha que conseguiu? Sim! + Categorias A carregar… Nenhuma selecionada diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index fa5174ced..24ef60b61 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -156,6 +156,7 @@ Undvik upphovsrättsskyddat material som du hittar på Internet, samt bilder av affischer, bokomslag, etc. Tror du att du förstår? Ja! + Kategorier Läser in… Ingen markerad @@ -270,4 +271,5 @@ Fortsätt Avbryt Försök igen + Dela app diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4966d9c08..a2878cddf 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -271,4 +271,5 @@ 已進行 取消 重試 + 分享應用程式 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 83650b408..d3d049ea2 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -269,4 +269,5 @@ 已处理 取消 重试 + 分享应用 From 9845a6265d7a1339998413fe1770931264a1af34 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Mon, 7 May 2018 13:39:23 +0530 Subject: [PATCH 055/184] Integrate API for displaying featured images (#1456) * Integrate API for displaying featured images * Add pagination and refactor code so that it can be reused for category images * Add license info to the images * Fix author view * Remove unused values * Fix minor issues with featured images * Fix null license url issue * Remove some log lines * Fix back navigation issue * fix tests * fix test inits * Gracefully handling various error situations * Added java docs --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 5 +- .../category/CategoryImageController.java | 29 +++ .../commons/category/CategoryImageUtils.java | 225 +++++++++++++++++ .../category/CategoryImagesActivity.java | 160 ++++++++++++ .../category/CategoryImagesListFragment.java | 227 ++++++++++++++++++ .../nrw/commons/category/GridViewAdapter.java | 88 +++++++ .../nrw/commons/category/QueryContinue.java | 24 ++ .../nrw/commons/di/ActivityBuilderModule.java | 4 +- .../commons/di/CommonsApplicationModule.java | 30 ++- .../nrw/commons/di/FragmentBuilderModule.java | 4 +- .../nrw/commons/featured/FeaturedImage.java | 44 ---- .../featured/FeaturedImagesActivity.java | 114 --------- .../featured/FeaturedImagesListFragment.java | 52 ---- .../commons/featured/MockGridViewAdapter.java | 50 ---- .../commons/media/MediaDetailFragment.java | 31 ++- .../mwapi/ApacheHttpClientMediaWikiApi.java | 98 +++++++- .../free/nrw/commons/mwapi/MediaWikiApi.java | 3 + .../commons/theme/NavigationBaseActivity.java | 7 +- .../free/nrw/commons/utils/ContinueUtils.java | 15 ++ ...mages.xml => activity_category_images.xml} | 11 +- ...mages.xml => fragment_category_images.xml} | 15 +- ..._images.xml => layout_category_images.xml} | 10 +- app/src/main/res/values/strings.xml | 4 + .../nrw/commons/TestCommonsApplication.kt | 5 +- .../mwapi/ApacheHttpClientMediaWikiApiTest.kt | 5 +- 26 files changed, 953 insertions(+), 309 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java rename app/src/main/res/layout/{activity_featured_images.xml => activity_category_images.xml} (69%) rename app/src/main/res/layout/{fragment_featured_images.xml => fragment_category_images.xml} (70%) rename app/src/main/res/layout/{layout_featured_images.xml => layout_category_images.xml} (88%) diff --git a/app/build.gradle b/app/build.gradle index 535f58143..9c6f62fd4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,8 @@ dependencies { implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0' implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' + implementation 'org.jsoup:jsoup:1.11.3' + implementation 'com.facebook.fresco:fresco:1.5.0' implementation 'com.facebook.stetho:stetho:1.5.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6aab09b55..17f6770d2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -92,8 +92,9 @@ android:label="@string/navigation_item_notification" /> + android:name=".category.CategoryImagesActivity" + android:label="@string/title_activity_featured_images" + android:parentActivityName=".contributions.ContributionsActivity" /> diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java new file mode 100644 index 000000000..3495d710c --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java @@ -0,0 +1,29 @@ +package fr.free.nrw.commons.category; + +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.mwapi.MediaWikiApi; + +@Singleton +public class CategoryImageController { + + private MediaWikiApi mediaWikiApi; + + @Inject + public CategoryImageController(MediaWikiApi mediaWikiApi) { + this.mediaWikiApi = mediaWikiApi; + } + + /** + * Takes a category name as input and calls the API to get a list of images for that category + * @param categoryName + * @return + */ + public List getCategoryImages(String categoryName) { + return mediaWikiApi.getCategoryImages(categoryName); + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java new file mode 100644 index 000000000..18749847e --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java @@ -0,0 +1,225 @@ +package fr.free.nrw.commons.category; + +import org.jsoup.Jsoup; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.annotation.Nullable; + +import fr.free.nrw.commons.Media; +import timber.log.Timber; + +public class CategoryImageUtils { + + /** + * The method iterates over the child nodes to return a list of Media objects + * @param childNodes + * @return + */ + public static List getMediaList(NodeList childNodes) { + List categoryImages = new ArrayList<>(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + categoryImages.add(getMediaFromPage(node)); + } + + return categoryImages; + } + + /** + * Creates a new Media object from the XML response as received by the API + * @param node + * @return + */ + private static Media getMediaFromPage(Node node) { + Media media = new Media(null, + getImageUrl(node), + getFileName(node), + getDescription(node), + getDataLength(node), + getDateCreated(node), + getDateCreated(node), + getCreator(node) + ); + + media.setLicense(getLicense(node)); + + return media; + } + + /** + * Extracts the filename of the uploaded image + * @param document + * @return + */ + private static String getFileName(Node document) { + Element element = (Element) document; + return element.getAttribute("title"); + } + + /** + * Extracts the image description for that particular upload + * @param document + * @return + */ + private static String getDescription(Node document) { + return getMetaDataValue(document, "ImageDescription"); + } + + /** + * Extracts license information from the image meta data + * @param document + * @return + */ + private static String getLicense(Node document) { + return getMetaDataValue(document, "License"); + } + + /** + * Returns the parsed value of artist from the response + * The artist information is returned as a HTML string from the API. Jsoup library parses the HTML string + * to extract just the text value + * @param document + * @return + */ + private static String getCreator(Node document) { + String artist = getMetaDataValue(document, "Artist"); + if (artist != null) { + return Jsoup.parse(artist).text(); + } + return null; + } + + /** + * Returns the parsed date of creation of the image + * @param document + * @return + */ + private static Date getDateCreated(Node document) { + String dateTime = getMetaDataValue(document, "DateTime"); + if (dateTime != null && !dateTime.equals("")) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + return format.parse(dateTime); + } catch (ParseException e) { + Timber.d("Error occurred while parsing date %s", dateTime); + return new Date(); + } + } + return new Date(); + } + + /** + * @param document + * @return Returns the url attribute from the imageInfo node + */ + private static String getImageUrl(Node document) { + Element element = (Element) getImageInfo(document); + if (element != null) { + return element.getAttribute("url"); + } + return null; + } + + /** + * Takes the node document and gives out the attribute length from the node document + * @param document + * @return + */ + private static long getDataLength(Node document) { + Element element = (Element) document; + if (element != null) { + String length = element.getAttribute("length"); + if (length != null && !length.equals("")) { + return Long.parseLong(length); + } + } + return 0L; + } + + /** + * Generic method to get the value of any meta as returned by the getMetaData function + * @param document node document as returned by API + * @param metaName the name of meta node to be returned + * @return + */ + private static String getMetaDataValue(Node document, String metaName) { + Element metaData = getMetaData(document, metaName); + if (metaData != null) { + return metaData.getAttribute("value"); + } + return null; + } + + /** + * Generic method to return an element taking the node document and metaName as input + * @param document node document as returned by API + * @param metaName the name of meta node to be returned + * @return + */ + @Nullable + private static Element getMetaData(Node document, String metaName) { + Node extraMetaData = getExtraMetaData(document); + if (extraMetaData != null) { + Node node = getNode(extraMetaData, metaName); + if (node != null) { + return (Element) node; + } + } + return null; + } + + /** + * Extracts extmetadata from the response XML + * @param document + * @return + */ + @Nullable + private static Node getExtraMetaData(Node document) { + Node imageInfo = getImageInfo(document); + if (imageInfo != null) { + return getNode(imageInfo, "extmetadata"); + } + return null; + } + + /** + * Extracts the ii node from the imageinfo node + * @param document + * @return + */ + @Nullable + private static Node getImageInfo(Node document) { + Node imageInfo = getNode(document, "imageinfo"); + if (imageInfo != null) { + return getNode(imageInfo, "ii"); + } + return null; + } + + /** + * Takes a parent node as input and returns a child node if present + * @param node parent node + * @param nodeName child node name + * @return + */ + @Nullable + public static Node getNode(Node node, String nodeName) { + NodeList childNodes = node.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node nodeItem = childNodes.item(i); + Element item = (Element) nodeItem; + if (item.getTagName().equals(nodeName)) { + return nodeItem; + } + } + return null; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java new file mode 100644 index 000000000..1f385b258 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java @@ -0,0 +1,160 @@ +package fr.free.nrw.commons.category; + +import android.content.Context; +import android.content.Intent; +import android.database.DataSetObserver; +import android.os.Bundle; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.view.View; +import android.widget.AdapterView; + +import butterknife.ButterKnife; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.auth.AuthenticatedActivity; +import fr.free.nrw.commons.media.MediaDetailPagerFragment; +import timber.log.Timber; + +/** + * This activity displays pictures of a particular category + * Its generic and simply takes the name of category name in its start intent to load all images in + * a particular category. This activity is currently being used to display a list of featured images, + * which is nothing but another category on wikimedia commons. + */ + +public class CategoryImagesActivity + extends AuthenticatedActivity + implements FragmentManager.OnBackStackChangedListener, + MediaDetailPagerFragment.MediaDetailProvider, + AdapterView.OnItemClickListener{ + + + private FragmentManager supportFragmentManager; + private CategoryImagesListFragment categoryImagesListFragment; + private MediaDetailPagerFragment mediaDetails; + + @Override + protected void onAuthCookieAcquired(String authCookie) { + + } + + @Override + protected void onAuthFailure() { + + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_category_images); + ButterKnife.bind(this); + + // Activity can call methods in the fragment by acquiring a + // reference to the Fragment from FragmentManager, using findFragmentById() + supportFragmentManager = getSupportFragmentManager(); + setCategoryImagesFragment(); + supportFragmentManager.addOnBackStackChangedListener(this); + if (savedInstanceState != null) { + mediaDetails = (MediaDetailPagerFragment) supportFragmentManager + .findFragmentById(R.id.fragmentContainer); + + } + requestAuthToken(); + initDrawer(); + setPageTitle(); + } + + /** + * Gets the categoryName from the intent and initializes the fragment for showing images of that category + */ + private void setCategoryImagesFragment() { + categoryImagesListFragment = new CategoryImagesListFragment(); + String categoryName = getIntent().getStringExtra("categoryName"); + if (getIntent() != null && categoryName != null) { + Bundle arguments = new Bundle(); + arguments.putString("categoryName", categoryName); + categoryImagesListFragment.setArguments(arguments); + FragmentTransaction transaction = supportFragmentManager.beginTransaction(); + transaction + .add(R.id.fragmentContainer, categoryImagesListFragment) + .commit(); + } + } + + /** + * Gets the passed title from the intents and displays it as the page title + */ + private void setPageTitle() { + if (getIntent() != null && getIntent().getStringExtra("title") != null) { + setTitle(getIntent().getStringExtra("title")); + } + } + + @Override + public void onBackStackChanged() { + } + + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (mediaDetails == null || !mediaDetails.isVisible()) { + // set isFeaturedImage true for featured images, to include author field on media detail + mediaDetails = new MediaDetailPagerFragment(false, true); + FragmentManager supportFragmentManager = getSupportFragmentManager(); + supportFragmentManager + .beginTransaction() + .replace(R.id.fragmentContainer, mediaDetails) + .addToBackStack(null) + .commit(); + supportFragmentManager.executePendingTransactions(); + } + mediaDetails.showImage(i); + } + + /** + * Consumers should be simply using this method to use this activity. + * @param context + * @param title Page title + * @param categoryName Name of the category for displaying its images + */ + public static void startYourself(Context context, String title, String categoryName) { + Intent intent = new Intent(context, CategoryImagesActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + intent.putExtra("title", title); + intent.putExtra("categoryName", categoryName); + context.startActivity(intent); + } + + @Override + public Media getMediaAtPosition(int i) { + if (categoryImagesListFragment.getAdapter() == null) { + // not yet ready to return data + return null; + } else { + return (Media) categoryImagesListFragment.getAdapter().getItem(i); + } + } + + @Override + public int getTotalMediaCount() { + if (categoryImagesListFragment.getAdapter() == null) { + return 0; + } + return categoryImagesListFragment.getAdapter().getCount(); + } + + @Override + public void notifyDatasetChanged() { + + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java new file mode 100644 index 000000000..3b6734edd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java @@ -0,0 +1,227 @@ +package fr.free.nrw.commons.category; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ListAdapter; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import dagger.android.support.DaggerFragment; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.utils.NetworkUtils; +import fr.free.nrw.commons.utils.ViewUtil; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; +import timber.log.Timber; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +/** + * Displays images for a particular category with load more on scrolling incorporated + */ +public class CategoryImagesListFragment extends DaggerFragment { + + private static int TIMEOUT_SECONDS = 15; + + private GridViewAdapter gridAdapter; + + @BindView(R.id.statusMessage) + TextView statusTextView; + @BindView(R.id.loadingImagesProgressBar) ProgressBar progressBar; + @BindView(R.id.categoryImagesList) GridView gridView; + + private boolean hasMoreImages = true; + private boolean isLoading; + private String categoryName = null; + + @Inject CategoryImageController controller; + @Inject @Named("category_prefs") SharedPreferences categoryPreferences; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_category_images, container, false); + ButterKnife.bind(this, v); + return v; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); + initViews(); + } + + /** + * Initializes the UI elements for the fragment + * Setup the grid view to and scroll listener for it + */ + private void initViews() { + String categoryName = getArguments().getString("categoryName"); + if (getArguments() != null && categoryName != null) { + this.categoryName = categoryName; + resetQueryContinueValues(categoryName); + initList(); + setScrollListener(); + } + } + + /** + * Query continue values determine the last page that was loaded for the particular keyword + * This method resets those values, so that the results can be queried from the first page itself + * @param keyword + */ + private void resetQueryContinueValues(String keyword) { + SharedPreferences.Editor editor = categoryPreferences.edit(); + editor.remove(keyword); + editor.apply(); + } + + /** + * Checks for internet connection and then initializes the grid view with first 10 images of that category + */ + @SuppressLint("CheckResult") + private void initList() { + if(!NetworkUtils.isInternetConnectionEstablished(getContext())) { + handleNoInternet(); + return; + } + + isLoading = true; + progressBar.setVisibility(VISIBLE); + Observable.fromCallable(() -> controller.getCategoryImages(categoryName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) + .subscribe(this::handleSuccess, this::handleError); + } + + /** + * Handles the UI updates for no internet scenario + */ + private void handleNoInternet() { + progressBar.setVisibility(GONE); + if (gridAdapter == null || gridAdapter.isEmpty()) { + statusTextView.setVisibility(VISIBLE); + statusTextView.setText(getString(R.string.no_internet)); + } else { + ViewUtil.showSnackbar(gridView, R.string.no_internet); + } + } + + /** + * Logs and handles API error scenario + * @param throwable + */ + private void handleError(Throwable throwable) { + Timber.e(throwable, "Error occurred while loading featured images"); + initErrorView(); + } + + /** + * Handles the UI updates for a error scenario + */ + private void initErrorView() { + ViewUtil.showSnackbar(gridView, R.string.error_loading_images); + progressBar.setVisibility(GONE); + if (gridAdapter == null || gridAdapter.isEmpty()) { + statusTextView.setVisibility(VISIBLE); + statusTextView.setText(getString(R.string.no_images_found)); + } else { + statusTextView.setVisibility(GONE); + } + } + + /** + * Initializes the adapter with a list of Media objects + * @param mediaList + */ + private void setAdapter(List mediaList) { + gridAdapter = new GridViewAdapter(this.getContext(), R.layout.layout_category_images, mediaList); + gridView.setAdapter(gridAdapter); + } + + /** + * Sets the scroll listener for the grid view so that more images are fetched when the user scrolls down + * Checks if the category has more images before loading + * Also checks whether images are currently being fetched before triggering another request + */ + private void setScrollListener() { + gridView.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (hasMoreImages && !isLoading && (firstVisibleItem + visibleItemCount + 1 >= totalItemCount)) { + isLoading = true; + fetchMoreImages(); + } + } + }); + } + + /** + * Fetches more images for the category and adds it to the grid view adapter + */ + @SuppressLint("CheckResult") + private void fetchMoreImages() { + if(!NetworkUtils.isInternetConnectionEstablished(getContext())) { + handleNoInternet(); + return; + } + + progressBar.setVisibility(VISIBLE); + Observable.fromCallable(() -> controller.getCategoryImages(categoryName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) + .subscribe(this::handleSuccess, this::handleError); + } + + /** + * Handles the success scenario + * On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter + * @param collection + */ + private void handleSuccess(List collection) { + if(collection == null || collection.isEmpty()) { + initErrorView(); + hasMoreImages = false; + return; + } + + if(gridAdapter == null) { + setAdapter(collection); + } else { + gridAdapter.addItems(collection); + } + + progressBar.setVisibility(GONE); + isLoading = false; + statusTextView.setVisibility(GONE); + } + + public ListAdapter getAdapter() { + return gridView.getAdapter(); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java new file mode 100644 index 000000000..c8e6066f6 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java @@ -0,0 +1,88 @@ +package fr.free.nrw.commons.category; + +import android.app.Activity; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.MediaWikiImageView; +import fr.free.nrw.commons.R; + +/** + * This is created to only display UI implementation. Needs to be changed in real implementation + */ + +public class GridViewAdapter extends ArrayAdapter { + private Context context; + private List data; + + public GridViewAdapter(Context context, int layoutResourceId, List data) { + super(context, layoutResourceId, data); + this.context = context; + this.data = data; + } + + /** + * Adds more item to the list + * Its triggered on scrolling down in the list + * @param images + */ + public void addItems(List images) { + if (data == null) { + data = new ArrayList<>(); + } + data.addAll(images); + notifyDataSetChanged(); + } + + @Override + public boolean isEmpty() { + return data == null || data.isEmpty(); + } + + /** + * Sets up the UI for the category image item + * @param position + * @param convertView + * @param parent + * @return + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + if (convertView == null) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + convertView = inflater.inflate(R.layout.layout_category_images, null); + } + + Media item = data.get(position); + MediaWikiImageView imageView = convertView.findViewById(R.id.categoryImageView); + TextView fileName = convertView.findViewById(R.id.categoryImageTitle); + TextView author = convertView.findViewById(R.id.categoryImageAuthor); + fileName.setText(item.getFilename()); + setAuthorView(item, author); + imageView.setMedia(item); + return convertView; + } + + /** + * Shows author information if its present + * @param item + * @param author + */ + private void setAuthorView(Media item, TextView author) { + if (item.getCreator() != null && !item.getCreator().equals("")) { + String uploadedByTemplate = context.getString(R.string.image_uploaded_by); + author.setText(String.format(uploadedByTemplate, item.getCreator())); + } else { + author.setVisibility(View.GONE); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java b/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java new file mode 100644 index 000000000..e12d5a778 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java @@ -0,0 +1,24 @@ +package fr.free.nrw.commons.category; + +/** + * For APIs that return paginated responses, MediaWiki APIs uses the QueryContinue to facilitate fetching of subsequent pages + * https://www.mediawiki.org/wiki/API:Raw_query_continue + */ +public class QueryContinue { + private String continueParam; + private String gcmContinueParam; + + public QueryContinue(String continueParam, String gcmContinueParam) { + this.continueParam = continueParam; + this.gcmContinueParam = gcmContinueParam; + } + + public String getGcmContinueParam() { + return gcmContinueParam; + } + + public String getContinueParam() { + return continueParam; + } +} + diff --git a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java index f88f3b34a..51aa85903 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java @@ -7,7 +7,7 @@ import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.auth.SignupActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; -import fr.free.nrw.commons.featured.FeaturedImagesActivity; +import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.settings.SettingsActivity; @@ -49,5 +49,5 @@ public abstract class ActivityBuilderModule { abstract NotificationActivity bindNotificationActivity(); @ContributesAndroidInjector - abstract FeaturedImagesActivity bindFeaturedImagesActivity(); + abstract CategoryImagesActivity bindFeaturedImagesActivity(); } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index e8b915c7e..55281be7e 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -6,6 +6,8 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.v4.util.LruCache; +import com.google.gson.Gson; + import javax.inject.Named; import javax.inject.Singleton; @@ -85,6 +87,17 @@ public class CommonsApplicationModule { return context.getSharedPreferences("prefs", MODE_PRIVATE); } + /** + * + * @param context + * @return returns categoryPrefs + */ + @Provides + @Named("category_prefs") + public SharedPreferences providesCategorySharedPreferences(Context context) { + return context.getSharedPreferences("categoryPrefs", MODE_PRIVATE); + } + @Provides @Named("direct_nearby_upload_prefs") public SharedPreferences providesDirectNearbyUploadPreferences(Context context) { @@ -106,8 +119,11 @@ public class CommonsApplicationModule { @Provides @Singleton - public MediaWikiApi provideMediaWikiApi(Context context, @Named("default_preferences") SharedPreferences sharedPreferences) { - return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, sharedPreferences); + public MediaWikiApi provideMediaWikiApi(Context context, + @Named("default_preferences") SharedPreferences defaultPreferences, + @Named("category_prefs") SharedPreferences categoryPrefs, + Gson gson) { + return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, defaultPreferences, categoryPrefs, gson); } @Provides @@ -116,6 +132,16 @@ public class CommonsApplicationModule { return new LocationServiceManager(context); } + /** + * Gson objects are very heavy. The app should ideally be using just one instance of it instead of creating new instances everywhere. + * @return returns a singleton Gson instance + */ + @Provides + @Singleton + public Gson provideGson() { + return new Gson(); + } + @Provides @Singleton public CacheController provideCacheController() { diff --git a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java index c5cdcb5a7..dfed64871 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java @@ -4,7 +4,7 @@ import dagger.Module; import dagger.android.ContributesAndroidInjector; import fr.free.nrw.commons.category.CategorizationFragment; import fr.free.nrw.commons.contributions.ContributionsListFragment; -import fr.free.nrw.commons.featured.FeaturedImagesListFragment; +import fr.free.nrw.commons.category.CategoryImagesListFragment; import fr.free.nrw.commons.media.MediaDetailFragment; import fr.free.nrw.commons.media.MediaDetailPagerFragment; import fr.free.nrw.commons.nearby.NearbyListFragment; @@ -49,6 +49,6 @@ public abstract class FragmentBuilderModule { abstract SingleUploadFragment bindSingleUploadFragment(); @ContributesAndroidInjector - abstract FeaturedImagesListFragment bindFeaturedImagesListFragment(); + abstract CategoryImagesListFragment bindFeaturedImagesListFragment(); } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java deleted file mode 100644 index 853fba29e..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.free.nrw.commons.featured; - - -import fr.free.nrw.commons.Media; - -/** - * Object to hold FeaturedImage - */ - -public class FeaturedImage { - private Media image; - private String author; - private String fileName; - - public FeaturedImage(Media image, String author, String fileName) { - this.image = image; - this.author = author; - this.fileName = fileName; - } - - public Media getImage() { - return image; - } - - public void setImage(Media image) { - this.image = image; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java deleted file mode 100644 index a2dc7b00b..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.database.DataSetObserver; -import android.os.Bundle; -import android.support.v4.app.FragmentManager; -import android.view.View; -import android.widget.AdapterView; - -import butterknife.ButterKnife; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.auth.AuthenticatedActivity; -import fr.free.nrw.commons.media.MediaDetailPagerFragment; - -/** - * This activity displays pic of the days of last xx days - */ - -public class FeaturedImagesActivity - extends AuthenticatedActivity - implements FragmentManager.OnBackStackChangedListener, - MediaDetailPagerFragment.MediaDetailProvider, - AdapterView.OnItemClickListener{ - - private FeaturedImagesListFragment featuredImagesListFragment; - private MediaDetailPagerFragment mediaDetails; - - @Override - protected void onAuthCookieAcquired(String authCookie) { - - } - - @Override - protected void onAuthFailure() { - - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_featured_images); - ButterKnife.bind(this); - - // Activity can call methods in the fragment by acquiring a - // reference to the Fragment from FragmentManager, using findFragmentById() - FragmentManager supportFragmentManager = getSupportFragmentManager(); - featuredImagesListFragment = (FeaturedImagesListFragment)supportFragmentManager - .findFragmentById(R.id.featuedListFragment); - - supportFragmentManager.addOnBackStackChangedListener(this); - if (savedInstanceState != null) { - mediaDetails = (MediaDetailPagerFragment)supportFragmentManager - .findFragmentById(R.id.featuredFragmentContainer); - - } - requestAuthToken(); - initDrawer(); - setTitle(getString(R.string.title_activity_featured_images)); - } - - @Override - public void onBackStackChanged() { - - } - - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - if (mediaDetails == null || !mediaDetails.isVisible()) { - // set isFeaturedImage true for featured images, to include author field on media detail - mediaDetails = new MediaDetailPagerFragment(false, true); - FragmentManager supportFragmentManager = getSupportFragmentManager(); - supportFragmentManager - .beginTransaction() - .replace(R.id.featuredFragmentContainer, mediaDetails) - .addToBackStack(null) - .commit(); - supportFragmentManager.executePendingTransactions(); - } - mediaDetails.showImage(i); - } - - @Override - public Media getMediaAtPosition(int i) { - if (featuredImagesListFragment.getAdapter() == null) { - // not yet ready to return data - return null; - } else { - return ((FeaturedImage)featuredImagesListFragment.getAdapter().getItem(i)).getImage(); - } - } - - @Override - public int getTotalMediaCount() { - if (featuredImagesListFragment.getAdapter() == null) { - return 0; - } - return featuredImagesListFragment.getAdapter().getCount(); - } - - @Override - public void notifyDatasetChanged() { - - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java deleted file mode 100644 index 19e33b0ee..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ /dev/null @@ -1,52 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.GridView; -import android.widget.ListAdapter; - -import java.util.ArrayList; - -import butterknife.ButterKnife; -import dagger.android.support.DaggerFragment; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.R; - -public class FeaturedImagesListFragment extends DaggerFragment { - private GridView gridView; - private MockGridViewAdapter gridAdapter; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_featured_images, container, false); - ButterKnife.bind(this, v); - return v; - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - gridView = getView().findViewById(R.id.featuredImagesList); - gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); - gridAdapter = new MockGridViewAdapter(this.getContext(), R.layout.layout_featured_images, getMockFeaturedImages()); - gridView.setAdapter(gridAdapter); - - } - - private ArrayList getMockFeaturedImages(){ - ArrayList featuredImages = new ArrayList<>(); - for (int i=0; i<10; i++){ - featuredImages.add(new FeaturedImage(new Media("test.jpg"), "username: test", "test file name")); - } - return featuredImages; - } - - public ListAdapter getAdapter() { - return gridView.getAdapter(); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java deleted file mode 100644 index 7aa2a8892..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import java.util.ArrayList; - -import fr.free.nrw.commons.MediaWikiImageView; -import fr.free.nrw.commons.R; - -/** - * This is created to only display UI implementation. Needs to be changed in real implementation - */ - -public class MockGridViewAdapter extends ArrayAdapter { - private Context context; - private int layoutResourceId; - private ArrayList data = new ArrayList(); - - public MockGridViewAdapter(Context context, int layoutResourceId, ArrayList data) { - super(context, layoutResourceId, data); - this.layoutResourceId = layoutResourceId; - this.context = context; - this.data = data; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - - if (convertView == null) { - LayoutInflater inflater = ((Activity) context).getLayoutInflater(); - convertView = inflater.inflate(R.layout.layout_featured_images, null); - } - - FeaturedImage item = data.get(position); - MediaWikiImageView imageView = convertView.findViewById(R.id.featuredImageView); - TextView fileName = convertView.findViewById(R.id.featuredImageTitle); - TextView author = convertView.findViewById(R.id.featuredImageAuthor); - fileName.setText("Test file name"); - author.setText("Uploaded by: Test user name"); - imageView.setMedia(item.getImage()); - return convertView; - } - -} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 037f92e56..c3a977ab5 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -45,6 +45,7 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.ui.widget.CompatTextView; import timber.log.Timber; +import static android.view.View.*; import static android.widget.Toast.LENGTH_SHORT; public class MediaDetailFragment extends CommonsDaggerSupportFragment { @@ -154,9 +155,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); if (isFeaturedMedia){ - authorLayout.setVisibility(View.VISIBLE); + authorLayout.setVisibility(VISIBLE); } else { - authorLayout.setVisibility(View.GONE); + authorLayout.setVisibility(GONE); } licenseList = new LicenseList(getActivity()); @@ -306,6 +307,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { } rebuildCatList(); + if(media.getCreator() == null || media.getCreator().equals("")) { + authorLayout.setVisibility(GONE); + } else { + author.setText(media.getCreator()); + } + checkDeletion(media); } @@ -313,13 +320,17 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (licenseLink(media) != null) { license.setOnClickListener(v -> openWebBrowser(licenseLink(media))); } else { - Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); - toast.show(); + if(isFeaturedMedia) { + Timber.d("Unable to fetch license URL for %s", media.getLicense()); + } else { + Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); + toast.show(); + } } if (media.getCoordinates() != null) { coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); } - if (delete.getVisibility() == View.VISIBLE) { + if (delete.getVisibility() == VISIBLE) { enableDeleteButton(true); delete.setOnClickListener(v -> { @@ -369,7 +380,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); }); } - if (nominatedforDeletion.getVisibility() == View.VISIBLE){ + if (nominatedforDeletion.getVisibility() == VISIBLE){ seeMore.setOnClickListener(v -> { openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); }); @@ -476,12 +487,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private void checkDeletion(Media media){ if (media.getRequestedDeletion()){ - delete.setVisibility(View.GONE); - nominatedforDeletion.setVisibility(View.VISIBLE); + delete.setVisibility(GONE); + nominatedforDeletion.setVisibility(VISIBLE); } else{ - delete.setVisibility(View.VISIBLE); - nominatedforDeletion.setVisibility(View.GONE); + delete.setVisibility(VISIBLE); + nominatedforDeletion.setVisibility(GONE); } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 78051abd8..6629d0933 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -9,6 +9,8 @@ import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; +import com.google.gson.Gson; + import org.apache.http.HttpResponse; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; @@ -38,7 +40,10 @@ import java.util.Locale; import java.util.concurrent.Callable; import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.Media; import fr.free.nrw.commons.PageTitle; +import fr.free.nrw.commons.category.CategoryImageUtils; +import fr.free.nrw.commons.category.QueryContinue; import fr.free.nrw.commons.notification.Notification; import fr.free.nrw.commons.notification.NotificationUtils; import in.yuvi.http.fluent.Http; @@ -46,6 +51,8 @@ import io.reactivex.Observable; import io.reactivex.Single; import timber.log.Timber; +import static fr.free.nrw.commons.utils.ContinueUtils.getQueryContinue; + /** * @author Addshore */ @@ -56,9 +63,15 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { private AbstractHttpClient httpClient; private MWApi api; private Context context; - private SharedPreferences sharedPreferences; + private SharedPreferences defaultPreferences; + private SharedPreferences categoryPreferences; + private Gson gson; - public ApacheHttpClientMediaWikiApi(Context context, String apiURL, SharedPreferences sharedPreferences) { + public ApacheHttpClientMediaWikiApi(Context context, + String apiURL, + SharedPreferences defaultPreferences, + SharedPreferences categoryPreferences, + Gson gson) { this.context = context; BasicHttpParams params = new BasicHttpParams(); SchemeRegistry schemeRegistry = new SchemeRegistry(); @@ -69,7 +82,9 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { params.setParameter(CoreProtocolPNames.USER_AGENT, getUserAgent()); httpClient = new DefaultHttpClient(cm, params); api = new MWApi(apiURL, httpClient); - this.sharedPreferences = sharedPreferences; + this.defaultPreferences = defaultPreferences; + this.categoryPreferences = categoryPreferences; + this.gson = gson; } @Override @@ -160,7 +175,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { } private void setAuthCookieOnLogin(boolean isLoggedIn) { - SharedPreferences.Editor editor = sharedPreferences.edit(); + SharedPreferences.Editor editor = defaultPreferences.edit(); if (isLoggedIn) { editor.putBoolean("isUserLoggedIn", true); editor.putString("getAuthCookie", api.getAuthCookie()); @@ -448,6 +463,81 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { return NotificationUtils.getNotificationsFromList(context, childNodes); } + /** + * The method takes categoryName as input and returns a List of Media objects + * It uses the generator query API to get the images in a category, 10 at a time. + * Uses the query continue values for fetching paginated responses + * @param categoryName Category name as defined on commons + * @return + */ + @Override + @NonNull + public List getCategoryImages(String categoryName) { + ApiResult apiResult = null; + try { + MWApi.RequestBuilder requestBuilder = api.action("query") + .param("generator", "categorymembers") + .param("format", "xml") + .param("gcmtype", "file") + .param("gcmtitle", categoryName) + .param("prop", "imageinfo") + .param("gcmlimit", "10") + .param("iiprop", "url|extmetadata"); + + QueryContinue queryContinueValues = getQueryContinueValues(categoryName); + if (queryContinueValues != null) { + requestBuilder.param("continue", queryContinueValues.getContinueParam()); + requestBuilder.param("gcmcontinue", queryContinueValues.getGcmContinueParam()); + } + + apiResult = requestBuilder.get(); + } catch (IOException e) { + Timber.e("Failed to obtain searchCategories", e); + } + + if (apiResult == null) { + return new ArrayList<>(); + } + + ApiResult categoryImagesNode = apiResult.getNode("/api/query/pages"); + if (categoryImagesNode == null + || categoryImagesNode.getDocument() == null + || categoryImagesNode.getDocument().getChildNodes() == null + || categoryImagesNode.getDocument().getChildNodes().getLength() == 0) { + return new ArrayList<>(); + } + + QueryContinue queryContinue = getQueryContinue(apiResult.getNode("/api/continue").getDocument()); + setQueryContinueValues(categoryName, queryContinue); + + NodeList childNodes = categoryImagesNode.getDocument().getChildNodes(); + return CategoryImageUtils.getMediaList(childNodes); + } + + /** + * For APIs that return paginated responses, MediaWiki APIs uses the QueryContinue to facilitate fetching of subsequent pages + * https://www.mediawiki.org/wiki/API:Raw_query_continue + * After fetching images a page of image for a particular category, shared prefs are updated with the latest QueryContinue Values + * @param keyword + * @param queryContinue + */ + private void setQueryContinueValues(String keyword, QueryContinue queryContinue) { + SharedPreferences.Editor editor = categoryPreferences.edit(); + editor.putString(keyword, gson.toJson(queryContinue)); + editor.apply(); + } + + /** + * Before making a paginated API call, this method is called to get the latest query continue values to be used + * @param keyword + * @return + */ + @Nullable + private QueryContinue getQueryContinueValues(String keyword) { + String queryContinueString = categoryPreferences.getString(keyword, null); + return gson.fromJson(queryContinueString, QueryContinue.class); + } + @Override public boolean existingFile(String fileSha1) throws IOException { return api.action("query") diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index fd213455d..c0bd2fd87 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; +import fr.free.nrw.commons.Media; import fr.free.nrw.commons.notification.Notification; import io.reactivex.Observable; import io.reactivex.Single; @@ -34,6 +35,8 @@ public interface MediaWikiApi { boolean logEvents(LogBuilder[] logBuilders); + List getCategoryImages(String categoryName); + @NonNull UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, ProgressListener progressListener) throws IOException; diff --git a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java index acd9b7646..4a7322b57 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java @@ -23,12 +23,11 @@ import fr.free.nrw.commons.AboutActivity; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; -import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; -import fr.free.nrw.commons.featured.FeaturedImagesActivity; +import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.settings.SettingsActivity; @@ -37,6 +36,8 @@ import timber.log.Timber; public abstract class NavigationBaseActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener { + private static final String FEATURED_IMAGES_CATEGORY = "Category:Featured_pictures_on_Wikimedia_Commons"; + @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.navigation_view) @@ -157,7 +158,7 @@ public abstract class NavigationBaseActivity extends BaseActivity return true; case R.id.action_featured_images: drawerLayout.closeDrawer(navigationView); - startActivityWithFlags(this, FeaturedImagesActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + CategoryImagesActivity.startYourself(this, getString(R.string.title_activity_featured_images), FEATURED_IMAGES_CATEGORY); return true; default: Timber.e("Unknown option [%s] selected from the navigation menu", itemId); diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java new file mode 100644 index 000000000..b05c8bc45 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java @@ -0,0 +1,15 @@ +package fr.free.nrw.commons.utils; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import fr.free.nrw.commons.category.QueryContinue; + +public class ContinueUtils { + + public static QueryContinue getQueryContinue(Node document) { + Element continueElement = (Element) document; + return new QueryContinue(continueElement.getAttribute("continue"), + continueElement.getAttribute("gcmcontinue")); + } +} diff --git a/app/src/main/res/layout/activity_featured_images.xml b/app/src/main/res/layout/activity_category_images.xml similarity index 69% rename from app/src/main/res/layout/activity_featured_images.xml rename to app/src/main/res/layout/activity_category_images.xml index 755fe4983..c329e4458 100644 --- a/app/src/main/res/layout/activity_featured_images.xml +++ b/app/src/main/res/layout/activity_category_images.xml @@ -1,6 +1,5 @@ - - diff --git a/app/src/main/res/layout/fragment_featured_images.xml b/app/src/main/res/layout/fragment_category_images.xml similarity index 70% rename from app/src/main/res/layout/fragment_featured_images.xml rename to app/src/main/res/layout/fragment_category_images.xml index ca45f44c3..001f0a780 100644 --- a/app/src/main/res/layout/fragment_featured_images.xml +++ b/app/src/main/res/layout/fragment_category_images.xml @@ -1,20 +1,21 @@ - + android:background="?attr/mainBackground"> @@ -33,7 +33,7 @@ android:padding="@dimen/small_gap" > Proceed Cancel Retry + + No images found! + Error occurred while loading images. + Uploaded by: %1$s Share App diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt index 73760dd40..b1de29143 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons import android.content.Context import android.content.SharedPreferences import android.support.v4.util.LruCache +import com.google.gson.Gson import com.nhaarman.mockito_kotlin.mock import com.squareup.leakcanary.RefWatcher import fr.free.nrw.commons.auth.AccountUtil @@ -36,6 +37,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu val accountUtil: AccountUtil = mock() val appSharedPreferences: SharedPreferences = mock() val defaultSharedPreferences: SharedPreferences = mock() + val categorySharedPreferences: SharedPreferences = mock() val otherSharedPreferences: SharedPreferences = mock() val uploadController: UploadController = mock() val mockSessionManager: SessionManager = mock() @@ -45,6 +47,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu val mockDbOpenHelper: DBOpenHelper = mock() val nearbyPlaces: NearbyPlaces = mock() val lruCache: LruCache = mock() + val gson: Gson = Gson() override fun providesAccountUtil(context: Context): AccountUtil = accountUtil @@ -58,7 +61,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu override fun providesSessionManager(context: Context, mediaWikiApi: MediaWikiApi, sharedPreferences: SharedPreferences): SessionManager = mockSessionManager - override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences): MediaWikiApi = mediaWikiApi + override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences, categorySharedPreferences: SharedPreferences, gson: Gson): MediaWikiApi = mediaWikiApi override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt index c51d354c2..686a90ef2 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons.mwapi import android.content.SharedPreferences import android.os.Build import android.preference.PreferenceManager +import com.google.gson.Gson import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.TestCommonsApplication import okhttp3.mockwebserver.MockResponse @@ -26,12 +27,14 @@ class ApacheHttpClientMediaWikiApiTest { private lateinit var testObject: ApacheHttpClientMediaWikiApi private lateinit var server: MockWebServer private lateinit var sharedPreferences: SharedPreferences + private lateinit var categoryPreferences: SharedPreferences @Before fun setUp() { server = MockWebServer() sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) - testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences) + categoryPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) + testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences, categoryPreferences, Gson()) testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/") } From e36ebfeffe6ced16f364101ca7356908bae015f5 Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Mon, 7 May 2018 19:27:14 +1000 Subject: [PATCH 056/184] Update pull_request_template.md (#1476) * Update pull_request_template.md * Remove Javadocs mention * Added required/optional notes --- PULL_REQUEST_TEMPLATE.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 34078f07e..9d7150008 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,15 @@ -## Description +## Description (required) -Fixes #{GitHub issue number} +Fixes #{GitHub issue number and title} {Describe the changes made and why they were made.} -## Tests performed +## Tests performed (required) Tested on {API level & name of device/emulator}, with {build variant, e.g. ProdDebug}. -{Please test your PR at least once before submitting.} - -## Screenshots showing what changed +## Screenshots showing what changed (optional) {Only for user interface changes, otherwise remove this section. See [how to take a screenshot](https://android.stackexchange.com/questions/1759/how-to-take-a-screenshot-with-an-android-device)} + +_Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._ From bd86dde4442cbe2f60628a1a99ebb5b01df17de4 Mon Sep 17 00:00:00 2001 From: Man Parvesh Singh Randhawa Date: Mon, 7 May 2018 17:32:11 +0800 Subject: [PATCH 057/184] resolves #1464 : MediaDataExtractor is making inefficient (redundant) server calls (#1496) --- app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java index 2d79a6c4f..affb57528 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java @@ -61,8 +61,8 @@ public class MediaDataExtractor { } try{ - Timber.d("Nominated for deletion: " + mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename)); - deletionStatus = mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename); + deletionStatus = mediaWikiApi.pageExists("Commons:Deletion_requests/" + filename); + Timber.d("Nominated for deletion: " + deletionStatus); } catch (Exception e){ Timber.d(e.getMessage()); From 4f6b791c936b6559018bd5c35ea7783f6b01c688 Mon Sep 17 00:00:00 2001 From: Tanvi Dadu Date: Mon, 7 May 2018 15:27:59 +0530 Subject: [PATCH 058/184] Open map of place where picture was taken (#1360) * Intent to map added * Merge conflicts resolved * Added the functionality to hide FAB incase of null coordinate * Merge Conflict resolved * Improve pr quality * Improve Quality * Added nested FAB animations * Nested FAB implemented * Improve Quality * Added up arrow * Javadocs Added --- .../nrw/commons/upload/ShareActivity.java | 105 +++++++++++++++++- .../ic_keyboard_arrow_up_black_24dp.xml | 5 + app/src/main/res/layout/activity_share.xml | 27 ++++- app/src/main/res/values/dimens.xml | 2 + app/src/main/res/values/strings.xml | 2 + 5 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 77f76fbed..6a59c8e30 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -81,8 +81,7 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; - - +import android.support.design.widget.FloatingActionButton; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; import static java.lang.Long.min; @@ -122,6 +121,7 @@ public class ShareActivity private Uri mediaUri; private Contribution contribution; private SimpleDraweeView backgroundImageView; + private FloatingActionButton maps_fragment; private boolean cacheFound; @@ -145,6 +145,8 @@ public class ShareActivity private long ShortAnimationDuration; private FloatingActionButton zoomInButton; private FloatingActionButton zoomOutButton; + private FloatingActionButton mainFab; + private boolean isFABOpen = false; /** @@ -284,6 +286,24 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } + + mainFab = (FloatingActionButton) findViewById(R.id.main_fab); + /* + * called when upper arrow floating button + */ + mainFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(!isFABOpen){ + showFABMenu(); + }else{ + closeFABMenu(); + } + } + }); + + + zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); try { zoomInButton.setOnClickListener(new View.OnClickListener() { @@ -358,7 +378,74 @@ public class ShareActivity .commitAllowingStateLoss(); } uploadController.prepareService(); + maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); + maps_fragment.setVisibility(View.VISIBLE); + if( imageObj == null || imageObj.imageCoordsExists != true){ + maps_fragment.setVisibility(View.INVISIBLE); + } + + + maps_fragment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if( imageObj != null && imageObj.imageCoordsExists == true) { + Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + startActivity(mapIntent); + } + } + }); } + /* + * Function to display the zoom and map FAB + */ + private void showFABMenu(){ + isFABOpen=true; + + if( imageObj != null && imageObj.imageCoordsExists == true) + maps_fragment.setVisibility(View.VISIBLE); + zoomInButton.setVisibility(View.VISIBLE); + + mainFab.animate().rotationBy(180); + maps_fragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); + zoomInButton.animate().translationY(-getResources().getDimension(R.dimen.first_fab)); + } + + /* + * function to close the zoom and map FAB + */ + private void closeFABMenu(){ + isFABOpen=false; + mainFab.animate().rotationBy(-180); + maps_fragment.animate().translationY(0); + zoomInButton.animate().translationY(0).setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + + } + + @Override + public void onAnimationEnd(Animator animator) { + if(!isFABOpen){ + maps_fragment.setVisibility(View.GONE); + zoomInButton.setVisibility(View.GONE); + } + + } + + @Override + public void onAnimationCancel(Animator animator) { + + } + + @Override + public void onAnimationRepeat(Animator animator) { + + } + }); + } + @Override public void onRequestPermissionsResult(int requestCode, @@ -461,6 +548,9 @@ public class ShareActivity detectUnwantedPicturesAsync.execute(); } + /* + * to display permission snackbar in share activity + */ private Snackbar requestPermissionUsingSnackBar(String rationale, final String[] perms, final int code) { @@ -693,7 +783,9 @@ public class ShareActivity return super.onOptionsItemSelected(item); } - // Get SHA1 of file from input stream + /* + * Get SHA1 of file from input stream + */ private String getSHA1(InputStream is) { MessageDigest digest; @@ -730,6 +822,9 @@ public class ShareActivity } } + /* + * function to provide pinch zoom + */ private void zoomImageFromThumb(final View thumbView, Uri imageuri ) { // If there's an animation in progress, cancel it // immediately and proceed with this one. @@ -737,6 +832,8 @@ public class ShareActivity CurrentAnimator.cancel(); } ViewUtil.hideKeyboard(ShareActivity.this.findViewById(R.id.titleEdit | R.id.descEdit)); + closeFABMenu(); + mainFab.setVisibility(View.GONE); InputStream input = null; Bitmap scaled = null; try { @@ -866,7 +963,7 @@ public class ShareActivity CurrentAnimator.cancel(); } zoomOutButton.setVisibility(View.GONE); - zoomInButton.setVisibility(View.VISIBLE); + mainFab.setVisibility(View.VISIBLE); // Animate the four positioning/sizing properties in parallel, // back to their original values. diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml new file mode 100644 index 000000000..bc010396b --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml index ca8097495..b6e523239 100644 --- a/app/src/main/res/layout/activity_share.xml +++ b/app/src/main/res/layout/activity_share.xml @@ -41,8 +41,6 @@ - - + + + + + + + 20sp 16sp 14sp + 15dp + 25dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e83fefd1..00bfafdad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -275,4 +275,6 @@ Error occurred while loading images. Uploaded by: %1$s Share App + Coordinates were not specified during image selection + From 2a98bd21ceff3241f2a4e4515ed56753be784415 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 7 May 2018 15:05:20 +0300 Subject: [PATCH 059/184] Add nearby tutorial (#1467) * Add dependency for MaterialShowcase * Add actionview class to get a reference to material showcase * Create a NearbyMaterialShowcaseSequence class * Apply sequence steps * Add first three steps of nearby showcase * Add sequence id constants to make sure they will be displayed only once * Add last step of sequence to explain plus fab * Create an object to prevent customize all sequences every time * Fix typo * Code cleanup * Add strings to strings.xml * Code cleanup * Revert irrelevant change * Revert irrelevant change * Remove showcaseview for recenter button * Use single showcaseView instead of sequence * Add single showcase view insted of sequence to be able to edit text style * Make sure it will be displayed only once * Cleanup * Update strings * Change dismiss text style --- app/build.gradle | 2 + .../nrw/commons/nearby/NearbyActivity.java | 91 ++++++++++++++++++- .../nrw/commons/nearby/NearbyMapFragment.java | 32 ++++++- .../NearbyMaterialShowcaseSequence.java | 18 ++++ .../fr/free/nrw/commons/utils/ViewUtil.java | 4 + app/src/main/res/values/strings.xml | 6 ++ 6 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java diff --git a/app/build.gradle b/app/build.gradle index 9c6f62fd4..5d37f8f54 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,8 @@ dependencies { transitive=true } + implementation "com.github.deano2390:MaterialShowcaseView:1.2.0" + implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION" implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION" implementation "com.android.support:design:$SUPPORT_LIB_VERSION" diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 2a423de93..3bf8beacf 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -4,14 +4,18 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; + import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -25,6 +29,7 @@ import com.google.gson.GsonBuilder; import java.util.List; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; @@ -41,6 +46,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import timber.log.Timber; +import uk.co.deanwild.materialshowcaseview.IShowcaseListener; +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener { @@ -56,12 +63,15 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp LinearLayout bottomSheetDetails; @BindView(R.id.transparentView) View transparentView; + @BindView(R.id.fab_recenter) + View fabRecenter; @Inject LocationServiceManager locationManager; @Inject NearbyController nearbyController; - + @Inject + @Named("application_preferences") SharedPreferences applicationPrefs; private LatLng curLatLng; private Bundle bundle; private Disposable placesDisposable; @@ -72,11 +82,18 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp private NearbyListFragment nearbyListFragment; private static final String TAG_RETAINED_MAP_FRAGMENT = NearbyMapFragment.class.getSimpleName(); private static final String TAG_RETAINED_LIST_FRAGMENT = NearbyListFragment.class.getSimpleName(); + private View listButton; // Reference to list button to use in tutorial private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private BroadcastReceiver broadcastReceiver; + + private boolean isListShowcaseAdded = false; + private boolean isMapShowCaseAdded = false; + private LatLng lastKnownLocation; + private MaterialShowcaseView secondSingleShowCaseView; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -126,6 +143,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_nearby, menu); + new Handler().post(() -> { + + listButton = findViewById(R.id.action_display_list); + + secondSingleShowCaseView = new MaterialShowcaseView.Builder(this) + .setTarget(listButton) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_list_icon)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_1) // provide a unique ID used to ensure it is only shown once + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .setListener(new IShowcaseListener() { + @Override + public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) { + + } + + // If dismissed, we can inform fragment to start showcase sequence there + @Override + public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) { + nearbyMapFragment.onNearbyMaterialShowcaseDismissed(); + } + }) + .build(); + + isListShowcaseAdded = true; + + if (isMapShowCaseAdded) { // If map showcase is also ready, start ShowcaseSequence + // Probably this case is not possible. Just added to be careful + setMapViewTutorialShowCase(); + } + }); + return super.onCreateOptionsMenu(menu); } @@ -420,6 +470,45 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp updateMapFragment(false); updateListFragment(); } + + isMapShowCaseAdded = true; + } + + public void setMapViewTutorialShowCase() { + /* + *This showcase view will be the first step of our nearbyMaterialShowcaseSequence. The reason we use a + * single item instead of adding another step to nearbyMaterialShowcaseSequence is that we are not able to + * call withoutShape() method on steps. For mapView we need an showcase view without + * any circle on it, it should cover the whole page. + * */ + MaterialShowcaseView firstSingleShowCaseView = new MaterialShowcaseView.Builder(this) + .setTarget(nearbyMapFragment.mapView) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_whole_nearby_activity)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_2) // provide a unique ID used to ensure it is only shown once + .withoutShape() // no shape on map view since there are no view to focus on + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .setListener(new IShowcaseListener() { + @Override + public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) { + + } + + @Override + public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) { + /* Add other nearbyMaterialShowcaseSequence here, it will make the user feel as they are a + * nearbyMaterialShowcaseSequence whole together. + * */ + secondSingleShowCaseView.show(NearbyActivity.this); + } + }) + .build(); + + if (applicationPrefs.getBoolean("firstRunNearby", true)) { + applicationPrefs.edit().putBoolean("firstRunNearby", false).apply(); + firstSingleShowCaseView.show(this); + } } private void lockNearbyView(boolean lock) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 431132436..69041d286 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Color; +import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; @@ -58,13 +59,14 @@ import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.utils.UriDeserializer; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; import static android.app.Activity.RESULT_OK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; public class NearbyMapFragment extends DaggerFragment { - private MapView mapView; + public MapView mapView; private List baseMarkerOptions; private fr.free.nrw.commons.location.LatLng curLatLng; public fr.free.nrw.commons.location.LatLng[] boundaryCoordinates; @@ -111,6 +113,10 @@ public class NearbyMapFragment extends DaggerFragment { private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04; + private boolean isSecondMaterialShowcaseDismissed; + private boolean isMapReady; + private MaterialShowcaseView thirdSingleShowCaseView; + private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location @Inject @@ -163,7 +169,6 @@ public class NearbyMapFragment extends DaggerFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Timber.d("onCreateView called"); if (curLatLng != null) { Timber.d("curLatLng found, setting up map view..."); @@ -476,6 +481,7 @@ public class NearbyMapFragment extends DaggerFragment { mapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(MapboxMap mapboxMap) { + ((NearbyActivity)getActivity()).setMapViewTutorialShowCase(); NearbyMapFragment.this.mapboxMap = mapboxMap; updateMapSignificantly(); } @@ -519,6 +525,7 @@ public class NearbyMapFragment extends DaggerFragment { private void addNearbyMarkerstoMapBoxMap() { mapboxMap.addMarkers(baseMarkerOptions); + mapboxMap.setOnInfoWindowCloseListener(marker -> { if (marker == selected) { bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); @@ -534,6 +541,7 @@ public class NearbyMapFragment extends DaggerFragment { }); mapboxMap.setOnMarkerClickListener(marker -> { + if (marker instanceof NearbyMarker) { this.selected = marker; NearbyMarker nearbyMarker = (NearbyMarker) marker; @@ -541,6 +549,7 @@ public class NearbyMapFragment extends DaggerFragment { passInfoToSheet(place); bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } return false; }); @@ -634,7 +643,19 @@ public class NearbyMapFragment extends DaggerFragment { addAnchorToSmallFABs(fabGallery, getActivity().findViewById(R.id.empty_view).getId()); addAnchorToSmallFABs(fabCamera, getActivity().findViewById(R.id.empty_view1).getId()); + thirdSingleShowCaseView = new MaterialShowcaseView.Builder(this.getActivity()) + .setTarget(fabPlus) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_plus_fab)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_3) // provide a unique ID used to ensure it is only shown once + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .build(); + isMapReady = true; + if (isSecondMaterialShowcaseDismissed) { + thirdSingleShowCaseView.show(getActivity()); + } } @@ -791,6 +812,13 @@ public class NearbyMapFragment extends DaggerFragment { this.bundleForUpdtes = bundleForUpdtes; } + public void onNearbyMaterialShowcaseDismissed() { + isSecondMaterialShowcaseDismissed = true; + if (isMapReady) { + thirdSingleShowCaseView.show(getActivity()); + } + } + @Override public void onStart() { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java new file mode 100644 index 000000000..c6e46611d --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java @@ -0,0 +1,18 @@ +package fr.free.nrw.commons.nearby; + +import android.app.Activity; + +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseSequence; +import uk.co.deanwild.materialshowcaseview.ShowcaseConfig; + + +public class NearbyMaterialShowcaseSequence extends MaterialShowcaseSequence { + + public NearbyMaterialShowcaseSequence(Activity activity, String sequenceID) { + super(activity, sequenceID); + ShowcaseConfig config = new ShowcaseConfig(); + config.setDelay(500); // half second between each showcase view + this.setConfig(config); + this.singleUse(sequenceID); // Display tutorial only once + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java index 1c45e8178..0c22a40a2 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -10,6 +10,10 @@ import android.widget.Toast; public class ViewUtil { + public static final String SHOWCASE_VIEW_ID_1 = "SHOWCASE_VIEW_ID_1"; + public static final String SHOWCASE_VIEW_ID_2 = "SHOWCASE_VIEW_ID_2"; + public static final String SHOWCASE_VIEW_ID_3 = "SHOWCASE_VIEW_ID_3"; + public static void showSnackbar(View view, int messageResourceId) { Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00bfafdad..dcea51bcc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -271,9 +271,15 @@ Cancel Retry + Got it! + These are the places near you that need pictures to illustrate their Wikipedia articles + Tapping this button brings up a list of these places + You can upload a picture for any place from your gallery or camera + No images found! Error occurred while loading images. Uploaded by: %1$s + Share App Coordinates were not specified during image selection From cbca264dbcae19a67ea27f7cdac226116f750b06 Mon Sep 17 00:00:00 2001 From: Kaartic Sivaraam Date: Tue, 8 May 2018 06:34:09 +0000 Subject: [PATCH 060/184] CONTRIBUTING: fix formatting of the gist of the guidelines (#1453) * CONTRIBUTING: fix formatting of the gist of the guidelines First level headings for a gist seems to be overkill. So, replace first level headings with an ordered-list which sounds more meaningful. * CONTRIBUTING: specify clearly that 'blame' is a feature of "Git" The contributing file specifies about the ability to know who wrote something without the need of @author javadoc tags but incorrectly attributes the feature to GitHub. Correctly attribute the feature to where it belongs, Git, and specify the name of the feature to help users easily take advantage of it. --- CONTRIBUTING.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a8e7af19..caa02a103 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,23 +5,30 @@ If you're not sure where to start head on to [this wiki page](https://github.com Here's a gist of the guidelines, -# Make separate commits for logically separate changes +1. Make separate commits for logically separate changes -# Describe your changes well in the commit message +1. Describe your changes well in the commit message -The first line of the commit message should be a short description of what has + The first line of the commit message should be a short description of what has changed. It is also good to prefix the first line with "area: " where the "area" is a filename or identifier for the general area of the code being modified. The body should provide a meaningful commit message. -# Write Javadocs +1. Write Javadocs -We require contributors to include Javadocs for all new methods and classes submitted via PRs (after 1 May 2018). This is aimed at making it easier for new contributors to dive into our codebase, especially those who are new to Android development. A few things to note: + We require contributors to include Javadocs for all new methods and classes + submitted via PRs (after 1 May 2018). This is aimed at making it easier for + new contributors to dive into our codebase, especially those who are new to + Android development. A few things to note: -- This should not replace the need for code that is easily-readable in and of itself -- Please make sure that your Javadocs are reasonably descriptive, not just a copy of the method name -- Please do not use `@author` tags - we aim for collective code ownership, and if needed, GitHub allows us to see who wrote something without needing to add these tags + - This should not replace the need for code that is easily-readable in + and of itself + - Please make sure that your Javadocs are reasonably descriptive, not just + a copy of the method name + - Please do not use `@author` tags - we aim for collective code ownership, + and if needed, Git allows us to see who wrote something without needing + to add these tags (`git blame`) -# Write tests for your code (if possible) +1. Write tests for your code (if possible) -# Make sure the Wiki pages don't become stale by updating them (if needed) +1. Make sure the Wiki pages don't become stale by updating them (if needed) From d9600297752f8d7fa6955bd44678811d64ddc8eb Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Tue, 8 May 2018 12:21:13 +0530 Subject: [PATCH 061/184] Feature/switch to butterknife (#1494) * Implemented butterknife in MediaDetailFragment [issue #1491] * Implemented butterknife in MediaDetailPagerFragment [[issue #1491]] * post merge upstream master wip [[issue #1491]] --- .../commons/media/MediaDetailFragment.java | 200 ++++++++++-------- .../media/MediaDetailPagerFragment.java | 7 +- 2 files changed, 112 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index c3a977ab5..9614c4f00 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -9,6 +9,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.TypedValue; import android.view.LayoutInflater; @@ -22,6 +23,9 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -45,7 +49,8 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.ui.widget.CompatTextView; import timber.log.Timber; -import static android.view.View.*; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_SHORT; public class MediaDetailFragment extends CommonsDaggerSupportFragment { @@ -75,23 +80,37 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Inject MediaWikiApi mwApi; - - private MediaWikiImageView image; - private MediaDetailSpacer spacer; private int initialListTop = 0; - private TextView title; - private TextView desc; - private TextView author; - private TextView license; - private TextView coordinates; - private TextView uploadedDate; - private TextView seeMore; - private LinearLayout nominatedforDeletion; - private LinearLayout categoryContainer; - private LinearLayout authorLayout; - private Button delete; - private ScrollView scrollView; + @BindView(R.id.mediaDetailImage) + MediaWikiImageView image; + @BindView(R.id.mediaDetailSpacer) + MediaDetailSpacer spacer; + @BindView(R.id.mediaDetailTitle) + TextView title; + @BindView(R.id.mediaDetailDesc) + TextView desc; + @BindView(R.id.mediaDetailAuthor) + TextView author; + @BindView(R.id.mediaDetailLicense) + TextView license; + @BindView(R.id.mediaDetailCoordinates) + TextView coordinates; + @BindView(R.id.mediaDetailuploadeddate) + TextView uploadedDate; + @BindView(R.id.seeMore) + TextView seeMore; + @BindView(R.id.nominatedDeletionBanner) + LinearLayout nominatedForDeletion; + @BindView(R.id.mediaDetailCategoryContainer) + LinearLayout categoryContainer; + @BindView(R.id.authorLinearLayout) + LinearLayout authorLayout; + @BindView(R.id.nominateDeletion) + Button delete; + @BindView(R.id.mediaDetailScrollView) + ScrollView scrollView; + private ArrayList categoryNames; private boolean categoriesLoaded = false; private boolean categoriesPresent = false; @@ -101,6 +120,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private AsyncTask detailFetchTask; private LicenseList licenseList; + //Had to make this class variable, to implement various onClicks, which access the media, also I fell why make separate variables when one can serve the purpose + private Media media; + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -137,22 +159,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { final View view = inflater.inflate(R.layout.fragment_media_detail, container, false); - image = (MediaWikiImageView) view.findViewById(R.id.mediaDetailImage); - scrollView = (ScrollView) view.findViewById(R.id.mediaDetailScrollView); - - // Detail consists of a list view with main pane in header view, plus category list. - spacer = (MediaDetailSpacer) view.findViewById(R.id.mediaDetailSpacer); - title = (TextView) view.findViewById(R.id.mediaDetailTitle); - desc = (TextView) view.findViewById(R.id.mediaDetailDesc); - author = (TextView) view.findViewById(R.id.mediaDetailAuthor); - license = (TextView) view.findViewById(R.id.mediaDetailLicense); - coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates); - uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate); - seeMore = (TextView) view.findViewById(R.id.seeMore); - nominatedforDeletion = (LinearLayout) view.findViewById(R.id.nominatedDeletionBanner); - delete = (Button) view.findViewById(R.id.nominateDeletion); - categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer); - authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); + ButterKnife.bind(this,view); if (isFeaturedMedia){ authorLayout.setVisibility(VISIBLE); @@ -196,7 +203,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Override public void onResume() { super.onResume(); - Media media = detailProvider.getMediaAtPosition(index); + media = detailProvider.getMediaAtPosition(index); if (media == null) { // Ask the detail provider to ping us when we're ready Timber.d("MediaDetailFragment not yet ready to display details; registering observer"); @@ -209,17 +216,18 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { Timber.d("MediaDetailFragment ready to display delayed details!"); detailProvider.unregisterDataSetObserver(dataObserver); dataObserver = null; - displayMediaDetails(detailProvider.getMediaAtPosition(index)); + media=detailProvider.getMediaAtPosition(index); + displayMediaDetails(); } }; detailProvider.registerDataSetObserver(dataObserver); } else { Timber.d("MediaDetailFragment ready to display details"); - displayMediaDetails(media); + displayMediaDetails(); } } - private void displayMediaDetails(final Media media) { + private void displayMediaDetails() { //Always load image from Internet to allow viewing the desc, license, and cats image.setMedia(media); @@ -256,7 +264,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (success) { extractor.fill(media); setTextFields(media); - setOnClickListeners(media); } else { Timber.d("Failed to load photo details."); } @@ -316,74 +323,81 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { checkDeletion(media); } - private void setOnClickListeners(final Media media) { - if (licenseLink(media) != null) { - license.setOnClickListener(v -> openWebBrowser(licenseLink(media))); + @OnClick(R.id.mediaDetailLicense) + public void onMediaDetailLicenceClicked(){ + if (!TextUtils.isEmpty(licenseLink(media))) { + openWebBrowser(licenseLink(media)); } else { if(isFeaturedMedia) { - Timber.d("Unable to fetch license URL for %s", media.getLicense()); + Timber.d("Unable to fetch license URL for %s", media.getLicense()); } else { Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); toast.show(); } } + } + + @OnClick(R.id.mediaDetailCoordinates) + public void onMediaDetailCoordinatesClicked(){ if (media.getCoordinates() != null) { - coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); + openMap(media.getCoordinates()); } - if (delete.getVisibility() == VISIBLE) { - enableDeleteButton(true); + } - delete.setOnClickListener(v -> { + @OnClick(R.id.nominateDeletion) + public void onDeleteButtonClicked(){ + //Reviewer correct me if i have misunderstood something over here + //But how does this if (delete.getVisibility() == View.VISIBLE) { + // enableDeleteButton(true); makes sense ? + AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); + alert.setMessage("Why should this file be deleted?"); + final EditText input = new EditText(getActivity()); + alert.setView(input); + input.requestFocus(); + alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + String reason = input.getText().toString(); + DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); + deleteTask.execute(); + enableDeleteButton(false); + } + }); + alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }); + AlertDialog d = alert.create(); + input.addTextChangedListener(new TextWatcher() { + private void handleText() { + final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); + if (input.getText().length() == 0) { + okButton.setEnabled(false); + } else { + okButton.setEnabled(true); + } + } - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); - alert.setMessage("Why should this file be deleted?"); - final EditText input = new EditText(getActivity()); - alert.setView(input); - input.requestFocus(); - alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String reason = input.getText().toString(); - DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); - deleteTask.execute(); - enableDeleteButton(false); - } - }); - alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }); - AlertDialog d = alert.create(); - input.addTextChangedListener(new TextWatcher() { - private void handleText() { - final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); - if (input.getText().length() == 0) { - okButton.setEnabled(false); - } else { - okButton.setEnabled(true); - } - } + @Override + public void afterTextChanged(Editable arg0) { + handleText(); + } - @Override - public void afterTextChanged(Editable arg0) { - handleText(); - } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + }); + d.show(); + d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }); - d.show(); - d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - }); - } - if (nominatedforDeletion.getVisibility() == VISIBLE){ - seeMore.setOnClickListener(v -> { - openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); - }); + @OnClick(R.id.seeMore) + public void onSeeMoreClicked(){ + if(nominatedForDeletion.getVisibility()== VISIBLE) { + openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); } } @@ -488,11 +502,11 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private void checkDeletion(Media media){ if (media.getRequestedDeletion()){ delete.setVisibility(GONE); - nominatedforDeletion.setVisibility(VISIBLE); + nominatedForDeletion.setVisibility(VISIBLE); } else{ delete.setVisibility(VISIBLE); - nominatedforDeletion.setVisibility(GONE); + nominatedForDeletion.setVisibility(GONE); } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index c0564c603..62d1261cf 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -26,6 +26,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; import javax.inject.Inject; import javax.inject.Named; @@ -53,7 +55,8 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple @Named("default_preferences") SharedPreferences prefs; - private ViewPager pager; + @BindView(R.id.mediaDetailsPager) + ViewPager pager; private Boolean editable; private boolean isFeaturedImage; @@ -72,7 +75,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_media_detail_pager, container, false); - pager = (ViewPager) view.findViewById(R.id.mediaDetailsPager); + ButterKnife.bind(this,view); pager.addOnPageChangeListener(this); final MediaDetailAdapter adapter = new MediaDetailAdapter(getChildFragmentManager()); From f8cb469b48c2f33d1c8cbcb5542dcf5424ac66ae Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 8 May 2018 19:33:21 +1000 Subject: [PATCH 062/184] Create new UploadUtils class --- app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java new file mode 100644 index 000000000..f6b82ba1d --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java @@ -0,0 +1,4 @@ +package fr.free.nrw.commons.upload; + +public class UploadUtils { +} From 7f58b21fa0419fe48685b499d8ceec3c0253cde0 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 8 May 2018 19:52:49 +1000 Subject: [PATCH 063/184] Add Javadocs to ShareActivity.java --- .../free/nrw/commons/upload/ShareActivity.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 6a59c8e30..69e68c245 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -148,9 +148,9 @@ public class ShareActivity private FloatingActionButton mainFab; private boolean isFABOpen = false; - /** * Called when user taps the submit button. + * Requests Storage permission, if needed. */ @Override public void uploadActionInitiated(String title, String description) { @@ -159,8 +159,6 @@ public class ShareActivity this.description = description; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - // Check for Storage permission that is required for upload. - // Do not allow user to proceed without permission, otherwise will crash if (needsToRequestStoragePermission()) { requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERM_ON_SUBMIT_STORAGE); @@ -172,16 +170,22 @@ public class ShareActivity } } + /** + * Checks whether storage permissions need to be requested. + * Permissions are needed if the file is not owned by this application, (e.g. shared from the Gallery) + * @return true if file is not owned by this application and permission hasn't been granted beforehand + */ @RequiresApi(16) private boolean needsToRequestStoragePermission() { - // We need to ask storage permission when - // the file is not owned by this application, (e.g. shared from the Gallery) - // and permission is not obtained. return !FileUtils.isSelfOwned(getApplicationContext(), mediaUri) && (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED); } + /** + * Called after permission checks are done. + * Gets file metadata for category suggestions, displays toast, caches categories found, calls uploadController + */ private void uploadBegins() { getFileMetadata(locationPermitted); From b1f777c674fdb773d310761464cc75c5688f55d5 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 8 May 2018 19:54:13 +1000 Subject: [PATCH 064/184] Add TODOs --- app/src/main/AndroidManifest.xml | 1 + .../java/fr/free/nrw/commons/upload/MultipleShareActivity.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 17f6770d2..e617b385e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,6 +52,7 @@
+ Date: Tue, 8 May 2018 20:21:10 +1000 Subject: [PATCH 065/184] Add TODOs and Javadocs --- .../java/fr/free/nrw/commons/upload/ShareActivity.java | 7 ++++++- .../main/java/fr/free/nrw/commons/upload/UploadUtils.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 69e68c245..1a73c6f43 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -204,6 +204,9 @@ public class ShareActivity }); } + /** + * Starts CategorizationFragment after uploadBegins. + */ private void showPostUpload() { if (categorizationFragment == null) { categorizationFragment = new CategorizationFragment(); @@ -787,6 +790,7 @@ public class ShareActivity return super.onOptionsItemSelected(item); } + //TODO: Move this to a new class. /* * Get SHA1 of file from input stream */ @@ -826,6 +830,7 @@ public class ShareActivity } } + //TODO: Move this to a new class. Save references to the findViewByIds and pass them to the new method /* * function to provide pinch zoom */ @@ -874,7 +879,7 @@ public class ShareActivity expandedImageView.setImageBitmap(scaled); - + // Calculate the starting and ending bounds for the zoomed-in image. // This step involves lots of math. Yay, math. final Rect startBounds = new Rect(); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java index f6b82ba1d..0c0703ca6 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadUtils.java @@ -1,4 +1,7 @@ package fr.free.nrw.commons.upload; public class UploadUtils { + + + } From f4cef8da1b83376bbb693a27dc846bb9f6aeb070 Mon Sep 17 00:00:00 2001 From: misaochan Date: Wed, 9 May 2018 02:29:52 +1000 Subject: [PATCH 066/184] Add TODOs --- .../nrw/commons/upload/ShareActivity.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 1a73c6f43..ffc965d90 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -216,6 +216,10 @@ public class ShareActivity .commit(); } + /** + * Send categories to modifications queue after they are selected + * @param categories categories selected + */ @Override public void onCategoriesSave(List categories) { if (categories.size() > 0) { @@ -253,10 +257,6 @@ public class ShareActivity finish(); } - protected boolean isNearbyUpload() { - return isNearbyUpload; - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -309,8 +309,6 @@ public class ShareActivity } }); - - zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); try { zoomInButton.setOnClickListener(new View.OnClickListener() { @@ -345,6 +343,7 @@ public class ShareActivity } } + //TODO: We should only use snackbar for location permissions, since storage permissions are MANDATORY // Check storage permissions if marshmallow or newer if (useNewPermissions && (!storagePermitted || !locationPermitted)) { if (!storagePermitted && !locationPermitted) { @@ -404,7 +403,8 @@ public class ShareActivity } }); } - /* + + /** * Function to display the zoom and map FAB */ private void showFABMenu(){ @@ -419,8 +419,8 @@ public class ShareActivity zoomInButton.animate().translationY(-getResources().getDimension(R.dimen.first_fab)); } - /* - * function to close the zoom and map FAB + /** + * Function to close the zoom and map FAB */ private void closeFABMenu(){ isFABOpen=false; @@ -429,7 +429,6 @@ public class ShareActivity zoomInButton.animate().translationY(0).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { - } @Override @@ -438,21 +437,25 @@ public class ShareActivity maps_fragment.setVisibility(View.GONE); zoomInButton.setVisibility(View.GONE); } - } @Override public void onAnimationCancel(Animator animator) { - } @Override public void onAnimationRepeat(Animator animator) { - } }); } + /** + * Checks if upload was initiated via Nearby + * @return true if upload was initiated via Nearby + */ + protected boolean isNearbyUpload() { + return isNearbyUpload; + } @Override public void onRequestPermissionsResult(int requestCode, From 2d1f166ac77a21a0f2cf96c203f2359fe4927213 Mon Sep 17 00:00:00 2001 From: Ashish Date: Wed, 9 May 2018 17:57:59 +0530 Subject: [PATCH 067/184] Implemented butterknife in MultipleUploadListFragment [issue #1491] --- .../commons/upload/MultipleUploadListFragment.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java index 4390bcef4..089f1ac46 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleUploadListFragment.java @@ -26,6 +26,8 @@ import android.widget.GridView; import android.widget.RelativeLayout; import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; @@ -41,9 +43,13 @@ public class MultipleUploadListFragment extends Fragment { void OnMultipleUploadInitiated(); } - private GridView photosGrid; + @BindView(R.id.multipleShareBackground) + GridView photosGrid; + + @BindView(R.id.multipleBaseTitle) + EditText baseTitle; + private PhotoDisplayAdapter photosAdapter; - private EditText baseTitle; private TitleTextWatcher textWatcher = new TitleTextWatcher(); private Point photoSize; @@ -166,9 +172,7 @@ public class MultipleUploadListFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_multiple_uploads_list, container, false); - photosGrid = view.findViewById(R.id.multipleShareBackground); - baseTitle = view.findViewById(R.id.multipleBaseTitle); - + ButterKnife.bind(this,view); photosAdapter = new PhotoDisplayAdapter(); photosGrid.setAdapter(photosAdapter); photosGrid.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); From 8f76dd0b61e0769d2e7831f7a7272967c80fa84e Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 10 May 2018 13:31:51 +0530 Subject: [PATCH 068/184] Implemented butterknife in ShareActivity [issue #1491] --- .../nrw/commons/upload/ShareActivity.java | 236 +++++++++--------- 1 file changed, 115 insertions(+), 121 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 6a59c8e30..cfcec1da5 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -8,7 +8,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.ContentResolver; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -32,16 +31,16 @@ import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.BitmapCompat; -import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.MenuItem; import android.view.View; -import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; -import android.view.inputmethod.InputMethodManager; +import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; +import butterknife.BindView; +import butterknife.OnClick; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.github.chrisbanes.photoview.PhotoView; @@ -69,22 +68,18 @@ import fr.free.nrw.commons.caching.CacheController; import fr.free.nrw.commons.category.CategorizationFragment; import fr.free.nrw.commons.category.OnCategoriesSaveHandler; import fr.free.nrw.commons.contributions.Contribution; -import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.modifications.CategoryModifier; import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModifierSequence; import fr.free.nrw.commons.modifications.ModifierSequenceDao; import fr.free.nrw.commons.modifications.TemplateRemoveModifier; -import fr.free.nrw.commons.utils.ImageUtils; import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; -import android.support.design.widget.FloatingActionButton; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; -import static java.lang.Long.min; /** * Activity for the title/desc screen after image is selected. Also starts processing image @@ -95,6 +90,22 @@ public class ShareActivity implements SingleUploadFragment.OnUploadActionInitiated, OnCategoriesSaveHandler,SimilarImageDialogFragment.onResponse { + @BindView(R.id.container) + FrameLayout flContainer; + @BindView(R.id.backgroundImage) + SimpleDraweeView backgroundImageView; + @BindView(R.id.media_map) + FloatingActionButton mapsFragment; //Lets stick to camelCase + @BindView(R.id.media_upload_zoom_in) + FloatingActionButton zoomInButton; + @BindView(R.id.media_upload_zoom_out) + FloatingActionButton zoomOutButton; + @BindView(R.id.main_fab) + FloatingActionButton mainFab; + @BindView(R.id.expanded_image) + PhotoView expandedImageView; + + private static final int REQUEST_PERM_ON_CREATE_STORAGE = 1; private static final int REQUEST_PERM_ON_CREATE_LOCATION = 2; private static final int REQUEST_PERM_ON_CREATE_STORAGE_AND_LOCATION = 3; @@ -120,9 +131,6 @@ public class ShareActivity private Uri mediaUri; private Contribution contribution; - private SimpleDraweeView backgroundImageView; - private FloatingActionButton maps_fragment; - private boolean cacheFound; private GPSExtractor imageObj; @@ -143,11 +151,14 @@ public class ShareActivity private Animator CurrentAnimator; private long ShortAnimationDuration; - private FloatingActionButton zoomInButton; - private FloatingActionButton zoomOutButton; - private FloatingActionButton mainFab; private boolean isFABOpen = false; + //Had to make them class variables, to extract out the click listeners, also I see no harm in this + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + private float startScaleFinal; + /** * Called when user taps the submit button. @@ -257,7 +268,6 @@ public class ShareActivity setContentView(R.layout.activity_share); ButterKnife.bind(this); initBack(); - backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder .newInstance(getResources()) .setPlaceholderImage(VectorDrawableCompat.create(getResources(), @@ -286,37 +296,6 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } - - mainFab = (FloatingActionButton) findViewById(R.id.main_fab); - /* - * called when upper arrow floating button - */ - mainFab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if(!isFABOpen){ - showFABMenu(); - }else{ - closeFABMenu(); - } - } - }); - - - - zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); - try { - zoomInButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - zoomImageFromThumb(backgroundImageView, mediaUri); - } - }); - } catch (Exception e){ - Log.i("exception", e.toString()); - } - zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); - if (savedInstanceState != null) { contribution = savedInstanceState.getParcelable("contribution"); } @@ -378,25 +357,13 @@ public class ShareActivity .commitAllowingStateLoss(); } uploadController.prepareService(); - maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); - maps_fragment.setVisibility(View.VISIBLE); + mapsFragment.setVisibility(View.VISIBLE); if( imageObj == null || imageObj.imageCoordsExists != true){ - maps_fragment.setVisibility(View.INVISIBLE); + mapsFragment.setVisibility(View.INVISIBLE); } - - maps_fragment.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if( imageObj != null && imageObj.imageCoordsExists == true) { - Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); - Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); - mapIntent.setPackage("com.google.android.apps.maps"); - startActivity(mapIntent); - } - } - }); } + /* * Function to display the zoom and map FAB */ @@ -404,11 +371,11 @@ public class ShareActivity isFABOpen=true; if( imageObj != null && imageObj.imageCoordsExists == true) - maps_fragment.setVisibility(View.VISIBLE); + mapsFragment.setVisibility(View.VISIBLE); zoomInButton.setVisibility(View.VISIBLE); mainFab.animate().rotationBy(180); - maps_fragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); + mapsFragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); zoomInButton.animate().translationY(-getResources().getDimension(R.dimen.first_fab)); } @@ -418,7 +385,7 @@ public class ShareActivity private void closeFABMenu(){ isFABOpen=false; mainFab.animate().rotationBy(-180); - maps_fragment.animate().translationY(0); + mapsFragment.animate().translationY(0); zoomInButton.animate().translationY(0).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { @@ -428,7 +395,7 @@ public class ShareActivity @Override public void onAnimationEnd(Animator animator) { if(!isFABOpen){ - maps_fragment.setVisibility(View.GONE); + mapsFragment.setVisibility(View.GONE); zoomInButton.setVisibility(View.GONE); } @@ -700,8 +667,9 @@ public class ShareActivity return; } + //I might not be supposed to change it, but still, I saw it @Override - public void onPostiveResponse() { + public void onPositiveResponse() { imageObj = tempImageObj; decimalCoords = imageObj.getCoords(false);// Not necessary to use gps as image already ha EXIF data Timber.d("EXIF from tempImageObj"); @@ -865,26 +833,19 @@ public class ShareActivity scaled = bitmap; } // Load the high-resolution "zoomed-in" image. - PhotoView expandedImageView = (PhotoView) findViewById( - R.id.expanded_image); expandedImageView.setImageBitmap(scaled); - + // Calculate the starting and ending bounds for the zoomed-in image. // This step involves lots of math. Yay, math. - final Rect startBounds = new Rect(); - final Rect finalBounds = new Rect(); - final Point globalOffset = new Point(); - // The start bounds are the global visible rectangle of the thumbnail, // and the final bounds are the global visible rectangle of the container // view. Also set the container view's offset as the origin for the // bounds, since that's the origin for the positioning animation // properties (X, Y). thumbView.getGlobalVisibleRect(startBounds); - findViewById(R.id.container) - .getGlobalVisibleRect(finalBounds, globalOffset); + flContainer.getGlobalVisibleRect(finalBounds, globalOffset); startBounds.offset(-globalOffset.x, -globalOffset.y); finalBounds.offset(-globalOffset.x, -globalOffset.y); @@ -955,53 +916,86 @@ public class ShareActivity // Upon clicking the zoomed-in image, it should zoom back down // to the original bounds and show the thumbnail instead of // the expanded image. - final float startScaleFinal = startScale; - zoomOutButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (CurrentAnimator != null) { - CurrentAnimator.cancel(); - } - zoomOutButton.setVisibility(View.GONE); - mainFab.setVisibility(View.VISIBLE); + startScaleFinal = startScale; - // Animate the four positioning/sizing properties in parallel, - // back to their original values. - AnimatorSet set = new AnimatorSet(); - set.play(ObjectAnimator - .ofFloat(expandedImageView, View.X, startBounds.left)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.Y,startBounds.top)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.SCALE_X, startScaleFinal)) - .with(ObjectAnimator - .ofFloat(expandedImageView, - View.SCALE_Y, startScaleFinal)); - set.setDuration(ShortAnimationDuration); - set.setInterpolator(new DecelerateInterpolator()); - set.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - thumbView.setAlpha(1f); - expandedImageView.setVisibility(View.GONE); - CurrentAnimator = null; - } - - @Override - public void onAnimationCancel(Animator animation) { - thumbView.setAlpha(1f); - expandedImageView.setVisibility(View.GONE); - CurrentAnimator = null; - } - }); - set.start(); - CurrentAnimator = set; - - } - - }); } + /* + * called when upper arrow floating button + */ + @OnClick(R.id.main_fab) + public void onMainFabClicked() { + if (!isFABOpen) { + showFABMenu(); + } else { + closeFABMenu(); + } + } + + @OnClick(R.id.media_upload_zoom_in) + public void onZoomInFabClicked() { + //This try catch block was originally holding the entire click listener on the fab button, I did not wanted to risk exceptions + try { + zoomImageFromThumb(backgroundImageView, mediaUri); + } catch (Exception e) { + Log.i("exception", e.toString()); + } + } + + @OnClick(R.id.media_upload_zoom_out) + public void onZoomOutFabClicked() { + if (CurrentAnimator != null) { + CurrentAnimator.cancel(); + } + zoomOutButton.setVisibility(View.GONE); + mainFab.setVisibility(View.VISIBLE); + + // Animate the four positioning/sizing properties in parallel, + // back to their original values. + AnimatorSet set = new AnimatorSet(); + set.play(ObjectAnimator + .ofFloat(expandedImageView, View.X, startBounds.left)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(expandedImageView, + View.SCALE_Y, startScaleFinal)); + set.setDuration(ShortAnimationDuration); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + //background image view is thumbView + backgroundImageView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + //background image view is thumbView + backgroundImageView.setAlpha(1f); + expandedImageView.setVisibility(View.GONE); + CurrentAnimator = null; + } + }); + set.start(); + CurrentAnimator = set; + } + + @OnClick(R.id.media_map) + public void onFabShowMapsClicked() { + if (imageObj != null && imageObj.imageCoordsExists == true) { + Uri gmmIntentUri = Uri + .parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj + .getDecLongitude()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + startActivity(mapIntent); + } + } } From 6ab6a21e40b318f80ba98af7b89154c0af74c699 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 10 May 2018 10:11:14 +0200 Subject: [PATCH 069/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-bn/strings.xml | 3 + app/src/main/res/values-de/strings.xml | 8 +++ app/src/main/res/values-diq/strings.xml | 8 +++ app/src/main/res/values-el/strings.xml | 8 +++ app/src/main/res/values-es/strings.xml | 8 +++ app/src/main/res/values-eu/strings.xml | 17 +++-- app/src/main/res/values-fr/strings.xml | 9 +++ app/src/main/res/values-it/strings.xml | 7 +++ app/src/main/res/values-iw/strings.xml | 8 +++ app/src/main/res/values-ja/strings.xml | 73 +++++++++++++++++++--- app/src/main/res/values-ko/strings.xml | 8 +++ app/src/main/res/values-lb/strings.xml | 4 ++ app/src/main/res/values-lv/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 8 +++ app/src/main/res/values-pl/strings.xml | 2 + app/src/main/res/values-pms/strings.xml | 8 +++ app/src/main/res/values-pt-rBR/strings.xml | 8 +++ app/src/main/res/values-pt/strings.xml | 19 ++++-- app/src/main/res/values-ru/strings.xml | 9 +++ app/src/main/res/values-skr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 20 ++++-- app/src/main/res/values-zh-rTW/strings.xml | 10 ++- app/src/main/res/values-zh/strings.xml | 8 +++ 24 files changed, 231 insertions(+), 25 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 6d9c94c1d..a9127c1eb 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -145,4 +145,5 @@ مرحبا بكم في ويكيمديا كومنز، %1$s! نحن سعداء لأنك هنا. %1$s رسالة على صفحة الحديث %1$s ذكر لك على %2$s. + شارك التطبيق diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 679c50803..e7167393c 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -259,4 +259,7 @@ ইন্টারনেট উপলব্ধ কোন বিজ্ঞপ্তি পাওয়া যায়নি পুনঃচেষ্টা করুন + বুঝেছি! + কোন চিত্র পাওয়া যায়নি! + আপলোড করেছেন: %1$s diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 36e013976..5f751153c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -269,5 +269,13 @@ Fortfahren Abbrechen Erneut versuchen + Verstanden! + Dies sind die Orte in deiner Nähe, die Bilder zur Illustration ihrer Wikipedia-Artikel benötigen. + Das Antippen dieser Schaltfläche zeigt eine Liste mit diesen Orten + Du kannst ein Bild für einen beliebigen Ort von deiner Galerie oder Kamera hochladen + Keine Bilder gefunden! + Beim Laden der Bilder ist ein Fehler aufgetreten. + Hochgeladen von: %1$s App teilen + Während der Bildauswahl wurden keine Koordinaten angegeben diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index 2b66709f0..1f1d69ea3 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -9,11 +9,15 @@ * Mirzali --> + Asayış + Bıngeh + Lokasyon Commons Eyari Namey karberi Parola Cı kewe + Parola, xo vira kerde? Qeyd be Cıkewtış Kerem kerên, bıpawên... @@ -58,6 +62,8 @@ Bar ke Kategoriyan dı cı geyr Star ke + Newe ke + Liste \@string/contributions_subtitle_zero Yew barbiyayış @@ -129,5 +135,7 @@ Keye Bar ke Veciyayış + Bıtexelne Anciya bıcerrebne + Mı fehm kerd! diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 0dae5c65e..ee50aa3d7 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -273,5 +273,13 @@ Συνέχεια Ακύρωση Ξαναπροσπαθήστε + Κατάλαβα! + Αυτά είναι τα μέρη κοντά σας που χρειάζονται φωτογραφίες για να εικονογραφηθούν τα λήμματά τους στη Βικιπαίδεια + Πατώντας αυτό το κουμπί φέρνει μια λίστα αυτών των μερών + Μπορείτε να ανεβάσετε μια εικόνα για οποιοδήποτε μέρος από την γκαλερί ή την κάμερά σας + Δεν βρέθηκαν εικόνες! + Συνέβη σφάλμα κατά το ανέβασμα των εικόνων. + Ανέβηκε από: %1$s Κοινοποίηση εφαρμογής + Οι συντεταγμένες δεν ορίστηκαν κατά την διάρκεια της επιλογής εικόνας diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c1a45b309..69cf2f8b7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -267,4 +267,12 @@ Selecciona el idioma en que quieres enviar traducciones Cancelar Reintentar + Entendido + Estos sitios cercanos a ti necesitan imágenes para ilustrar sus artículos de Wikipedia + Puedes cargar una imagen para cualquier sitio desde la galería o la cámara + No se encontró ninguna imagen. + Se produjo un error al cargar las imágenes. + Cargada por: %1$s + Compartir aplicación + No se especificaron las coordenadas al seleccionar la imagen diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index f44262e05..a109ff541 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -8,11 +8,17 @@ * Theklan --> + Itxura + Orokorra + Feedback + Kokapena Commons + Hobespenak Erabiltzaile izena Pasahitza Saioa hasi + Pasahitza ahaztu duzu? Eman izena Saioa hasten Mesedez itxaron… @@ -54,22 +60,23 @@ Kategoriak bilatu Gorde Eguneratu + Zerrenda GPSa gaitu Oraindik ez da ezer igo - - Oraindik igoerarik ez + + \@string/contributions_subtitle_zero igoera 1 %1$d igoera Ez da kategoriak aukritu %1$s izenarekin - Gehitu kategoriak zure argazkiak Wikimedia Commonsen aurkitzen errazagoak izan daitezen. + Gehitu kategoriak zure argazkiak Wikimedia Commonsen aurkitzen errazagoak izan daitezen.\nHasi idazten kategoriak gehitzeko. Kategoriak Hobespenak Eman izena Honi buruz Open Source softwarea <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache v2 Lizentziaren</a> pean egina. Wikimedia Commons eta bere logoa Wikimedia Fundazioaren marka erregistratuak dira eta Wikimedia Fundazioaren baimenarekin erabiltzen dira. Ez gaude Wikimedia Fundaziora afiliatuta. GitHub-eko <a href=\"https://github.com/commons-app/apps-android-commons\">Iturria</a> eta <a href=\"https://commons-app.github.io/\">webgunea</a>. <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-eko gai</a> berria sortu erroreen berri emateko. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Pribatutasun politika</a> + <u>Pribatutasun politika</u> Honi buruz Bidali zure iritzia (e-posta bidez) Posta bezerorik ez da instalatu @@ -81,7 +88,7 @@ Irudi hau %1$s lizentziapean egongo da Irudi hau bidaltzen, nire lan propioa dela aitortzen dut, copyrighta duten materiala edo selfiak ez duela, eta beste motatakoak <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Ohikoaren arauak</a> Jaitsi - Lizentzia + Berezko lizentzia Aurreko izenburu/deskribapena erabili Oraingo kokapena automatikoki lortu Gau modua diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 442fc6bc5..6dd08a30d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -5,6 +5,7 @@ * Happy13241 * Jean-Frédéric * KATRINE1992 +* Melissadeba95 * Metroitendo * Nicolas Raoul * Orikrin1998 @@ -279,5 +280,13 @@ Continuer Annuler Réessayer + C’est bon ! + Il y a des lieux autour de vous qui demandent des images pour illustrer leurs articles Wikipédia + En cliquant sur ce bouton vous afficherez une liste de ces endroits + Vous pouvez téléverser une photo de n\'importe quel endroit de votre gallerie ou de votre appareil photo + Aucune images trouvée. + Une erreur s\'est produite pendant le chargement des images. + Importé par:%1$s Partager les applications + Les coordonnées n\'ont pas été spécifiées pendant la sélection de l\'image diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 306a1e3a4..06bfa701f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -223,4 +223,11 @@ Lingue Annulla Riprova + Capito! + Questi sono i luoghi vicino a te che necessitano di immagini per illustrare le loro voci di Wikipedia + Puoi caricare un\'immagine per ogni luogo dalla tua galleria o fotocamera + Nessuna immagine trovata! + Si è verificato un errore durante il caricamento delle immagini. + Caricato da: %1$s + Condividi applicazione diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 762a3be31..f0cdf1f3d 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -273,5 +273,13 @@ המשך ביטול לנסות שוב + הבנתי! + אלה המקומות בסביבתך שזקוקים לתמונות כדי להמחיש את הערכים שלהם בוויקיפדיה + ניתן ללחוץ על כפתור זה כדי להציג רשימה של המקומות האלה + באפשרותך להעלות תמונה של כל מקום מהגלריה או מהמצלמה שלך + לא נמצאו תמונות! + אירעה שגיאה בטעינת התמונות. + הועלתה על־ידי: %1$s שיתוף היישום + לא צוינו קואורדינטות בעת בחירת התמונה diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index e34c98432..ef45a5d3a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -12,13 +12,18 @@ * Yusuke1109 --> + 表示 + 全般 フィードバック 場所 コモンズ + 設定 利用者名 パスワード + コモンズのベータ版アカウントにログイン ログイン + パスワードを忘れた場合 利用者登録 ログイン中 お待ちください… @@ -49,6 +54,7 @@ 共有 ブラウザーで表示 タイトル + ファイル名をつけてください 説明 ログインできません - ネットワークのエラーです ログインできません - 利用者名を確認してください @@ -64,6 +70,7 @@ カテゴリを検索 保存 更新 + 一覧 お使いのデバイスではGPSが無効になっています。有効にしますか? GPSを有効にする まだ何もアップロードされていません。 @@ -82,6 +89,7 @@ カテゴリ 設定 利用者登録 + 秀逸な画像 このアプリについて ウィキメディア・コモンズ・アプリはウィキメディア・コミュニティの助成金受給者とボランティアによって製作・メンテナンスされているオープンソースソフトウェアです。ウィキメディア財団はこのアプリの製作・開発・メンテナンスに関与していません。 バグとアイディアは <a href=\"https://github.com/commons-app/apps-android-commons/issues\">Github</a> へ。 @@ -96,6 +104,7 @@ 再試行 キャンセル この画像が %1$s ライセンスでアップロードされます。 + この画像の投稿に当たり、私はこれが自分自身の作品であり、著作権のあるコンテンツや自撮りは含まれていないと宣言します。 ダウンロード 既定のライセンス 前回のタイトルと記述を使用 @@ -126,11 +135,19 @@ ウィキメディア・コモンズにはウィキペディアで使用する画像のほぼすべてが保管されています。 あなたの画像は世界中の人々が学習する助けになります! アップロードする画像はあなたご本人が撮影したものかあなたが単独で制作したものに限定します。 - - 自然物 (動植物、山)\n- 道具 (自転車、駅)\n- 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) + 自然物 (動植物、山)\n• 道具 (自転車、駅)\n• 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) + 自然物 (動植物、山) + 道具 (自転車、駅) + 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) アップロードが《禁止》のもの: - あなたの友人の自撮り写真や画像\n- インターネットからダウンロードした画像\n- 著作権のあるアプリのスクリーンショット + 自撮りもしくは友達を撮影した写真 + ウェブからダウンロードした画像 + 独自のアプリケーションのスクリーンショット アップロードの例: - 題名: シドニー・オペラハウス\n- 説明: 湾の向こうから見たシドニー・オペラハウス\n- カテゴリ: 西側から見たシドニー・オペラハウス、遠くから見たシドニー・オペラハウス + 題名: シドニーのオペラハウス + 説明: シドニーのオペラハウス。湾を挟んで撮影。 画像を投稿してください。ウィキペディアの記事に彩りを! ウィキペディアの画像はウィキメディア・コモンズに保管されています。 あなたの画像は世界中の人々が学習する助けになります @@ -143,11 +160,11 @@ 説明はありません。 不明なライセンス 更新 - 必要な権限:外部ストレージを読み込みます。これがなければアプリは機能しません。 - 必要な権限:外部ストレージを作成します。これがなければアプリは機能しません。 - オプションの権限:カテゴリ候補の現在の位置を取得する + 必要な権限:外部ストレージを読み込みます。これがなければアプリはギャラリーを開けません。 + 必要な権限:外部ストレージに入力します。これがないとアプリはカメラにアクセスできません。 + オプションの権限:カテゴリ候補のため現在の位置を取得する 承認 - 周りの場所 + 近くの場所 付近の場所が見つかりません 警告 このファイルが既にコモンズにあります。本当にアップロードしますか? @@ -158,6 +175,7 @@ 記述 ここにメディアの説明が入ります。かなり長文になる場合には数行にわたることがあります。それでも見栄えがよいと願っています。 作者 + 秀逸な画像の作者名を記入します。 アップロード日時 ライセンス 緯度経度 @@ -174,14 +192,19 @@ コモンズの商標 コモンズのウェブサイト コモンズのフェイスブックページ + コモンズのGithubソースコード 背景画像 + メディアイメージが失敗しました 画像がありません 画像をアップロード 蔵王連峰 リャマ レインボーブリッジ チューリップ + 自撮りはアップロードできません + 独自の著作権がある画像 ウィキペディアへようこそ + 著作権について シドニーオペラハウス キャンセル 開く @@ -195,28 +218,62 @@ ログアウト チュートリアル 通知 - 場所の権限がないと、近くの場所を表示できません + 秀逸 + 場所の権限がないため、近くの場所を表示できません 説明がありません + コモンズのファイルページ ウィキデータ項目 ウィキペディアの記事 画像をキャッシュする際のエラー ファイル固有の説明的な表題。ファイル名として使われます。平易な言葉を使い、空白を入れることができます。拡張子は含めないでください。 可能な限りメディアを説明してください:どこで撮られましたか?それは何を示していますか?文脈とは何ですか?物や人を説明してください。容易に推測できない情報、例えば風景の場合の時刻を明らかにする。メディアに珍しいことがある場合は、何が珍しいのかを説明してください。 - 権限を取得 + この画像は暗すぎますがアップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 + ピントが合っていませんが、アップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 + 権限を付与 外部ストレージを使用 アプリ内のカメラで撮影した写真を端末に保存する 自分のアカウントにログイン ログファイルを送信する メールで開発者にログファイルを送信する + URLを開くブラウザーが見つかりません + エラーが発生しました。URL が見つかりません + 削除の提案 + この画像の削除が提案されています。 ブラウザーで表示 場所は変更されていません。 位置が無効です。 + 近くの場所を表示するには権限が必要です + 道順を調べる 記事を読む + ウィキメディアコモンズにようこそ、%1$さん! このサイトへ来てくれてありがとうございます。 + %1$さんからアナタのとーくぺ^字にメッセージが届いています + 編集をしてくれてありがとうございます + %1$さんが%2$であなたに言及しています。 + 表示の切り替え + 道順 + ウィキデータ + ウィキペディア + コモンズ <u>評価する</u> <u>FAQ</u> チュートリアルをスキップする + インターネットに接続していません + インターネットに接続しました + 通知の取得に失敗しました + 通知はありません <u>翻訳</u> 言語 + どの言語に編集するか選択 + 次へ キャンセル - 再試行 + やり直す + 了解 + 近くでウィキペディアの記事に使う写真がない場所はこちら + このボタンをタップするとリストを表示します + 場所の写真をアップロードするには、ギャラリーから選ぶことも撮影することもできます + 画像がありません + 画像の読み込み中にエラーが発生しました + アップロードした人: %1$ + アプリをシェアする + 画像の選択中に位置情報を特定できませんでした diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d0e1c21ed..e80999d54 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -266,5 +266,13 @@ 진행 취소 다시 시도 + 알겠습니다! + 이들은 위키백과 글에 사진을 넣을 필요가 있는 당신 주위의 장소들입니다 + 이 버튼을 탭하면 이 장소들의 목록을 가져옵니다 + 갤러리나 카메라 어느 곳이든 사진을 올릴 수 있습니다 + 그림이 없습니다! + 그림을 불러오는 동안 오류가 발생했습니다. + 올린이: %1$s 앱 공유 + 그림 선택 중에 좌표가 지정되지 않았습니다 diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index 5abca6562..d346b90bd 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -240,4 +240,8 @@ Virufueren Ofbriechen Nach eng Kéier probéieren + Verstanen! + Keng Biller fonnt! + Feeler beim Eropluede vu Biller. + Eropgeluede vum: %1$s diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 1eba570d2..b6c5103e2 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -109,4 +109,5 @@ Valodas Turpināt Atcelt + Sapratu! diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 4e44dad60..492e1bc0c 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -263,5 +263,13 @@ Продолжи Откажи Пробај пак + Јасно! + Ова се места во ваша близинана кои им требаат слики за илустрирање на нивните статии на Википедија + Ако допрете на копчево ќе добиете список на тие места + Можете да подигнете слика за било кое од местата од вашата галерија или камера + Не пронајдов ниедна слика! + Се појави грешка при вчитувањето на сликите. + Подигач: %1$s Сподели прилог + Не беа укажани координати при изборот на сликата diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 77cdb547d..ccc5f374f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -227,4 +227,6 @@ Nie znaleziono powiadomień Języki Anuluj + Nie znaleziono grafik! + Wystąpił błąd podczas ładowania grafik. diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 30115f1ad..53ce91cc5 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -263,5 +263,13 @@ Andé anans Anulé Prové torna + Fàit! + A-i é dij pòst davzin a chiel ch\'a l\'han da manca ëd plance për ilustré ij sò artìcoj su Wikipedia + Sgnacand su \'s boton a comparirà na lista ëd si pòst + A peul carié na fòto da \'n pòst qualsëssìa ëd soa galarìa o màchina fòto + Gnun-e plance trovà! + A-i é staje n\'eror durant ël cariament ëd le plance. + Carià da: %1$s Partagé j\'aplicassion + Le coordinà a son nen ëstàite spessificà durant la selession ëd la plancia diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6722ae4bb..23b5e4abf 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -275,5 +275,13 @@ Avançar Cancelar Tentar novamente + Entendido! + Estes são os lugares perto de você que precisam de fotografias para ilustrar os respetivos artigos na Wikipédia + Tocar neste botão fará surgir uma lista destes lugares + Pode carregar uma fotografia para qualquer dos lugares, da sua galeria ou câmara + Não foi encontrada nenhuma imagem! + Ocorreu um erro durante o carregamento das imagens. + Carregada por: %1$s Compartilhar o aplicativo + Não foram especificadas coordenadas durante a seleção da imagem diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index b0717f3dc..3da1296b7 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -16,12 +16,12 @@ Geral Comentários Localização - Wikimedia Commons + Commons Configurações - Nome de utilizador(a) + Nome de utilizador Palavra-passe - Entre com a sua conta do Commons Beta + Entre com a sua conta da wiki Commons Beta Iniciar sessão Esqueceu-se da palavra-passe? Registar-se @@ -118,7 +118,7 @@ Utilizar tema escuro Atribuição-CompartilhaIgual 4.0 Atribuição 4.0 - Atribuição – Compartilhamento pela mesma Licença + Atribuição–CompartilhaIgual 3.0 Atribuição 3.0 CC0 CC BY-SA 3.0 @@ -136,7 +136,7 @@ CC-BY-SA 4.0 CC BY 4.0 CC Zero - Wikimedia Commons armazena a maioria das imagens que são usadas na Wikipédia. + A wiki Wikimedia Commons aloja a maioria das imagens que são usadas na Wikipédia. As suas imagens ajudam a educar pessoas em todo o mundo! Por favor, carregue apenas imagens tiradas ou criadas exclusivamente por si: Objetos naturais (flores, animais, montanhas)\n• Objetos úteis (bicicletas, estações de comboio)\n• Pessoas famosas (o seu presidente da câmara, atletas olímpicos que conheça) @@ -274,4 +274,13 @@ Avançar Cancelar Tentar novamente + Entendido! + Estes são os lugares perto de si que precisam de fotografias para ilustrar os respetivos artigos na Wikipédia + Tocar neste botão fará surgir uma lista destes lugares + Pode carregar uma fotografia para qualquer dos lugares, da sua galeria ou câmara + Não foi encontrada nenhuma imagem! + Ocorreu um erro durante o carregamento das imagens. + Carregada por: %1$s + Partilhar aplicação + Não foram especificadas coordenadas durante a seleção da imagem diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4dc90489d..ce71af94b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -285,4 +285,13 @@ Выполняется Отмена Повторить + Понятно! + Это места поблизости, статьи о которых нуждаются в иллюстрациях + Нажатие этой кнопки сгенерирует список таких мест + Вы можете загрузить изображение для любого из этих мест, сделав снимок камерой или выбрав уже существующее изображение из галереи + Изображений не найдено! + Произошла ошибка при загрузке изображений. + Загружено участником %1$s + Поделиться приложением + Во время выбора изображения не были указаны координаты diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index 796ae8555..73a5b7e51 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -129,4 +129,5 @@ اڳوں تے تھیوو منسوخ ولدا کوشش کرو + گھن گھندا diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 24ef60b61..17a324a97 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -90,9 +90,9 @@ Kategorier Inställningar Registrera - Utvalda bild + Utvalda bilder Om - Wikimedia Commons är en app med öppen källkod som skapas och underhålls av frivilliga från Wikimedias gemenskap. Wikimedia Foundation är inte involverad i skapandet, utvecklingen eller underhållet av appen. + Wikimedia Commons-appen är en app med öppen källkod som skapas och underhålls av frivilliga från Wikimedias gemenskap. Wikimedia Foundation är inte involverad i skapandet, utvecklingen eller underhållet av appen. Skapa ett nytt <a href=\"https://github.com/commons-app/apps-android-commons/issues\">ärende på GitHub</a> för att rapportera buggar och förslag. <u>Integritetspolicy</u> <u>Erkännande</u> @@ -105,7 +105,7 @@ Försök igen Avbryt Denna bild kommer att licensieras under %1$s - Genom att skicka in denna bild intygar jag att detta är mitt eget verk, som inte innehåller upphovsrättsskyddat material eller selfies samt annars följer <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Commons-policys</a>. + Genom att skicka in denna bild intygar jag att detta är mitt eget verk, som inte innehåller upphovsrättsskyddat material eller selfies samt följer <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Commons-policys</a>. Ladda ned Standardlicens Använd föregående titel/beskrivning @@ -135,7 +135,7 @@ CC Zero Wikimedia Commons lagrar de flesta bilderna som används på Wikipedia. Dina bilder hjälper till att utbilda\nmänniskor runt hela världen! - Ladda upp bilder som endast du har tagit eller skapat: + Ladda endast upp bilder som du har tagit eller skapat själv: Naturliga föremål (blommor, djur, berg)\n• Användbara föremål (cyklar, tågstationer)\n• Berömda personer (din borgmästare, olympiska atleter du har träffat) Naturliga föremål (blommor, djur, berg) Användbar föremål (cyklar, tågstationer) @@ -163,8 +163,8 @@ Ingen beskrivning Okänd licens Uppdatera - Nödvändig behörighet: Läsa extern lagring. Appen kan inte komma åt ditt galleri utan detta. - Nödvändig behörighet: Skriva till extern lagring. Appen kan inte komma åt din kamera utan detta. + Nödvändig behörighet: Läs extern lagring. Appen kan inte komma åt ditt galleri utan detta. + Nödvändig behörighet: Skriv till extern lagring. Appen kan inte komma åt din kamera utan detta. Valfri behörighet: Hämta aktuell plats för kategoriförslag OK Platser i närheten @@ -271,5 +271,13 @@ Fortsätt Avbryt Försök igen + Uppfattat! + Detta är platserna nära dig som behöver bilder för att illustrera deras Wikipedia-artiklar + Klicka på den här knappen för att få upp en lista med dessa platser + Du kan ladda upp en bild från vilken plats som helst från ditt galleri eller kamera + Inga bilder hittades! + Ett fel uppstod vid inläsning av bilder. + Uppladdad av: %1$s Dela app + Koordinater specificerades inte vid bildvalet diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index a2878cddf..80b595f5d 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -32,7 +32,7 @@ 未能核對身分! 開始上傳! 已上傳%1$s! - 點選檢視您上傳的項目 + 輕觸來檢視您上傳的項目 開始上傳%1$s 正在上傳%1$s 即將完成上傳 %1$s @@ -271,5 +271,13 @@ 已進行 取消 重試 + 了解! + 這些是在您的附近,並且需要圖片來圖解有關它們的維基百科條目之地點 + 輕觸此按鈕來帶出這些地點的清單 + 您可從您的圖庫或相機,來上傳任何地點的圖片 + 找不到圖片! + 當載入圖片時發生錯誤。 + 由:%1$s 上傳 分享應用程式 + 當選擇圖片時未指定座標 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index d3d049ea2..29a1ae898 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -269,5 +269,13 @@ 已处理 取消 重试 + 明白了! + 这些是您附近需要图片以阐明维基百科条目的地方 + 点按此按钮会出现这些地点的列表 + 您可以从您的图库或照相机中上传任意地点的图片 + 找不到图片! + 加载图片时出错。 + 由%1$s上传 分享应用 + 图片选择时,坐标并未指定 From 66b275b19d52a32c99ea8cab95cd51258044706d Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 10 May 2018 14:16:08 +0530 Subject: [PATCH 070/184] Implemented butterknife in SimilarImageFragment [issue #1491] --- .../upload/SimilarImageDialogFragment.java | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java index a8f336927..59b8a1223 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java @@ -13,6 +13,9 @@ import android.view.ViewGroup; import android.view.Window; import android.widget.Button; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.imagepipeline.listener.RequestListener; @@ -29,29 +32,33 @@ import fr.free.nrw.commons.R; */ public class SimilarImageDialogFragment extends DialogFragment { + + @BindView(R.id.orginalImage) SimpleDraweeView originalImage; + @BindView(R.id.possibleImage) SimpleDraweeView possibleImage; + @BindView(R.id.postive_button) Button positiveButton; + @BindView(R.id.negative_button) Button negativeButton; onResponse mOnResponse;//Implemented interface from shareActivity Boolean gotResponse = false; + public SimilarImageDialogFragment() { } public interface onResponse{ - public void onPostiveResponse(); + public void onPositiveResponse(); + public void onNegativeResponse(); } + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_similar_image_dialog, container, false); + ButterKnife.bind(this,view); Set requestListeners = new HashSet<>(); requestListeners.add(new RequestLoggingListener()); - originalImage =(SimpleDraweeView) view.findViewById(R.id.orginalImage); - possibleImage =(SimpleDraweeView) view.findViewById(R.id.possibleImage); - positiveButton = (Button) view.findViewById(R.id.postive_button); - negativeButton = (Button) view.findViewById(R.id.negative_button); - originalImage.setHierarchy(GenericDraweeHierarchyBuilder .newInstance(getResources()) .setPlaceholderImage(VectorDrawableCompat.create(getResources(), @@ -70,22 +77,6 @@ public class SimilarImageDialogFragment extends DialogFragment { originalImage.setImageURI(Uri.fromFile(new File(getArguments().getString("originalImagePath")))); possibleImage.setImageURI(Uri.fromFile(new File(getArguments().getString("possibleImagePath")))); - negativeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mOnResponse.onNegativeResponse(); - gotResponse = true; - dismiss(); - } - }); - positiveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mOnResponse.onPostiveResponse(); - gotResponse = true; - dismiss(); - } - }); return view; } @@ -105,8 +96,23 @@ public class SimilarImageDialogFragment extends DialogFragment { @Override public void onDismiss(DialogInterface dialog) { // I user dismisses dialog by pressing outside the dialog. - if(!gotResponse) + if (!gotResponse) { mOnResponse.onNegativeResponse(); + } super.onDismiss(dialog); } + + @OnClick(R.id.negative_button) + public void onNegativeButtonClicked() { + mOnResponse.onNegativeResponse(); + gotResponse = true; + dismiss(); + } + + @OnClick(R.id.postive_button) + public void onPositiveButtonClicked() { + mOnResponse.onPositiveResponse(); + gotResponse = true; + dismiss(); + } } From b6e4fb2d68673463840f1f7d02471d83dd1d66e9 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sat, 12 May 2018 16:49:43 +0530 Subject: [PATCH 071/184] Bug fix #1504 (#1506) * Bug fix #1504 * Filtered messages with ConnectException [issue #1504] * A generalised message for exceptions in Nearby Activity [issue #1504] --- .../nrw/commons/nearby/NearbyActivity.java | 29 ++++++++++++++++--- .../nrw/commons/nearby/NearbyController.java | 3 +- .../free/nrw/commons/nearby/NearbyPlaces.java | 10 +------ app/src/main/res/values/strings.xml | 1 + 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 3bf8beacf..04886fda4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -16,6 +16,7 @@ import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; +import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -23,9 +24,14 @@ import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; +import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import io.reactivex.functions.Consumer; +import java.io.IOException; +import java.net.ConnectException; +import java.net.UnknownHostException; import java.util.List; import javax.inject.Inject; @@ -427,8 +433,14 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces); - } else if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { + .subscribe(this::populatePlaces, + throwable -> { + Timber.d(throwable); + showErrorMessage(getString(R.string.error_fetching_nearby_places)); + progressBar.setVisibility(View.GONE); + }); + } else if (locationChangeType + .equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); @@ -451,7 +463,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp if (placeList.size() == 0) { ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby); } - + bundle.putString("PlaceList", gsonPlaceList); //bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("BoundaryCoord", gsonBoundaryCoordinates); @@ -580,7 +592,12 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces); + .subscribe(this::populatePlaces, + throwable -> { + Timber.d(throwable); + showErrorMessage(getString(R.string.error_fetching_nearby_places)); + progressBar.setVisibility(View.GONE); + }); nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.updateMapSignificantly(); updateListFragment(); @@ -646,4 +663,8 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp public void prepareViewsForSheetPosition(int bottomSheetState) { // TODO } + + private void showErrorMessage(String message) { + ViewUtil.showLongToast(NearbyActivity.this, message); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index 015d22135..bd042b4d7 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -7,6 +7,7 @@ import android.support.graphics.drawable.VectorDrawableCompat; import com.mapbox.mapboxsdk.annotations.IconFactory; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -44,7 +45,7 @@ public class NearbyController { * @return NearbyPlacesInfo a variable holds Place list without distance information * and boundary coordinates of current Place List */ - public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng) { + public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng) throws IOException { Timber.d("Loading attractions near %s", curLatLng); NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo(); diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java index a2f4b2352..d05d81251 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java @@ -40,10 +40,9 @@ public class NearbyPlaces { } } - List getFromWikidataQuery(LatLng curLatLng, String lang) { + List getFromWikidataQuery(LatLng curLatLng, String lang) throws IOException { List places = Collections.emptyList(); - try { // increase the radius gradually to find a satisfactory number of nearby places while (radius <= MAX_RADIUS) { places = getFromWikidataQuery(curLatLng, lang, radius); @@ -54,13 +53,6 @@ public class NearbyPlaces { radius *= RADIUS_MULTIPLIER; } } - } catch (IOException e) { - Timber.d(e.toString()); - // errors tend to be caused by too many results (and time out) - // try a small radius next time - Timber.d("back to initial radius: %f", radius); - radius = INITIAL_RADIUS; - } // make sure we will be able to send at least one request next time if (radius > MAX_RADIUS) { radius = MAX_RADIUS; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dcea51bcc..6e30baa10 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -282,5 +282,6 @@ Share App Coordinates were not specified during image selection + Error fetching nearby places. From 93b0db9ecdacbb03ccf362f7262c9015fdecfcbd Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 14 May 2018 08:13:34 +0200 Subject: [PATCH 072/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-bn/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-iw/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-pms/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-qq/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 9 +++++++++ app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + 15 files changed, 23 insertions(+) diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index e7167393c..7c76ebaea 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -262,4 +262,5 @@ বুঝেছি! কোন চিত্র পাওয়া যায়নি! আপলোড করেছেন: %1$s + কাছাকাছি স্থানগুলি আনতে ত্রুটি। diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5f751153c..9f47ce42e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -278,4 +278,5 @@ Hochgeladen von: %1$s App teilen Während der Bildauswahl wurden keine Koordinaten angegeben + Fehler beim Abrufen der Orte in der Nähe. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index ee50aa3d7..e372df836 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -282,4 +282,5 @@ Ανέβηκε από: %1$s Κοινοποίηση εφαρμογής Οι συντεταγμένες δεν ορίστηκαν κατά την διάρκεια της επιλογής εικόνας + Σφάλμα κατά την εύρεση κοντινών μερών. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 69cf2f8b7..9e5dae650 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -275,4 +275,5 @@ Cargada por: %1$s Compartir aplicación No se especificaron las coordenadas al seleccionar la imagen + Error al recuperar los lugares cercanos. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6dd08a30d..bfb14baf1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -289,4 +289,5 @@ Importé par:%1$s Partager les applications Les coordonnées n\'ont pas été spécifiées pendant la sélection de l\'image + Erreur durant l\'exploration du voisinage. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index f0cdf1f3d..9ba67e4ee 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -282,4 +282,5 @@ הועלתה על־ידי: %1$s שיתוף היישום לא צוינו קואורדינטות בעת בחירת התמונה + שגיאה באחזור המקומות בסביבתך. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index e80999d54..883665c85 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -275,4 +275,5 @@ 올린이: %1$s 앱 공유 그림 선택 중에 좌표가 지정되지 않았습니다 + 주변 장소를 가져오는데 오류가 있습니다. diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 492e1bc0c..a344fcad2 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -272,4 +272,5 @@ Подигач: %1$s Сподели прилог Не беа укажани координати при изборот на сликата + Грешка при добивањето на околните места. diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 53ce91cc5..8b2bd292c 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -272,4 +272,5 @@ Carià da: %1$s Partagé j\'aplicassion Le coordinà a son nen ëstàite spessificà durant la selession ëd la plancia + Eror durant l\'esplorassion dj\'anviron. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 23b5e4abf..849c4e6b1 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -284,4 +284,5 @@ Carregada por: %1$s Compartilhar o aplicativo Não foram especificadas coordenadas durante a seleção da imagem + Erro ao buscar lugares próximos. diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 3da1296b7..e59582fa0 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -283,4 +283,5 @@ Carregada por: %1$s Partilhar aplicação Não foram especificadas coordenadas durante a seleção da imagem + Erro ao localizar locais próximos. diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index 37c2978bf..d84ce08ab 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -99,6 +99,7 @@ Message explaining what kind of images not to submit. Message asking user if they understand what kinds of images to upload. Button text for confirming the user understands what kinds of images to upload.\n{{Identical|Yes}} + \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' Label for categories list in media detail panel.\n{{Identical|Category}} Placeholder for categories list in media detail panel, while loading from network.\n{{Identical|Loading}} Placeholder for categories list in media detail panel, if no categories found.\n{{Identical|None selected}} diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 95548b662..dadd40917 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -271,4 +271,13 @@ İlerle Vazgeç Tekrar Deneyin + Anladım! + Vikipedi maddelerine eklemek için fotoğrafa ihtiyaç duyan size yakın yerler + Bu tuşa dokunmak bu yerlerin bir listesini getirir + Galerinizden veya kameranızla herhangi bir yer için resim yükleyebilirsiniz. + Resim bulunamadı! + Resimler yüklenirken hata oluştu. + Yükleyen: %1$s + Uygulamayı Paylaş + Koordinatlar görüntü seçimi sırasında belirlenmedi diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 80b595f5d..4581d45ce 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -280,4 +280,5 @@ 由:%1$s 上傳 分享應用程式 當選擇圖片時未指定座標 + 索取附近地點時出錯。 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 29a1ae898..2079eb925 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -278,4 +278,5 @@ 由%1$s上传 分享应用 图片选择时,坐标并未指定 + 检索附近地点时出错。 From d891b8f31032fcde2e274732b69a450b3dbb0a38 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Tue, 15 May 2018 12:55:37 +0530 Subject: [PATCH 073/184] Fix security exception crash while accessing network location provider (#1498) * Fix security exception crash while accessing network location provider * Added java docs --- .../location/LocationServiceManager.java | 33 ++++++++++++---- .../nrw/commons/nearby/NearbyActivity.java | 39 +++++++++++++++++-- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java index 73ded852f..49c422633 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.location; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; @@ -10,9 +11,10 @@ import android.location.LocationManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import timber.log.Timber; @@ -29,6 +31,7 @@ public class LocationServiceManager implements LocationListener { private Location lastLocation; private final List locationListeners = new CopyOnWriteArrayList<>(); private boolean isLocationManagerRegistered = false; + private Set locationExplanationDisplayed = new HashSet<>(); /** * Constructs a new instance of LocationServiceManager. @@ -51,7 +54,6 @@ public class LocationServiceManager implements LocationListener { /** * Returns whether the location permission is granted. - * * @return true if the location permission is granted */ public boolean isLocationPermissionGranted() { @@ -73,10 +75,23 @@ public class LocationServiceManager implements LocationListener { LOCATION_REQUEST); } + /** + * The permission explanation dialog box is now displayed just once for a particular activity. We are subscribing + * to updates from multiple providers so its important to show the dialog just once. Otherwise it will be displayed + * once for every provider, which in our case currently is 2. + * @param activity + * @return + */ public boolean isPermissionExplanationRequired(Activity activity) { - return !activity.isFinishing() && - ActivityCompat.shouldShowRequestPermissionRationale(activity, - Manifest.permission.ACCESS_FINE_LOCATION); + if (activity.isFinishing()) { + return false; + } + boolean showRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION); + if (showRequestPermissionRationale && !locationExplanationDisplayed.contains(activity)) { + locationExplanationDisplayed.add(activity); + return true; + } + return false; } /** @@ -84,8 +99,9 @@ public class LocationServiceManager implements LocationListener { * (e.g. when Location permission just granted) * @return last known LatLng */ + @SuppressLint("MissingPermission") public LatLng getLKL() { - if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (isLocationPermissionGranted()) { Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (lastKL == null) { lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); @@ -107,9 +123,10 @@ public class LocationServiceManager implements LocationListener { * Registers a LocationManager to listen for current location. */ public void registerLocationManager() { - if (!isLocationManagerRegistered) + if (!isLocationManagerRegistered) { isLocationManagerRegistered = requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER) && requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); + } } /** @@ -142,7 +159,7 @@ public class LocationServiceManager implements LocationListener { * @return LOCATION_SIGNIFICANTLY_CHANGED if location changed significantly * LOCATION_SLIGHTLY_CHANGED if location changed slightly */ - protected LocationChangeType isBetterLocation(Location location, Location currentBestLocation) { + private LocationChangeType isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 04886fda4..35e15b0d9 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -322,7 +322,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp protected void onStart() { super.onStart(); locationManager.addLocationListener(this); - locationManager.registerLocationManager(); + registerLocationUpdates(); } @Override @@ -400,7 +400,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp return; } - locationManager.registerLocationManager(); + registerLocationUpdates(); LatLng lastLocation = locationManager.getLastLocation(); if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed @@ -450,6 +450,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp } } + /** + * This method first checks if the location permissions has been granted and then register the location manager for updates. + */ + private void registerLocationUpdates() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (locationManager.isLocationPermissionGranted()) { + locationManager.registerLocationManager(); + } else { + // Should we show an explanation? + if (locationManager.isPermissionExplanationRequired(this)) { + new AlertDialog.Builder(this) + .setMessage(getString(R.string.location_permission_rationale_nearby)) + .setPositiveButton("OK", (dialog, which) -> { + requestLocationPermissions(); + dialog.dismiss(); + }) + .setNegativeButton("Cancel", (dialog, id) -> { + showLocationPermissionDeniedErrorDialog(); + dialog.cancel(); + }) + .create() + .show(); + + } else { + // No explanation needed, we can request the permission. + requestLocationPermissions(); + } + } + } else { + locationManager.registerLocationManager(); + } + } + private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { List placeList = nearbyPlacesInfo.placeList; LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates; @@ -530,7 +563,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp locationManager.removeLocationListener(this); } else { lockNearbyView = false; - locationManager.registerLocationManager(); + registerLocationUpdates(); locationManager.addLocationListener(this); } } From 625f58259889378790e12c9d13dc94908e0b0dee Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 19:52:21 +1000 Subject: [PATCH 074/184] Remove MultipleShareActivity from manifest and send SEND_MULTIPLE intent to ShareActivity as well --- app/src/main/AndroidManifest.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e617b385e..aaba6abc8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,18 +46,6 @@ android:label="@string/app_name"> - - - - - - - - - From 66245d25a5c6b1a9b94ec0093da71fe147e716e8 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 19:56:47 +1000 Subject: [PATCH 075/184] Remove check for Storage permissions and snackbar in onCreate() --- .../nrw/commons/upload/ShareActivity.java | 37 +++---------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index ffc965d90..27cb3d4f4 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -334,10 +334,6 @@ public class ShareActivity useNewPermissions = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { useNewPermissions = true; - - if (!needsToRequestStoragePermission()) { - storagePermitted = true; - } if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationPermitted = true; } @@ -345,35 +341,14 @@ public class ShareActivity //TODO: We should only use snackbar for location permissions, since storage permissions are MANDATORY // Check storage permissions if marshmallow or newer - if (useNewPermissions && (!storagePermitted || !locationPermitted)) { - if (!storagePermitted && !locationPermitted) { - String permissionRationales = - getResources().getString(R.string.read_storage_permission_rationale) + "\n" - + getResources().getString(R.string.location_permission_rationale); - snackbar = requestPermissionUsingSnackBar( - permissionRationales, - new String[]{ - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.ACCESS_FINE_LOCATION}, - REQUEST_PERM_ON_CREATE_STORAGE_AND_LOCATION); - View snackbarView = snackbar.getView(); - TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text); - textView.setMaxLines(3); - } else if (!storagePermitted) { - requestPermissionUsingSnackBar( - getString(R.string.read_storage_permission_rationale), - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, - REQUEST_PERM_ON_CREATE_STORAGE); - } else if (!locationPermitted) { - requestPermissionUsingSnackBar( - getString(R.string.location_permission_rationale), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - REQUEST_PERM_ON_CREATE_LOCATION); - } + if (!locationPermitted) { + requestPermissionUsingSnackBar( + getString(R.string.location_permission_rationale), + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + REQUEST_PERM_ON_CREATE_LOCATION); } performPreUploadProcessingOfFile(); - SingleUploadFragment shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView"); categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization"); if (shareView == null && categorizationFragment == null) { @@ -389,8 +364,6 @@ public class ShareActivity if( imageObj == null || imageObj.imageCoordsExists != true){ maps_fragment.setVisibility(View.INVISIBLE); } - - maps_fragment.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { From c0c74f68d2211c6bf8939d9e61115c2f66282bd1 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 19:57:22 +1000 Subject: [PATCH 076/184] Clear lint warnings --- .../main/java/fr/free/nrw/commons/upload/ShareActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 27cb3d4f4..b21f510b1 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -361,13 +361,13 @@ public class ShareActivity uploadController.prepareService(); maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); maps_fragment.setVisibility(View.VISIBLE); - if( imageObj == null || imageObj.imageCoordsExists != true){ + if( imageObj == null || imageObj.imageCoordsExists){ maps_fragment.setVisibility(View.INVISIBLE); } maps_fragment.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if( imageObj != null && imageObj.imageCoordsExists == true) { + if( imageObj != null && imageObj.imageCoordsExists) { Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); mapIntent.setPackage("com.google.android.apps.maps"); From aa731659645d6592a9f2ad109824befe1e6295f6 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:03:46 +1000 Subject: [PATCH 077/184] Create new receiveIntent() method to tidy onCreate --- .../nrw/commons/upload/ShareActivity.java | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index b21f510b1..918fe68c7 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -257,23 +257,10 @@ public class ShareActivity finish(); } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_share); - ButterKnife.bind(this); - initBack(); - backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); - backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder - .newInstance(getResources()) - .setPlaceholderImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_image_black_24dp, getTheme())) - .setFailureImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_error_outline_black_24dp, getTheme())) - .build()); - - //Receive intent from ContributionController.java when user selects picture to upload + /** + * Receive intent from ContributionController.java when user selects picture to upload + */ + private void receiveIntent() { Intent intent = getIntent(); if (Intent.ACTION_SEND.equals(intent.getAction())) { @@ -293,6 +280,25 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_share); + ButterKnife.bind(this); + initBack(); + backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); + backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder + .newInstance(getResources()) + .setPlaceholderImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_image_black_24dp, getTheme())) + .setFailureImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_error_outline_black_24dp, getTheme())) + .build()); + + receiveIntent(); mainFab = (FloatingActionButton) findViewById(R.id.main_fab); /* @@ -339,8 +345,7 @@ public class ShareActivity } } - //TODO: We should only use snackbar for location permissions, since storage permissions are MANDATORY - // Check storage permissions if marshmallow or newer + // Check location permissions if M or newer for category suggestions, request via snackbar if not present if (!locationPermitted) { requestPermissionUsingSnackBar( getString(R.string.location_permission_rationale), From 11d3517b70f402bf314add72a03bbc6e4804a271 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:07:34 +1000 Subject: [PATCH 078/184] Create initViewsAndListeners() method to tidy onCreate --- .../nrw/commons/upload/ShareActivity.java | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 918fe68c7..3da0ef8fe 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -282,28 +282,12 @@ public class ShareActivity } } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_share); - ButterKnife.bind(this); - initBack(); - backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); - backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder - .newInstance(getResources()) - .setPlaceholderImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_image_black_24dp, getTheme())) - .setFailureImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_error_outline_black_24dp, getTheme())) - .build()); - - receiveIntent(); - + /** + * Initialize views and setup listeners here for FAB to prevent cluttering onCreate + */ + private void initViewsAndListeners() { mainFab = (FloatingActionButton) findViewById(R.id.main_fab); - /* - * called when upper arrow floating button - */ + //called when upper arrow floating button mainFab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -327,6 +311,26 @@ public class ShareActivity Log.i("exception", e.toString()); } zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_share); + ButterKnife.bind(this); + initBack(); + backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); + backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder + .newInstance(getResources()) + .setPlaceholderImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_image_black_24dp, getTheme())) + .setFailureImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_error_outline_black_24dp, getTheme())) + .build()); + + receiveIntent(); + initViewsAndListeners(); if (savedInstanceState != null) { contribution = savedInstanceState.getParcelable("contribution"); From 3bd421424685070fcd061f3e730900476f390a18 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:09:22 +1000 Subject: [PATCH 079/184] More FAB tidying --- .../nrw/commons/upload/ShareActivity.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 3da0ef8fe..a9c5c1260 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -291,9 +291,9 @@ public class ShareActivity mainFab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if(!isFABOpen){ + if(!isFABOpen) { showFABMenu(); - }else{ + } else { closeFABMenu(); } } @@ -307,10 +307,27 @@ public class ShareActivity zoomImageFromThumb(backgroundImageView, mediaUri); } }); - } catch (Exception e){ + } catch (Exception e) { Log.i("exception", e.toString()); } zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); + + maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); + maps_fragment.setVisibility(View.VISIBLE); + if( imageObj == null || imageObj.imageCoordsExists){ + maps_fragment.setVisibility(View.INVISIBLE); + } + maps_fragment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if( imageObj != null && imageObj.imageCoordsExists) { + Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + startActivity(mapIntent); + } + } + }); } @Override @@ -368,22 +385,6 @@ public class ShareActivity .commitAllowingStateLoss(); } uploadController.prepareService(); - maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); - maps_fragment.setVisibility(View.VISIBLE); - if( imageObj == null || imageObj.imageCoordsExists){ - maps_fragment.setVisibility(View.INVISIBLE); - } - maps_fragment.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if( imageObj != null && imageObj.imageCoordsExists) { - Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); - Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); - mapIntent.setPackage("com.google.android.apps.maps"); - startActivity(mapIntent); - } - } - }); } /** From 478c4900dfd5017c8ce6a397de5be55574e49375 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:13:03 +1000 Subject: [PATCH 080/184] Tidy initViewsAndListeners() --- .../fr/free/nrw/commons/upload/ShareActivity.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index a9c5c1260..9849387b8 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -286,8 +286,12 @@ public class ShareActivity * Initialize views and setup listeners here for FAB to prevent cluttering onCreate */ private void initViewsAndListeners() { + //Main FAB splits into Zoom and Map mainFab = (FloatingActionButton) findViewById(R.id.main_fab); - //called when upper arrow floating button + zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); + zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); + maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); + mainFab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -299,7 +303,6 @@ public class ShareActivity } }); - zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); try { zoomInButton.setOnClickListener(new View.OnClickListener() { @Override @@ -308,11 +311,9 @@ public class ShareActivity } }); } catch (Exception e) { - Log.i("exception", e.toString()); + Timber.e(e); } - zoomOutButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_out); - maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); maps_fragment.setVisibility(View.VISIBLE); if( imageObj == null || imageObj.imageCoordsExists){ maps_fragment.setVisibility(View.INVISIBLE); From c22d4ce07136006f15b545beb4af13e75daa44c0 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:13:59 +1000 Subject: [PATCH 081/184] Shift helper methods to more logical place --- .../nrw/commons/upload/ShareActivity.java | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 9849387b8..51527b680 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -257,6 +257,63 @@ public class ShareActivity finish(); } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_share); + ButterKnife.bind(this); + initBack(); + backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); + backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder + .newInstance(getResources()) + .setPlaceholderImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_image_black_24dp, getTheme())) + .setFailureImage(VectorDrawableCompat.create(getResources(), + R.drawable.ic_error_outline_black_24dp, getTheme())) + .build()); + + receiveIntent(); + initViewsAndListeners(); + + if (savedInstanceState != null) { + contribution = savedInstanceState.getParcelable("contribution"); + } + + requestAuthToken(); + + Timber.d("Uri: %s", mediaUri.toString()); + Timber.d("Ext storage dir: %s", Environment.getExternalStorageDirectory()); + + useNewPermissions = false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + useNewPermissions = true; + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + locationPermitted = true; + } + } + + // Check location permissions if M or newer for category suggestions, request via snackbar if not present + if (!locationPermitted) { + requestPermissionUsingSnackBar( + getString(R.string.location_permission_rationale), + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + REQUEST_PERM_ON_CREATE_LOCATION); + } + performPreUploadProcessingOfFile(); + + SingleUploadFragment shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView"); + categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization"); + if (shareView == null && categorizationFragment == null) { + shareView = new SingleUploadFragment(); + getSupportFragmentManager() + .beginTransaction() + .add(R.id.single_upload_fragment_container, shareView, "shareView") + .commitAllowingStateLoss(); + } + uploadController.prepareService(); + } + /** * Receive intent from ContributionController.java when user selects picture to upload */ @@ -330,64 +387,7 @@ public class ShareActivity } }); } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_share); - ButterKnife.bind(this); - initBack(); - backgroundImageView = (SimpleDraweeView) findViewById(R.id.backgroundImage); - backgroundImageView.setHierarchy(GenericDraweeHierarchyBuilder - .newInstance(getResources()) - .setPlaceholderImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_image_black_24dp, getTheme())) - .setFailureImage(VectorDrawableCompat.create(getResources(), - R.drawable.ic_error_outline_black_24dp, getTheme())) - .build()); - - receiveIntent(); - initViewsAndListeners(); - - if (savedInstanceState != null) { - contribution = savedInstanceState.getParcelable("contribution"); - } - - requestAuthToken(); - - Timber.d("Uri: %s", mediaUri.toString()); - Timber.d("Ext storage dir: %s", Environment.getExternalStorageDirectory()); - - useNewPermissions = false; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - useNewPermissions = true; - if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { - locationPermitted = true; - } - } - - // Check location permissions if M or newer for category suggestions, request via snackbar if not present - if (!locationPermitted) { - requestPermissionUsingSnackBar( - getString(R.string.location_permission_rationale), - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - REQUEST_PERM_ON_CREATE_LOCATION); - } - performPreUploadProcessingOfFile(); - - SingleUploadFragment shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView"); - categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization"); - if (shareView == null && categorizationFragment == null) { - shareView = new SingleUploadFragment(); - getSupportFragmentManager() - .beginTransaction() - .add(R.id.single_upload_fragment_container, shareView, "shareView") - .commitAllowingStateLoss(); - } - uploadController.prepareService(); - } - + /** * Function to display the zoom and map FAB */ From e62022ab55aa2370b22dae728e6155907bff0790 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:25:42 +1000 Subject: [PATCH 082/184] Tidy up onRequestPermissionsResult() --- .../nrw/commons/upload/ShareActivity.java | 35 +++---------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 51527b680..be4d65e27 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -387,11 +387,11 @@ public class ShareActivity } }); } - + /** * Function to display the zoom and map FAB */ - private void showFABMenu(){ + private void showFABMenu() { isFABOpen=true; if( imageObj != null && imageObj.imageCoordsExists == true) @@ -445,42 +445,18 @@ public class ShareActivity public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { - case REQUEST_PERM_ON_CREATE_STORAGE: { - if (grantResults.length >= 1 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - backgroundImageView.setImageURI(mediaUri); - storagePermitted = true; - performPreUploadProcessingOfFile(); - } - return; - } case REQUEST_PERM_ON_CREATE_LOCATION: { - if (grantResults.length >= 1 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - locationPermitted = true; - performPreUploadProcessingOfFile(); - } - return; - } - case REQUEST_PERM_ON_CREATE_STORAGE_AND_LOCATION: { - if (grantResults.length >= 2 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - backgroundImageView.setImageURI(mediaUri); - storagePermitted = true; - performPreUploadProcessingOfFile(); - } - if (grantResults.length >= 2 - && grantResults[1] == PackageManager.PERMISSION_GRANTED) { + if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { locationPermitted = true; performPreUploadProcessingOfFile(); } return; } + // Storage (from submit button) - this needs to be separate from (1) because only the // submit button should bring user to next screen case REQUEST_PERM_ON_SUBMIT_STORAGE: { - if (grantResults.length >= 1 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { //It is OK to call this at both (1) and (4) because if perm had been granted at //snackbar, user should not be prompted at submit button performPreUploadProcessingOfFile(); @@ -489,7 +465,6 @@ public class ShareActivity uploadBegins(); snackbar.dismiss(); } - return; } } } From b1c3e8a0ac270f7b5dafb2ca49649c30b7626bda Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:41:15 +1000 Subject: [PATCH 083/184] Tidying up code --- .../fr/free/nrw/commons/upload/ShareActivity.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index be4d65e27..567cd27e9 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -394,7 +394,7 @@ public class ShareActivity private void showFABMenu() { isFABOpen=true; - if( imageObj != null && imageObj.imageCoordsExists == true) + if( imageObj != null && imageObj.imageCoordsExists) maps_fragment.setVisibility(View.VISIBLE); zoomInButton.setVisibility(View.VISIBLE); @@ -482,12 +482,10 @@ public class ShareActivity ExistingFileAsync fileAsyncTask = new ExistingFileAsync(new WeakReference(this), fileSHA1, new WeakReference(this), result -> { Timber.d("%s duplicate check: %s", mediaUri.toString(), result); - duplicateCheckPassed = (result == DUPLICATE_PROCEED - || result == NO_DUPLICATE); - /* - TODO: 16/9/17 should we run DetectUnwantedPicturesAsync if DUPLICATE_PROCEED is returned? Since that means - we are processing images that are already on server???... - */ + duplicateCheckPassed = (result == DUPLICATE_PROCEED || result == NO_DUPLICATE); + + //TODO: 16/9/17 should we run DetectUnwantedPicturesAsync if DUPLICATE_PROCEED is returned? Since that means + //we are processing images that are already on server???... if (duplicateCheckPassed) { //image can be uploaded, so now check if its a useless picture or not @@ -500,7 +498,6 @@ public class ShareActivity Timber.d(e, "IO Exception: "); } } - getFileMetadata(locationPermitted); } else { Timber.w("not ready for preprocessing: useNewPermissions=%s storage=%s location=%s", From ea5f3a6ea9e2d09b33b81cab1a492fc3a1f46611 Mon Sep 17 00:00:00 2001 From: misaochan Date: Tue, 15 May 2018 20:43:21 +1000 Subject: [PATCH 084/184] Add Javadocs --- .../java/fr/free/nrw/commons/upload/ShareActivity.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 567cd27e9..198792314 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -441,9 +441,14 @@ public class ShareActivity return isNearbyUpload; } + /** + * Handles BOTH snackbar permission request (for location) and submit button permission request (for storage) + * @param requestCode type of request + * @param permissions permissions requested + * @param grantResults grant results + */ @Override - public void onRequestPermissionsResult(int requestCode, - @NonNull String[] permissions, @NonNull int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_PERM_ON_CREATE_LOCATION: { if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { From 80a97c503714916b432cd382daf977030ef867c3 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 17 May 2018 08:24:27 +0200 Subject: [PATCH 085/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ast/strings.xml | 14 ++++++++++++++ app/src/main/res/values-diq/strings.xml | 8 ++++++-- app/src/main/res/values-hu/strings.xml | 12 ++++++++++-- app/src/main/res/values-is/strings.xml | 10 ++++++++++ app/src/main/res/values-ru/strings.xml | 19 ++++++++----------- app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 7 +++++++ 8 files changed, 57 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 532a4897e..947bc441a 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -84,6 +84,7 @@ Categoríes Configuración Date d\'alta + Imáxenes destacaes Tocante a La app de Wikimedia Commons ye software de códigu abiertu, creáu y calteníu por becaos y voluntarios de la comunidá de Wikimedia. La Fundación Wikimedia nun participa na creación, desendolcu nin caltenimientu de la app. Crea una nueva <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia en GitHub</a> pa informar de problemes y suxerencies. @@ -169,6 +170,8 @@ Títulu del mediu Descripción Equí va la descripción del mediu. Esto pué ser llargo enforma, y necesitará espardese per delles llinies. Sicasí, esperamos que se vea bien. + Autor + El nome d\'usuariu del autor de la imaxe destacada va equí. Data d\'unviu Llicencia Coordenaes @@ -211,6 +214,7 @@ Salir Tutorial Avisos + Destacada Los sitios cercanos nun pueden amosase ensin los permisos d\'allugamientu nun s\'atoparon descripciones Páxina del ficheru en Commons @@ -259,4 +263,14 @@ Siguir Encaboxar Retentar + Entendílo + Estos son sitios cercanos a ti que precisen imaxes para ilustrar los sos artículos de Wikipedia + Tocando esti botón amuésase la llista d\'esos llugares + Puedes xubir una imaxe pa cualquier sitiu dende la galería o la cámara + Nun s\'alcontró nenguna imaxe + Asocedió un error al cargar les imáxenes. + Xubida por: %1$s + Compartir app + Nun s\'especificaron les coordenaes al escoyer la imaxe + Error al llograr los llugares cercanos. diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index 1f1d69ea3..53bd88bac 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -13,6 +13,7 @@ Bıngeh Lokasyon Commons + Eyari Namey karberi Parola @@ -84,7 +85,8 @@ Qeyd be Heq te cı Qandê yew <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-cıkewtış</a>ê neweyi rê rapor û teklifan bıaferne. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Politikay nımıtışi</a> + <u>Politikaya nımıtışi</u> + <u>İştırakkerdoği</u> Heq te cı Peyd rışten bırış (E-posta ra) E-posta eyar nêbi @@ -92,7 +94,7 @@ Anciya bıcerrebne Bıtexelne Ron - Lisans + Lisanso hesebiyaye Attribution-ShareAlike 3.0 Attribution 3.0 CC0 @@ -127,6 +129,8 @@ E Sername + Şınasnayış + Nuştekar Lisans Koordinati Korbıze diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 81e655b95..d9580dca1 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -162,8 +162,8 @@ Nincs leírás Ismeretlen licenc Frissítés - Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. - Szükséges engedély: Külső tárhely írása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely írása. Az alkalmazás nem tudja használni a kamerát enélkül. Lehetséges engedély: Jelenlegi hely megszerzése, a kategóriajavaslatok lehetőségéért. OK Közeli helyek @@ -242,6 +242,7 @@ A hely nem változott. A hely nem érhető el. Közeli helyek listájának megtekintéséhez engedély szükséges + SZÓCIKK OLVASÁSA Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. %1$s üzenetet hagyott a vitalapodon Köszönjük a szerkesztésedet! @@ -258,5 +259,12 @@ Folytatás Mégse Újra + Ezek a helyek vannak a közeledben, amikről van Wikipédia szócikk és nincs bennük kép. + A gombra koppintva bejön egy lista, ami ezeket a helyeket mutatja. + Bármelyik helyhez feltölthetsz képet a galériádból vagy készíthetsz újat a kamerával. + Nem található kép! + Képbetöltés közben hiba történt Alkalmazás megosztása + A koordináták nem lettek megadva a kép kiválasztásakor. + Hiba a közeli helyek elérésekor. diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index ba5bdfe42..f1b020965 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -263,4 +263,14 @@ Halda áfram Hætta við Reyna aftur + Náði því! + Þetta eru þeir staðir í næsta nágrenni við þig sem vantar myndir til að skýra með Wikipedia-greinar + Ef ýtt er á þennan hnapp birtist listi yfir þessa staði + Þú getur sent inn mynd úr myndasafninu þínu eða myndavélinni + Engir myndir fundust! + Villa kom upp við að hlaða inn myndum. + Sent inn af: %1$s + Deila forriti + Hnit voru ekki tilgreind við val myndar + Villa við að sækja nálæga staði. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce71af94b..0d5a0ee3e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -46,11 +46,7 @@ Завершение загрузки %1$s Загрузка %1$s не удалась Нажмите для просмотра - - %1$d файл загружается - %1$d файла загружается - %1$d файлов загружается - + %1$d {{PLURAL:%1$d|one=файл загружается|few=файла загружается|файлов загружается}} Мои недавние загрузки В очереди Ошибка загрузки. @@ -115,7 +111,7 @@ Почтовый клиент не установлен Недавно использованные категории Ожидание первой синхронизации… - Вы ещё не загрузили ни одной фотографии. + Вы ещё не загрузили ни одного изображения. Повторить Отмена Это изображение будет лицензировано под %1$s @@ -123,7 +119,7 @@ Скачать Лицензия по умолчанию Использовать предыдущие название/описание - Автоматически получить текущее местоположение + Анализ местоположения Получить текущее местоположение, чтобы были предложены категории, если изображение не содержит геотегов Ночной режим Использовать тёмную тему @@ -148,7 +144,7 @@ CC BY 4.0 CC Zero Викисклад содержит бо́льшую часть изображений, которые используются в Википедии. - Ваши изображения помогают образованию людей во всём мире! + Ваши изображения могут помочь образованию людей во всём мире! Пожалуйста, загрузите фотографии, которые были сняты или созданы исключительно вами: Природные объекты (например, цветы, животные, горы)\n• Полезные предметы (например, велосипеды, вокзалы)\n• Известные люди (например, ваш мэр, спортсмены-олимпийцы, которых вы встретили) Природные объекты (например, цветы, животные, горы) @@ -166,7 +162,7 @@ Категории: Sydney Opera House from the west, Sydney Opera House remote views Загрузите свои изображения. Помогите Википедии оживить статьи! Изображения в Википедии хранятся на Викискладе. - Ваши изображения помогают образованию людей во всём мире. + Ваши изображения могут помочь образованию людей во всём мире. Избегайте материалов, защищённых авторским правом, например, найденных в Интернете, изображений плакатов, книжных обложек и т.п. Вам это понятно? Да! @@ -211,7 +207,7 @@ Facebook-страница Commons Исходные коды Commons на гитхабе Фоновое изображение - Ошибка медиаизображения + Ошибка медиафайла Изображение не найдено Загрузить изображение Гора Зао @@ -246,7 +242,7 @@ Пожалуйста, подробно опишите загружаемый файл: где он был снят? что на нём изображено? каков его контекст? Пожалуйста опишите изображённых персон или объекты. Добавьте информацию, о которой нельзя легко догадаться, например, время суток, когда снимался файл. Если снято что-то необычное, постарайтесь пояснить, что именно в этом необычного. Это изображение слишком тёмное. Вы уверены, что хотите его загрузить? Викисклад подходит только для фотографий, имеющих энциклопедическую ценность. Это изображение размыто. Вы уверены, что хотите его загрузить? Викисклад подходит только для фотографий, имеющих энциклопедическую ценность. - Дать разрешение + Разрешить Использовать внешнее хранилище Сохранять изображения, сделанные с помощью встроенной камеры на устройстве Войдите в свою учётную запись @@ -294,4 +290,5 @@ Загружено участником %1$s Поделиться приложением Во время выбора изображения не были указаны координаты + Ошибка получения мест поблизости diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 17a324a97..1d2fc868e 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -280,4 +280,5 @@ Uppladdad av: %1$s Dela app Koordinater specificerades inte vid bildvalet + Fel uppstod när platser i närheten hämtades. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dadd40917..c9dd60b41 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -280,4 +280,5 @@ Yükleyen: %1$s Uygulamayı Paylaş Koordinatlar görüntü seçimi sırasında belirlenmedi + Yakındaki yerler alınırken hata oluştu. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a4ed20320..1aba51e02 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -279,4 +279,11 @@ Виконується Скасувати Повторити + Зрозуміло + Натискання цієї кнопки згенерує список таких місць + Зображень не знайдено! + Сталася помилка при завантаженні зображень. + Завантажено: %1$s + Поділитися програмою + Помилка отримання місць поблизу. From c4f55d2fe8a2f0e658a4b443c7aa2fbb70a94ec9 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 7 May 2018 07:54:16 +0200 Subject: [PATCH 086/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-hu/strings.xml | 8 ++++++++ app/src/main/res/values-iw/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-pms/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 2 ++ app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + 13 files changed, 21 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f265e7ebd..36e013976 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -269,4 +269,5 @@ Fortfahren Abbrechen Erneut versuchen + App teilen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 58aa93860..0dae5c65e 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -273,4 +273,5 @@ Συνέχεια Ακύρωση Ξαναπροσπαθήστε + Κοινοποίηση εφαρμογής diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8494a7a36..442fc6bc5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -279,4 +279,5 @@ Continuer Annuler Réessayer + Partager les applications diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 5524afb0e..81e655b95 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -13,6 +13,7 @@ * ViDam --> + Megjelenés Általános Visszajelzés Helyszín @@ -145,6 +146,7 @@ Híres emberek (a polgármestered, olimpikonok, akikkel találkoztál) Kérjük, NE tölts fel: - Szelfiket vagy képeket a barátaidról\n- Internetröl letöltött képeket\n- Kereskedelmi alkalmazások képernyőképeit + Az Internetről letöltött képek Példa feltöltés: - Cím: Sydney-i Operaház\n- Leírás: A Sydney-i Operaház az öböl túlpartjáról\n- Kategóriák: Sydney Opera House from the west, Sydney Opera House remote views Cím: Sydney-i Operaház @@ -191,6 +193,7 @@ Commons Logo Commons weboldal Commons Facebook-oldal + Commons Github forráskód Háttérkép Nem található kép Kép feltöltése @@ -223,6 +226,8 @@ Hiba a képek gyorsítótárazásakor Egy egyedi, leíró cím a fájlnak, ami fájlnévként fog szolgálni. Egyszerű nyelvezetet használhatsz szóközökkel. Ne tedd bele a kiterjesztést. Kérlek a lehető legteljesebb módon írd le a fájlt: hol készült, mit ábrázol, mi a kontextus? Kérlek add meg az objektumokat vagy személyeket a képen, valamint a nehezen kitalálható információkat (például a kép készítésének dátumát, ha az egy tájkép). Amennyiben a média valami szokatlant ábrázol, kérlek fejtsd ki, hogy mi teszi szokatlanná. + Ez a fénykép túl sötét, biztos fel akarod tölteni? A Wikimédia Commons csak enciklopédikus értékkel bíró képeket tart meg. + Ez a fénykép homályos, biztos fel akarod tölteni? A Wikimédia Commons csak enciklopédikus értékkel bíró képeket tart meg. Engedély adása Külső tárhely használata Az alkalmazáson belüli kamerával készült képek mentése az eszközre @@ -238,6 +243,7 @@ A hely nem érhető el. Közeli helyek listájának megtekintéséhez engedély szükséges Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. + %1$s üzenetet hagyott a vitalapodon Köszönjük a szerkesztésedet! WIKIDATA WIKIPÉDIA @@ -249,6 +255,8 @@ Internet elérhető Nincs értesítés Nyelvek + Folytatás Mégse Újra + Alkalmazás megosztása diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 48750daf9..762a3be31 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -273,4 +273,5 @@ המשך ביטול לנסות שוב + שיתוף היישום diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 11faee9c6..d0e1c21ed 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -266,4 +266,5 @@ 진행 취소 다시 시도 + 앱 공유 diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index dd1e6f03e..4e44dad60 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -263,4 +263,5 @@ Продолжи Откажи Пробај пак + Сподели прилог diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 0cd748031..30115f1ad 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -263,4 +263,5 @@ Andé anans Anulé Prové torna + Partagé j\'aplicassion diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 4bc478527..6722ae4bb 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -275,4 +275,5 @@ Avançar Cancelar Tentar novamente + Compartilhar o aplicativo diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 5e4862ecb..b0717f3dc 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -159,6 +159,7 @@ Evite materiais protegidos por direitos de autor que tenham sido encontrados na Internet, bem como imagens de cartazes, capas de livros, etc. Acha que conseguiu? Sim! + Categorias A carregar… Nenhuma selecionada diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index fa5174ced..24ef60b61 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -156,6 +156,7 @@ Undvik upphovsrättsskyddat material som du hittar på Internet, samt bilder av affischer, bokomslag, etc. Tror du att du förstår? Ja! + Kategorier Läser in… Ingen markerad @@ -270,4 +271,5 @@ Fortsätt Avbryt Försök igen + Dela app diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4966d9c08..a2878cddf 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -271,4 +271,5 @@ 已進行 取消 重試 + 分享應用程式 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 83650b408..d3d049ea2 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -269,4 +269,5 @@ 已处理 取消 重试 + 分享应用 From 30d7b5d35c7734730933405ed82bf2744076179a Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Mon, 7 May 2018 13:39:23 +0530 Subject: [PATCH 087/184] Integrate API for displaying featured images (#1456) * Integrate API for displaying featured images * Add pagination and refactor code so that it can be reused for category images * Add license info to the images * Fix author view * Remove unused values * Fix minor issues with featured images * Fix null license url issue * Remove some log lines * Fix back navigation issue * fix tests * fix test inits * Gracefully handling various error situations * Added java docs --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 5 +- .../category/CategoryImageController.java | 29 +++ .../commons/category/CategoryImageUtils.java | 225 +++++++++++++++++ .../category/CategoryImagesActivity.java | 160 ++++++++++++ .../category/CategoryImagesListFragment.java | 227 ++++++++++++++++++ .../nrw/commons/category/GridViewAdapter.java | 88 +++++++ .../nrw/commons/category/QueryContinue.java | 24 ++ .../nrw/commons/di/ActivityBuilderModule.java | 4 +- .../commons/di/CommonsApplicationModule.java | 30 ++- .../nrw/commons/di/FragmentBuilderModule.java | 4 +- .../nrw/commons/featured/FeaturedImage.java | 44 ---- .../featured/FeaturedImagesActivity.java | 114 --------- .../featured/FeaturedImagesListFragment.java | 52 ---- .../commons/featured/MockGridViewAdapter.java | 50 ---- .../commons/media/MediaDetailFragment.java | 31 ++- .../mwapi/ApacheHttpClientMediaWikiApi.java | 98 +++++++- .../free/nrw/commons/mwapi/MediaWikiApi.java | 3 + .../commons/theme/NavigationBaseActivity.java | 7 +- .../free/nrw/commons/utils/ContinueUtils.java | 15 ++ ...mages.xml => activity_category_images.xml} | 11 +- ...mages.xml => fragment_category_images.xml} | 15 +- ..._images.xml => layout_category_images.xml} | 10 +- app/src/main/res/values/strings.xml | 4 + .../nrw/commons/TestCommonsApplication.kt | 5 +- .../mwapi/ApacheHttpClientMediaWikiApiTest.kt | 5 +- 26 files changed, 953 insertions(+), 309 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java delete mode 100644 app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java rename app/src/main/res/layout/{activity_featured_images.xml => activity_category_images.xml} (69%) rename app/src/main/res/layout/{fragment_featured_images.xml => fragment_category_images.xml} (70%) rename app/src/main/res/layout/{layout_featured_images.xml => layout_category_images.xml} (88%) diff --git a/app/build.gradle b/app/build.gradle index 535f58143..9c6f62fd4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,8 @@ dependencies { implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0' implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' + implementation 'org.jsoup:jsoup:1.11.3' + implementation 'com.facebook.fresco:fresco:1.5.0' implementation 'com.facebook.stetho:stetho:1.5.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6aab09b55..17f6770d2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -92,8 +92,9 @@ android:label="@string/navigation_item_notification" /> + android:name=".category.CategoryImagesActivity" + android:label="@string/title_activity_featured_images" + android:parentActivityName=".contributions.ContributionsActivity" /> diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java new file mode 100644 index 000000000..3495d710c --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageController.java @@ -0,0 +1,29 @@ +package fr.free.nrw.commons.category; + +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.mwapi.MediaWikiApi; + +@Singleton +public class CategoryImageController { + + private MediaWikiApi mediaWikiApi; + + @Inject + public CategoryImageController(MediaWikiApi mediaWikiApi) { + this.mediaWikiApi = mediaWikiApi; + } + + /** + * Takes a category name as input and calls the API to get a list of images for that category + * @param categoryName + * @return + */ + public List getCategoryImages(String categoryName) { + return mediaWikiApi.getCategoryImages(categoryName); + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java new file mode 100644 index 000000000..18749847e --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImageUtils.java @@ -0,0 +1,225 @@ +package fr.free.nrw.commons.category; + +import org.jsoup.Jsoup; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.annotation.Nullable; + +import fr.free.nrw.commons.Media; +import timber.log.Timber; + +public class CategoryImageUtils { + + /** + * The method iterates over the child nodes to return a list of Media objects + * @param childNodes + * @return + */ + public static List getMediaList(NodeList childNodes) { + List categoryImages = new ArrayList<>(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + categoryImages.add(getMediaFromPage(node)); + } + + return categoryImages; + } + + /** + * Creates a new Media object from the XML response as received by the API + * @param node + * @return + */ + private static Media getMediaFromPage(Node node) { + Media media = new Media(null, + getImageUrl(node), + getFileName(node), + getDescription(node), + getDataLength(node), + getDateCreated(node), + getDateCreated(node), + getCreator(node) + ); + + media.setLicense(getLicense(node)); + + return media; + } + + /** + * Extracts the filename of the uploaded image + * @param document + * @return + */ + private static String getFileName(Node document) { + Element element = (Element) document; + return element.getAttribute("title"); + } + + /** + * Extracts the image description for that particular upload + * @param document + * @return + */ + private static String getDescription(Node document) { + return getMetaDataValue(document, "ImageDescription"); + } + + /** + * Extracts license information from the image meta data + * @param document + * @return + */ + private static String getLicense(Node document) { + return getMetaDataValue(document, "License"); + } + + /** + * Returns the parsed value of artist from the response + * The artist information is returned as a HTML string from the API. Jsoup library parses the HTML string + * to extract just the text value + * @param document + * @return + */ + private static String getCreator(Node document) { + String artist = getMetaDataValue(document, "Artist"); + if (artist != null) { + return Jsoup.parse(artist).text(); + } + return null; + } + + /** + * Returns the parsed date of creation of the image + * @param document + * @return + */ + private static Date getDateCreated(Node document) { + String dateTime = getMetaDataValue(document, "DateTime"); + if (dateTime != null && !dateTime.equals("")) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + return format.parse(dateTime); + } catch (ParseException e) { + Timber.d("Error occurred while parsing date %s", dateTime); + return new Date(); + } + } + return new Date(); + } + + /** + * @param document + * @return Returns the url attribute from the imageInfo node + */ + private static String getImageUrl(Node document) { + Element element = (Element) getImageInfo(document); + if (element != null) { + return element.getAttribute("url"); + } + return null; + } + + /** + * Takes the node document and gives out the attribute length from the node document + * @param document + * @return + */ + private static long getDataLength(Node document) { + Element element = (Element) document; + if (element != null) { + String length = element.getAttribute("length"); + if (length != null && !length.equals("")) { + return Long.parseLong(length); + } + } + return 0L; + } + + /** + * Generic method to get the value of any meta as returned by the getMetaData function + * @param document node document as returned by API + * @param metaName the name of meta node to be returned + * @return + */ + private static String getMetaDataValue(Node document, String metaName) { + Element metaData = getMetaData(document, metaName); + if (metaData != null) { + return metaData.getAttribute("value"); + } + return null; + } + + /** + * Generic method to return an element taking the node document and metaName as input + * @param document node document as returned by API + * @param metaName the name of meta node to be returned + * @return + */ + @Nullable + private static Element getMetaData(Node document, String metaName) { + Node extraMetaData = getExtraMetaData(document); + if (extraMetaData != null) { + Node node = getNode(extraMetaData, metaName); + if (node != null) { + return (Element) node; + } + } + return null; + } + + /** + * Extracts extmetadata from the response XML + * @param document + * @return + */ + @Nullable + private static Node getExtraMetaData(Node document) { + Node imageInfo = getImageInfo(document); + if (imageInfo != null) { + return getNode(imageInfo, "extmetadata"); + } + return null; + } + + /** + * Extracts the ii node from the imageinfo node + * @param document + * @return + */ + @Nullable + private static Node getImageInfo(Node document) { + Node imageInfo = getNode(document, "imageinfo"); + if (imageInfo != null) { + return getNode(imageInfo, "ii"); + } + return null; + } + + /** + * Takes a parent node as input and returns a child node if present + * @param node parent node + * @param nodeName child node name + * @return + */ + @Nullable + public static Node getNode(Node node, String nodeName) { + NodeList childNodes = node.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node nodeItem = childNodes.item(i); + Element item = (Element) nodeItem; + if (item.getTagName().equals(nodeName)) { + return nodeItem; + } + } + return null; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java new file mode 100644 index 000000000..1f385b258 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesActivity.java @@ -0,0 +1,160 @@ +package fr.free.nrw.commons.category; + +import android.content.Context; +import android.content.Intent; +import android.database.DataSetObserver; +import android.os.Bundle; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.view.View; +import android.widget.AdapterView; + +import butterknife.ButterKnife; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.auth.AuthenticatedActivity; +import fr.free.nrw.commons.media.MediaDetailPagerFragment; +import timber.log.Timber; + +/** + * This activity displays pictures of a particular category + * Its generic and simply takes the name of category name in its start intent to load all images in + * a particular category. This activity is currently being used to display a list of featured images, + * which is nothing but another category on wikimedia commons. + */ + +public class CategoryImagesActivity + extends AuthenticatedActivity + implements FragmentManager.OnBackStackChangedListener, + MediaDetailPagerFragment.MediaDetailProvider, + AdapterView.OnItemClickListener{ + + + private FragmentManager supportFragmentManager; + private CategoryImagesListFragment categoryImagesListFragment; + private MediaDetailPagerFragment mediaDetails; + + @Override + protected void onAuthCookieAcquired(String authCookie) { + + } + + @Override + protected void onAuthFailure() { + + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_category_images); + ButterKnife.bind(this); + + // Activity can call methods in the fragment by acquiring a + // reference to the Fragment from FragmentManager, using findFragmentById() + supportFragmentManager = getSupportFragmentManager(); + setCategoryImagesFragment(); + supportFragmentManager.addOnBackStackChangedListener(this); + if (savedInstanceState != null) { + mediaDetails = (MediaDetailPagerFragment) supportFragmentManager + .findFragmentById(R.id.fragmentContainer); + + } + requestAuthToken(); + initDrawer(); + setPageTitle(); + } + + /** + * Gets the categoryName from the intent and initializes the fragment for showing images of that category + */ + private void setCategoryImagesFragment() { + categoryImagesListFragment = new CategoryImagesListFragment(); + String categoryName = getIntent().getStringExtra("categoryName"); + if (getIntent() != null && categoryName != null) { + Bundle arguments = new Bundle(); + arguments.putString("categoryName", categoryName); + categoryImagesListFragment.setArguments(arguments); + FragmentTransaction transaction = supportFragmentManager.beginTransaction(); + transaction + .add(R.id.fragmentContainer, categoryImagesListFragment) + .commit(); + } + } + + /** + * Gets the passed title from the intents and displays it as the page title + */ + private void setPageTitle() { + if (getIntent() != null && getIntent().getStringExtra("title") != null) { + setTitle(getIntent().getStringExtra("title")); + } + } + + @Override + public void onBackStackChanged() { + } + + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (mediaDetails == null || !mediaDetails.isVisible()) { + // set isFeaturedImage true for featured images, to include author field on media detail + mediaDetails = new MediaDetailPagerFragment(false, true); + FragmentManager supportFragmentManager = getSupportFragmentManager(); + supportFragmentManager + .beginTransaction() + .replace(R.id.fragmentContainer, mediaDetails) + .addToBackStack(null) + .commit(); + supportFragmentManager.executePendingTransactions(); + } + mediaDetails.showImage(i); + } + + /** + * Consumers should be simply using this method to use this activity. + * @param context + * @param title Page title + * @param categoryName Name of the category for displaying its images + */ + public static void startYourself(Context context, String title, String categoryName) { + Intent intent = new Intent(context, CategoryImagesActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + intent.putExtra("title", title); + intent.putExtra("categoryName", categoryName); + context.startActivity(intent); + } + + @Override + public Media getMediaAtPosition(int i) { + if (categoryImagesListFragment.getAdapter() == null) { + // not yet ready to return data + return null; + } else { + return (Media) categoryImagesListFragment.getAdapter().getItem(i); + } + } + + @Override + public int getTotalMediaCount() { + if (categoryImagesListFragment.getAdapter() == null) { + return 0; + } + return categoryImagesListFragment.getAdapter().getCount(); + } + + @Override + public void notifyDatasetChanged() { + + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java new file mode 100644 index 000000000..3b6734edd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/CategoryImagesListFragment.java @@ -0,0 +1,227 @@ +package fr.free.nrw.commons.category; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ListAdapter; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import dagger.android.support.DaggerFragment; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.utils.NetworkUtils; +import fr.free.nrw.commons.utils.ViewUtil; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; +import timber.log.Timber; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +/** + * Displays images for a particular category with load more on scrolling incorporated + */ +public class CategoryImagesListFragment extends DaggerFragment { + + private static int TIMEOUT_SECONDS = 15; + + private GridViewAdapter gridAdapter; + + @BindView(R.id.statusMessage) + TextView statusTextView; + @BindView(R.id.loadingImagesProgressBar) ProgressBar progressBar; + @BindView(R.id.categoryImagesList) GridView gridView; + + private boolean hasMoreImages = true; + private boolean isLoading; + private String categoryName = null; + + @Inject CategoryImageController controller; + @Inject @Named("category_prefs") SharedPreferences categoryPreferences; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_category_images, container, false); + ButterKnife.bind(this, v); + return v; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); + initViews(); + } + + /** + * Initializes the UI elements for the fragment + * Setup the grid view to and scroll listener for it + */ + private void initViews() { + String categoryName = getArguments().getString("categoryName"); + if (getArguments() != null && categoryName != null) { + this.categoryName = categoryName; + resetQueryContinueValues(categoryName); + initList(); + setScrollListener(); + } + } + + /** + * Query continue values determine the last page that was loaded for the particular keyword + * This method resets those values, so that the results can be queried from the first page itself + * @param keyword + */ + private void resetQueryContinueValues(String keyword) { + SharedPreferences.Editor editor = categoryPreferences.edit(); + editor.remove(keyword); + editor.apply(); + } + + /** + * Checks for internet connection and then initializes the grid view with first 10 images of that category + */ + @SuppressLint("CheckResult") + private void initList() { + if(!NetworkUtils.isInternetConnectionEstablished(getContext())) { + handleNoInternet(); + return; + } + + isLoading = true; + progressBar.setVisibility(VISIBLE); + Observable.fromCallable(() -> controller.getCategoryImages(categoryName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) + .subscribe(this::handleSuccess, this::handleError); + } + + /** + * Handles the UI updates for no internet scenario + */ + private void handleNoInternet() { + progressBar.setVisibility(GONE); + if (gridAdapter == null || gridAdapter.isEmpty()) { + statusTextView.setVisibility(VISIBLE); + statusTextView.setText(getString(R.string.no_internet)); + } else { + ViewUtil.showSnackbar(gridView, R.string.no_internet); + } + } + + /** + * Logs and handles API error scenario + * @param throwable + */ + private void handleError(Throwable throwable) { + Timber.e(throwable, "Error occurred while loading featured images"); + initErrorView(); + } + + /** + * Handles the UI updates for a error scenario + */ + private void initErrorView() { + ViewUtil.showSnackbar(gridView, R.string.error_loading_images); + progressBar.setVisibility(GONE); + if (gridAdapter == null || gridAdapter.isEmpty()) { + statusTextView.setVisibility(VISIBLE); + statusTextView.setText(getString(R.string.no_images_found)); + } else { + statusTextView.setVisibility(GONE); + } + } + + /** + * Initializes the adapter with a list of Media objects + * @param mediaList + */ + private void setAdapter(List mediaList) { + gridAdapter = new GridViewAdapter(this.getContext(), R.layout.layout_category_images, mediaList); + gridView.setAdapter(gridAdapter); + } + + /** + * Sets the scroll listener for the grid view so that more images are fetched when the user scrolls down + * Checks if the category has more images before loading + * Also checks whether images are currently being fetched before triggering another request + */ + private void setScrollListener() { + gridView.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (hasMoreImages && !isLoading && (firstVisibleItem + visibleItemCount + 1 >= totalItemCount)) { + isLoading = true; + fetchMoreImages(); + } + } + }); + } + + /** + * Fetches more images for the category and adds it to the grid view adapter + */ + @SuppressLint("CheckResult") + private void fetchMoreImages() { + if(!NetworkUtils.isInternetConnectionEstablished(getContext())) { + handleNoInternet(); + return; + } + + progressBar.setVisibility(VISIBLE); + Observable.fromCallable(() -> controller.getCategoryImages(categoryName)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) + .subscribe(this::handleSuccess, this::handleError); + } + + /** + * Handles the success scenario + * On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter + * @param collection + */ + private void handleSuccess(List collection) { + if(collection == null || collection.isEmpty()) { + initErrorView(); + hasMoreImages = false; + return; + } + + if(gridAdapter == null) { + setAdapter(collection); + } else { + gridAdapter.addItems(collection); + } + + progressBar.setVisibility(GONE); + isLoading = false; + statusTextView.setVisibility(GONE); + } + + public ListAdapter getAdapter() { + return gridView.getAdapter(); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java new file mode 100644 index 000000000..c8e6066f6 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/GridViewAdapter.java @@ -0,0 +1,88 @@ +package fr.free.nrw.commons.category; + +import android.app.Activity; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.MediaWikiImageView; +import fr.free.nrw.commons.R; + +/** + * This is created to only display UI implementation. Needs to be changed in real implementation + */ + +public class GridViewAdapter extends ArrayAdapter { + private Context context; + private List data; + + public GridViewAdapter(Context context, int layoutResourceId, List data) { + super(context, layoutResourceId, data); + this.context = context; + this.data = data; + } + + /** + * Adds more item to the list + * Its triggered on scrolling down in the list + * @param images + */ + public void addItems(List images) { + if (data == null) { + data = new ArrayList<>(); + } + data.addAll(images); + notifyDataSetChanged(); + } + + @Override + public boolean isEmpty() { + return data == null || data.isEmpty(); + } + + /** + * Sets up the UI for the category image item + * @param position + * @param convertView + * @param parent + * @return + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + if (convertView == null) { + LayoutInflater inflater = ((Activity) context).getLayoutInflater(); + convertView = inflater.inflate(R.layout.layout_category_images, null); + } + + Media item = data.get(position); + MediaWikiImageView imageView = convertView.findViewById(R.id.categoryImageView); + TextView fileName = convertView.findViewById(R.id.categoryImageTitle); + TextView author = convertView.findViewById(R.id.categoryImageAuthor); + fileName.setText(item.getFilename()); + setAuthorView(item, author); + imageView.setMedia(item); + return convertView; + } + + /** + * Shows author information if its present + * @param item + * @param author + */ + private void setAuthorView(Media item, TextView author) { + if (item.getCreator() != null && !item.getCreator().equals("")) { + String uploadedByTemplate = context.getString(R.string.image_uploaded_by); + author.setText(String.format(uploadedByTemplate, item.getCreator())); + } else { + author.setVisibility(View.GONE); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java b/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java new file mode 100644 index 000000000..e12d5a778 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/category/QueryContinue.java @@ -0,0 +1,24 @@ +package fr.free.nrw.commons.category; + +/** + * For APIs that return paginated responses, MediaWiki APIs uses the QueryContinue to facilitate fetching of subsequent pages + * https://www.mediawiki.org/wiki/API:Raw_query_continue + */ +public class QueryContinue { + private String continueParam; + private String gcmContinueParam; + + public QueryContinue(String continueParam, String gcmContinueParam) { + this.continueParam = continueParam; + this.gcmContinueParam = gcmContinueParam; + } + + public String getGcmContinueParam() { + return gcmContinueParam; + } + + public String getContinueParam() { + return continueParam; + } +} + diff --git a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java index f88f3b34a..51aa85903 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java @@ -7,7 +7,7 @@ import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.auth.SignupActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; -import fr.free.nrw.commons.featured.FeaturedImagesActivity; +import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.settings.SettingsActivity; @@ -49,5 +49,5 @@ public abstract class ActivityBuilderModule { abstract NotificationActivity bindNotificationActivity(); @ContributesAndroidInjector - abstract FeaturedImagesActivity bindFeaturedImagesActivity(); + abstract CategoryImagesActivity bindFeaturedImagesActivity(); } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java index e8b915c7e..55281be7e 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationModule.java @@ -6,6 +6,8 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.v4.util.LruCache; +import com.google.gson.Gson; + import javax.inject.Named; import javax.inject.Singleton; @@ -85,6 +87,17 @@ public class CommonsApplicationModule { return context.getSharedPreferences("prefs", MODE_PRIVATE); } + /** + * + * @param context + * @return returns categoryPrefs + */ + @Provides + @Named("category_prefs") + public SharedPreferences providesCategorySharedPreferences(Context context) { + return context.getSharedPreferences("categoryPrefs", MODE_PRIVATE); + } + @Provides @Named("direct_nearby_upload_prefs") public SharedPreferences providesDirectNearbyUploadPreferences(Context context) { @@ -106,8 +119,11 @@ public class CommonsApplicationModule { @Provides @Singleton - public MediaWikiApi provideMediaWikiApi(Context context, @Named("default_preferences") SharedPreferences sharedPreferences) { - return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, sharedPreferences); + public MediaWikiApi provideMediaWikiApi(Context context, + @Named("default_preferences") SharedPreferences defaultPreferences, + @Named("category_prefs") SharedPreferences categoryPrefs, + Gson gson) { + return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, defaultPreferences, categoryPrefs, gson); } @Provides @@ -116,6 +132,16 @@ public class CommonsApplicationModule { return new LocationServiceManager(context); } + /** + * Gson objects are very heavy. The app should ideally be using just one instance of it instead of creating new instances everywhere. + * @return returns a singleton Gson instance + */ + @Provides + @Singleton + public Gson provideGson() { + return new Gson(); + } + @Provides @Singleton public CacheController provideCacheController() { diff --git a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java index c5cdcb5a7..dfed64871 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/FragmentBuilderModule.java @@ -4,7 +4,7 @@ import dagger.Module; import dagger.android.ContributesAndroidInjector; import fr.free.nrw.commons.category.CategorizationFragment; import fr.free.nrw.commons.contributions.ContributionsListFragment; -import fr.free.nrw.commons.featured.FeaturedImagesListFragment; +import fr.free.nrw.commons.category.CategoryImagesListFragment; import fr.free.nrw.commons.media.MediaDetailFragment; import fr.free.nrw.commons.media.MediaDetailPagerFragment; import fr.free.nrw.commons.nearby.NearbyListFragment; @@ -49,6 +49,6 @@ public abstract class FragmentBuilderModule { abstract SingleUploadFragment bindSingleUploadFragment(); @ContributesAndroidInjector - abstract FeaturedImagesListFragment bindFeaturedImagesListFragment(); + abstract CategoryImagesListFragment bindFeaturedImagesListFragment(); } diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java deleted file mode 100644 index 853fba29e..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImage.java +++ /dev/null @@ -1,44 +0,0 @@ -package fr.free.nrw.commons.featured; - - -import fr.free.nrw.commons.Media; - -/** - * Object to hold FeaturedImage - */ - -public class FeaturedImage { - private Media image; - private String author; - private String fileName; - - public FeaturedImage(Media image, String author, String fileName) { - this.image = image; - this.author = author; - this.fileName = fileName; - } - - public Media getImage() { - return image; - } - - public void setImage(Media image) { - this.image = image; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java deleted file mode 100644 index a2dc7b00b..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.database.DataSetObserver; -import android.os.Bundle; -import android.support.v4.app.FragmentManager; -import android.view.View; -import android.widget.AdapterView; - -import butterknife.ButterKnife; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.auth.AuthenticatedActivity; -import fr.free.nrw.commons.media.MediaDetailPagerFragment; - -/** - * This activity displays pic of the days of last xx days - */ - -public class FeaturedImagesActivity - extends AuthenticatedActivity - implements FragmentManager.OnBackStackChangedListener, - MediaDetailPagerFragment.MediaDetailProvider, - AdapterView.OnItemClickListener{ - - private FeaturedImagesListFragment featuredImagesListFragment; - private MediaDetailPagerFragment mediaDetails; - - @Override - protected void onAuthCookieAcquired(String authCookie) { - - } - - @Override - protected void onAuthFailure() { - - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_featured_images); - ButterKnife.bind(this); - - // Activity can call methods in the fragment by acquiring a - // reference to the Fragment from FragmentManager, using findFragmentById() - FragmentManager supportFragmentManager = getSupportFragmentManager(); - featuredImagesListFragment = (FeaturedImagesListFragment)supportFragmentManager - .findFragmentById(R.id.featuedListFragment); - - supportFragmentManager.addOnBackStackChangedListener(this); - if (savedInstanceState != null) { - mediaDetails = (MediaDetailPagerFragment)supportFragmentManager - .findFragmentById(R.id.featuredFragmentContainer); - - } - requestAuthToken(); - initDrawer(); - setTitle(getString(R.string.title_activity_featured_images)); - } - - @Override - public void onBackStackChanged() { - - } - - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - if (mediaDetails == null || !mediaDetails.isVisible()) { - // set isFeaturedImage true for featured images, to include author field on media detail - mediaDetails = new MediaDetailPagerFragment(false, true); - FragmentManager supportFragmentManager = getSupportFragmentManager(); - supportFragmentManager - .beginTransaction() - .replace(R.id.featuredFragmentContainer, mediaDetails) - .addToBackStack(null) - .commit(); - supportFragmentManager.executePendingTransactions(); - } - mediaDetails.showImage(i); - } - - @Override - public Media getMediaAtPosition(int i) { - if (featuredImagesListFragment.getAdapter() == null) { - // not yet ready to return data - return null; - } else { - return ((FeaturedImage)featuredImagesListFragment.getAdapter().getItem(i)).getImage(); - } - } - - @Override - public int getTotalMediaCount() { - if (featuredImagesListFragment.getAdapter() == null) { - return 0; - } - return featuredImagesListFragment.getAdapter().getCount(); - } - - @Override - public void notifyDatasetChanged() { - - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java b/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java deleted file mode 100644 index 19e33b0ee..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/FeaturedImagesListFragment.java +++ /dev/null @@ -1,52 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.GridView; -import android.widget.ListAdapter; - -import java.util.ArrayList; - -import butterknife.ButterKnife; -import dagger.android.support.DaggerFragment; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.R; - -public class FeaturedImagesListFragment extends DaggerFragment { - private GridView gridView; - private MockGridViewAdapter gridAdapter; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_featured_images, container, false); - ButterKnife.bind(this, v); - return v; - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - gridView = getView().findViewById(R.id.featuredImagesList); - gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity()); - gridAdapter = new MockGridViewAdapter(this.getContext(), R.layout.layout_featured_images, getMockFeaturedImages()); - gridView.setAdapter(gridAdapter); - - } - - private ArrayList getMockFeaturedImages(){ - ArrayList featuredImages = new ArrayList<>(); - for (int i=0; i<10; i++){ - featuredImages.add(new FeaturedImage(new Media("test.jpg"), "username: test", "test file name")); - } - return featuredImages; - } - - public ListAdapter getAdapter() { - return gridView.getAdapter(); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java b/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java deleted file mode 100644 index 7aa2a8892..000000000 --- a/app/src/main/java/fr/free/nrw/commons/featured/MockGridViewAdapter.java +++ /dev/null @@ -1,50 +0,0 @@ -package fr.free.nrw.commons.featured; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import java.util.ArrayList; - -import fr.free.nrw.commons.MediaWikiImageView; -import fr.free.nrw.commons.R; - -/** - * This is created to only display UI implementation. Needs to be changed in real implementation - */ - -public class MockGridViewAdapter extends ArrayAdapter { - private Context context; - private int layoutResourceId; - private ArrayList data = new ArrayList(); - - public MockGridViewAdapter(Context context, int layoutResourceId, ArrayList data) { - super(context, layoutResourceId, data); - this.layoutResourceId = layoutResourceId; - this.context = context; - this.data = data; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - - if (convertView == null) { - LayoutInflater inflater = ((Activity) context).getLayoutInflater(); - convertView = inflater.inflate(R.layout.layout_featured_images, null); - } - - FeaturedImage item = data.get(position); - MediaWikiImageView imageView = convertView.findViewById(R.id.featuredImageView); - TextView fileName = convertView.findViewById(R.id.featuredImageTitle); - TextView author = convertView.findViewById(R.id.featuredImageAuthor); - fileName.setText("Test file name"); - author.setText("Uploaded by: Test user name"); - imageView.setMedia(item.getImage()); - return convertView; - } - -} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 037f92e56..c3a977ab5 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -45,6 +45,7 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.ui.widget.CompatTextView; import timber.log.Timber; +import static android.view.View.*; import static android.widget.Toast.LENGTH_SHORT; public class MediaDetailFragment extends CommonsDaggerSupportFragment { @@ -154,9 +155,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); if (isFeaturedMedia){ - authorLayout.setVisibility(View.VISIBLE); + authorLayout.setVisibility(VISIBLE); } else { - authorLayout.setVisibility(View.GONE); + authorLayout.setVisibility(GONE); } licenseList = new LicenseList(getActivity()); @@ -306,6 +307,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { } rebuildCatList(); + if(media.getCreator() == null || media.getCreator().equals("")) { + authorLayout.setVisibility(GONE); + } else { + author.setText(media.getCreator()); + } + checkDeletion(media); } @@ -313,13 +320,17 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (licenseLink(media) != null) { license.setOnClickListener(v -> openWebBrowser(licenseLink(media))); } else { - Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); - toast.show(); + if(isFeaturedMedia) { + Timber.d("Unable to fetch license URL for %s", media.getLicense()); + } else { + Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); + toast.show(); + } } if (media.getCoordinates() != null) { coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); } - if (delete.getVisibility() == View.VISIBLE) { + if (delete.getVisibility() == VISIBLE) { enableDeleteButton(true); delete.setOnClickListener(v -> { @@ -369,7 +380,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); }); } - if (nominatedforDeletion.getVisibility() == View.VISIBLE){ + if (nominatedforDeletion.getVisibility() == VISIBLE){ seeMore.setOnClickListener(v -> { openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); }); @@ -476,12 +487,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private void checkDeletion(Media media){ if (media.getRequestedDeletion()){ - delete.setVisibility(View.GONE); - nominatedforDeletion.setVisibility(View.VISIBLE); + delete.setVisibility(GONE); + nominatedforDeletion.setVisibility(VISIBLE); } else{ - delete.setVisibility(View.VISIBLE); - nominatedforDeletion.setVisibility(View.GONE); + delete.setVisibility(VISIBLE); + nominatedforDeletion.setVisibility(GONE); } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 78051abd8..6629d0933 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -9,6 +9,8 @@ import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; +import com.google.gson.Gson; + import org.apache.http.HttpResponse; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; @@ -38,7 +40,10 @@ import java.util.Locale; import java.util.concurrent.Callable; import fr.free.nrw.commons.BuildConfig; +import fr.free.nrw.commons.Media; import fr.free.nrw.commons.PageTitle; +import fr.free.nrw.commons.category.CategoryImageUtils; +import fr.free.nrw.commons.category.QueryContinue; import fr.free.nrw.commons.notification.Notification; import fr.free.nrw.commons.notification.NotificationUtils; import in.yuvi.http.fluent.Http; @@ -46,6 +51,8 @@ import io.reactivex.Observable; import io.reactivex.Single; import timber.log.Timber; +import static fr.free.nrw.commons.utils.ContinueUtils.getQueryContinue; + /** * @author Addshore */ @@ -56,9 +63,15 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { private AbstractHttpClient httpClient; private MWApi api; private Context context; - private SharedPreferences sharedPreferences; + private SharedPreferences defaultPreferences; + private SharedPreferences categoryPreferences; + private Gson gson; - public ApacheHttpClientMediaWikiApi(Context context, String apiURL, SharedPreferences sharedPreferences) { + public ApacheHttpClientMediaWikiApi(Context context, + String apiURL, + SharedPreferences defaultPreferences, + SharedPreferences categoryPreferences, + Gson gson) { this.context = context; BasicHttpParams params = new BasicHttpParams(); SchemeRegistry schemeRegistry = new SchemeRegistry(); @@ -69,7 +82,9 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { params.setParameter(CoreProtocolPNames.USER_AGENT, getUserAgent()); httpClient = new DefaultHttpClient(cm, params); api = new MWApi(apiURL, httpClient); - this.sharedPreferences = sharedPreferences; + this.defaultPreferences = defaultPreferences; + this.categoryPreferences = categoryPreferences; + this.gson = gson; } @Override @@ -160,7 +175,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { } private void setAuthCookieOnLogin(boolean isLoggedIn) { - SharedPreferences.Editor editor = sharedPreferences.edit(); + SharedPreferences.Editor editor = defaultPreferences.edit(); if (isLoggedIn) { editor.putBoolean("isUserLoggedIn", true); editor.putString("getAuthCookie", api.getAuthCookie()); @@ -448,6 +463,81 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { return NotificationUtils.getNotificationsFromList(context, childNodes); } + /** + * The method takes categoryName as input and returns a List of Media objects + * It uses the generator query API to get the images in a category, 10 at a time. + * Uses the query continue values for fetching paginated responses + * @param categoryName Category name as defined on commons + * @return + */ + @Override + @NonNull + public List getCategoryImages(String categoryName) { + ApiResult apiResult = null; + try { + MWApi.RequestBuilder requestBuilder = api.action("query") + .param("generator", "categorymembers") + .param("format", "xml") + .param("gcmtype", "file") + .param("gcmtitle", categoryName) + .param("prop", "imageinfo") + .param("gcmlimit", "10") + .param("iiprop", "url|extmetadata"); + + QueryContinue queryContinueValues = getQueryContinueValues(categoryName); + if (queryContinueValues != null) { + requestBuilder.param("continue", queryContinueValues.getContinueParam()); + requestBuilder.param("gcmcontinue", queryContinueValues.getGcmContinueParam()); + } + + apiResult = requestBuilder.get(); + } catch (IOException e) { + Timber.e("Failed to obtain searchCategories", e); + } + + if (apiResult == null) { + return new ArrayList<>(); + } + + ApiResult categoryImagesNode = apiResult.getNode("/api/query/pages"); + if (categoryImagesNode == null + || categoryImagesNode.getDocument() == null + || categoryImagesNode.getDocument().getChildNodes() == null + || categoryImagesNode.getDocument().getChildNodes().getLength() == 0) { + return new ArrayList<>(); + } + + QueryContinue queryContinue = getQueryContinue(apiResult.getNode("/api/continue").getDocument()); + setQueryContinueValues(categoryName, queryContinue); + + NodeList childNodes = categoryImagesNode.getDocument().getChildNodes(); + return CategoryImageUtils.getMediaList(childNodes); + } + + /** + * For APIs that return paginated responses, MediaWiki APIs uses the QueryContinue to facilitate fetching of subsequent pages + * https://www.mediawiki.org/wiki/API:Raw_query_continue + * After fetching images a page of image for a particular category, shared prefs are updated with the latest QueryContinue Values + * @param keyword + * @param queryContinue + */ + private void setQueryContinueValues(String keyword, QueryContinue queryContinue) { + SharedPreferences.Editor editor = categoryPreferences.edit(); + editor.putString(keyword, gson.toJson(queryContinue)); + editor.apply(); + } + + /** + * Before making a paginated API call, this method is called to get the latest query continue values to be used + * @param keyword + * @return + */ + @Nullable + private QueryContinue getQueryContinueValues(String keyword) { + String queryContinueString = categoryPreferences.getString(keyword, null); + return gson.fromJson(queryContinueString, QueryContinue.class); + } + @Override public boolean existingFile(String fileSha1) throws IOException { return api.action("query") diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index fd213455d..c0bd2fd87 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; +import fr.free.nrw.commons.Media; import fr.free.nrw.commons.notification.Notification; import io.reactivex.Observable; import io.reactivex.Single; @@ -34,6 +35,8 @@ public interface MediaWikiApi { boolean logEvents(LogBuilder[] logBuilders); + List getCategoryImages(String categoryName); + @NonNull UploadResult uploadFile(String filename, InputStream file, long dataLength, String pageContents, String editSummary, ProgressListener progressListener) throws IOException; diff --git a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java index acd9b7646..4a7322b57 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java @@ -23,12 +23,11 @@ import fr.free.nrw.commons.AboutActivity; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; -import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.WelcomeActivity; import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.contributions.ContributionsActivity; -import fr.free.nrw.commons.featured.FeaturedImagesActivity; +import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.settings.SettingsActivity; @@ -37,6 +36,8 @@ import timber.log.Timber; public abstract class NavigationBaseActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener { + private static final String FEATURED_IMAGES_CATEGORY = "Category:Featured_pictures_on_Wikimedia_Commons"; + @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.navigation_view) @@ -157,7 +158,7 @@ public abstract class NavigationBaseActivity extends BaseActivity return true; case R.id.action_featured_images: drawerLayout.closeDrawer(navigationView); - startActivityWithFlags(this, FeaturedImagesActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + CategoryImagesActivity.startYourself(this, getString(R.string.title_activity_featured_images), FEATURED_IMAGES_CATEGORY); return true; default: Timber.e("Unknown option [%s] selected from the navigation menu", itemId); diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java new file mode 100644 index 000000000..b05c8bc45 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/ContinueUtils.java @@ -0,0 +1,15 @@ +package fr.free.nrw.commons.utils; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import fr.free.nrw.commons.category.QueryContinue; + +public class ContinueUtils { + + public static QueryContinue getQueryContinue(Node document) { + Element continueElement = (Element) document; + return new QueryContinue(continueElement.getAttribute("continue"), + continueElement.getAttribute("gcmcontinue")); + } +} diff --git a/app/src/main/res/layout/activity_featured_images.xml b/app/src/main/res/layout/activity_category_images.xml similarity index 69% rename from app/src/main/res/layout/activity_featured_images.xml rename to app/src/main/res/layout/activity_category_images.xml index 755fe4983..c329e4458 100644 --- a/app/src/main/res/layout/activity_featured_images.xml +++ b/app/src/main/res/layout/activity_category_images.xml @@ -1,6 +1,5 @@ - - diff --git a/app/src/main/res/layout/fragment_featured_images.xml b/app/src/main/res/layout/fragment_category_images.xml similarity index 70% rename from app/src/main/res/layout/fragment_featured_images.xml rename to app/src/main/res/layout/fragment_category_images.xml index ca45f44c3..001f0a780 100644 --- a/app/src/main/res/layout/fragment_featured_images.xml +++ b/app/src/main/res/layout/fragment_category_images.xml @@ -1,20 +1,21 @@ - + android:background="?attr/mainBackground"> @@ -33,7 +33,7 @@ android:padding="@dimen/small_gap" > Proceed Cancel Retry + + No images found! + Error occurred while loading images. + Uploaded by: %1$s Share App diff --git a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt index 73760dd40..b1de29143 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/TestCommonsApplication.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons import android.content.Context import android.content.SharedPreferences import android.support.v4.util.LruCache +import com.google.gson.Gson import com.nhaarman.mockito_kotlin.mock import com.squareup.leakcanary.RefWatcher import fr.free.nrw.commons.auth.AccountUtil @@ -36,6 +37,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu val accountUtil: AccountUtil = mock() val appSharedPreferences: SharedPreferences = mock() val defaultSharedPreferences: SharedPreferences = mock() + val categorySharedPreferences: SharedPreferences = mock() val otherSharedPreferences: SharedPreferences = mock() val uploadController: UploadController = mock() val mockSessionManager: SessionManager = mock() @@ -45,6 +47,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu val mockDbOpenHelper: DBOpenHelper = mock() val nearbyPlaces: NearbyPlaces = mock() val lruCache: LruCache = mock() + val gson: Gson = Gson() override fun providesAccountUtil(context: Context): AccountUtil = accountUtil @@ -58,7 +61,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu override fun providesSessionManager(context: Context, mediaWikiApi: MediaWikiApi, sharedPreferences: SharedPreferences): SessionManager = mockSessionManager - override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences): MediaWikiApi = mediaWikiApi + override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences, categorySharedPreferences: SharedPreferences, gson: Gson): MediaWikiApi = mediaWikiApi override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager diff --git a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt index c51d354c2..686a90ef2 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApiTest.kt @@ -3,6 +3,7 @@ package fr.free.nrw.commons.mwapi import android.content.SharedPreferences import android.os.Build import android.preference.PreferenceManager +import com.google.gson.Gson import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.TestCommonsApplication import okhttp3.mockwebserver.MockResponse @@ -26,12 +27,14 @@ class ApacheHttpClientMediaWikiApiTest { private lateinit var testObject: ApacheHttpClientMediaWikiApi private lateinit var server: MockWebServer private lateinit var sharedPreferences: SharedPreferences + private lateinit var categoryPreferences: SharedPreferences @Before fun setUp() { server = MockWebServer() sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) - testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences) + categoryPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) + testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences, categoryPreferences, Gson()) testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/") } From f28cc6fc8ce9c900ba92c94f2d821d18110dedb2 Mon Sep 17 00:00:00 2001 From: Josephine Lim Date: Mon, 7 May 2018 19:27:14 +1000 Subject: [PATCH 088/184] Update pull_request_template.md (#1476) * Update pull_request_template.md * Remove Javadocs mention * Added required/optional notes --- PULL_REQUEST_TEMPLATE.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 34078f07e..9d7150008 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,15 @@ -## Description +## Description (required) -Fixes #{GitHub issue number} +Fixes #{GitHub issue number and title} {Describe the changes made and why they were made.} -## Tests performed +## Tests performed (required) Tested on {API level & name of device/emulator}, with {build variant, e.g. ProdDebug}. -{Please test your PR at least once before submitting.} - -## Screenshots showing what changed +## Screenshots showing what changed (optional) {Only for user interface changes, otherwise remove this section. See [how to take a screenshot](https://android.stackexchange.com/questions/1759/how-to-take-a-screenshot-with-an-android-device)} + +_Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._ From 539c03bf047f039ae501d00262cdef3b8b028c6f Mon Sep 17 00:00:00 2001 From: Man Parvesh Singh Randhawa Date: Mon, 7 May 2018 17:32:11 +0800 Subject: [PATCH 089/184] resolves #1464 : MediaDataExtractor is making inefficient (redundant) server calls (#1496) --- app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java index 2d79a6c4f..affb57528 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java @@ -61,8 +61,8 @@ public class MediaDataExtractor { } try{ - Timber.d("Nominated for deletion: " + mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename)); - deletionStatus = mediaWikiApi.pageExists("Commons:Deletion_requests/"+filename); + deletionStatus = mediaWikiApi.pageExists("Commons:Deletion_requests/" + filename); + Timber.d("Nominated for deletion: " + deletionStatus); } catch (Exception e){ Timber.d(e.getMessage()); From aca3f0f832370e1859892c4c89604595fcd84ccd Mon Sep 17 00:00:00 2001 From: Tanvi Dadu Date: Mon, 7 May 2018 15:27:59 +0530 Subject: [PATCH 090/184] Open map of place where picture was taken (#1360) * Intent to map added * Merge conflicts resolved * Added the functionality to hide FAB incase of null coordinate * Merge Conflict resolved * Improve pr quality * Improve Quality * Added nested FAB animations * Nested FAB implemented * Improve Quality * Added up arrow * Javadocs Added --- .../nrw/commons/upload/ShareActivity.java | 105 +++++++++++++++++- .../ic_keyboard_arrow_up_black_24dp.xml | 5 + app/src/main/res/layout/activity_share.xml | 27 ++++- app/src/main/res/values/dimens.xml | 2 + app/src/main/res/values/strings.xml | 2 + 5 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 77f76fbed..6a59c8e30 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -81,8 +81,7 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; - - +import android.support.design.widget.FloatingActionButton; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; import static java.lang.Long.min; @@ -122,6 +121,7 @@ public class ShareActivity private Uri mediaUri; private Contribution contribution; private SimpleDraweeView backgroundImageView; + private FloatingActionButton maps_fragment; private boolean cacheFound; @@ -145,6 +145,8 @@ public class ShareActivity private long ShortAnimationDuration; private FloatingActionButton zoomInButton; private FloatingActionButton zoomOutButton; + private FloatingActionButton mainFab; + private boolean isFABOpen = false; /** @@ -284,6 +286,24 @@ public class ShareActivity if (mediaUri != null) { backgroundImageView.setImageURI(mediaUri); } + + mainFab = (FloatingActionButton) findViewById(R.id.main_fab); + /* + * called when upper arrow floating button + */ + mainFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(!isFABOpen){ + showFABMenu(); + }else{ + closeFABMenu(); + } + } + }); + + + zoomInButton = (FloatingActionButton) findViewById(R.id.media_upload_zoom_in); try { zoomInButton.setOnClickListener(new View.OnClickListener() { @@ -358,7 +378,74 @@ public class ShareActivity .commitAllowingStateLoss(); } uploadController.prepareService(); + maps_fragment = (FloatingActionButton) findViewById(R.id.media_map); + maps_fragment.setVisibility(View.VISIBLE); + if( imageObj == null || imageObj.imageCoordsExists != true){ + maps_fragment.setVisibility(View.INVISIBLE); + } + + + maps_fragment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if( imageObj != null && imageObj.imageCoordsExists == true) { + Uri gmmIntentUri = Uri.parse("google.streetview:cbll=" + imageObj.getDecLatitude() + "," + imageObj.getDecLongitude()); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + startActivity(mapIntent); + } + } + }); } + /* + * Function to display the zoom and map FAB + */ + private void showFABMenu(){ + isFABOpen=true; + + if( imageObj != null && imageObj.imageCoordsExists == true) + maps_fragment.setVisibility(View.VISIBLE); + zoomInButton.setVisibility(View.VISIBLE); + + mainFab.animate().rotationBy(180); + maps_fragment.animate().translationY(-getResources().getDimension(R.dimen.second_fab)); + zoomInButton.animate().translationY(-getResources().getDimension(R.dimen.first_fab)); + } + + /* + * function to close the zoom and map FAB + */ + private void closeFABMenu(){ + isFABOpen=false; + mainFab.animate().rotationBy(-180); + maps_fragment.animate().translationY(0); + zoomInButton.animate().translationY(0).setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + + } + + @Override + public void onAnimationEnd(Animator animator) { + if(!isFABOpen){ + maps_fragment.setVisibility(View.GONE); + zoomInButton.setVisibility(View.GONE); + } + + } + + @Override + public void onAnimationCancel(Animator animator) { + + } + + @Override + public void onAnimationRepeat(Animator animator) { + + } + }); + } + @Override public void onRequestPermissionsResult(int requestCode, @@ -461,6 +548,9 @@ public class ShareActivity detectUnwantedPicturesAsync.execute(); } + /* + * to display permission snackbar in share activity + */ private Snackbar requestPermissionUsingSnackBar(String rationale, final String[] perms, final int code) { @@ -693,7 +783,9 @@ public class ShareActivity return super.onOptionsItemSelected(item); } - // Get SHA1 of file from input stream + /* + * Get SHA1 of file from input stream + */ private String getSHA1(InputStream is) { MessageDigest digest; @@ -730,6 +822,9 @@ public class ShareActivity } } + /* + * function to provide pinch zoom + */ private void zoomImageFromThumb(final View thumbView, Uri imageuri ) { // If there's an animation in progress, cancel it // immediately and proceed with this one. @@ -737,6 +832,8 @@ public class ShareActivity CurrentAnimator.cancel(); } ViewUtil.hideKeyboard(ShareActivity.this.findViewById(R.id.titleEdit | R.id.descEdit)); + closeFABMenu(); + mainFab.setVisibility(View.GONE); InputStream input = null; Bitmap scaled = null; try { @@ -866,7 +963,7 @@ public class ShareActivity CurrentAnimator.cancel(); } zoomOutButton.setVisibility(View.GONE); - zoomInButton.setVisibility(View.VISIBLE); + mainFab.setVisibility(View.VISIBLE); // Animate the four positioning/sizing properties in parallel, // back to their original values. diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml new file mode 100644 index 000000000..bc010396b --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml index ca8097495..b6e523239 100644 --- a/app/src/main/res/layout/activity_share.xml +++ b/app/src/main/res/layout/activity_share.xml @@ -41,8 +41,6 @@ - - + + + + + + + 20sp 16sp 14sp + 15dp + 25dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e83fefd1..00bfafdad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -275,4 +275,6 @@ Error occurred while loading images. Uploaded by: %1$s Share App + Coordinates were not specified during image selection + From 8eed630ee57036dcd07ced2fba98dee8c9a5e857 Mon Sep 17 00:00:00 2001 From: neslihanturan Date: Mon, 7 May 2018 15:05:20 +0300 Subject: [PATCH 091/184] Add nearby tutorial (#1467) * Add dependency for MaterialShowcase * Add actionview class to get a reference to material showcase * Create a NearbyMaterialShowcaseSequence class * Apply sequence steps * Add first three steps of nearby showcase * Add sequence id constants to make sure they will be displayed only once * Add last step of sequence to explain plus fab * Create an object to prevent customize all sequences every time * Fix typo * Code cleanup * Add strings to strings.xml * Code cleanup * Revert irrelevant change * Revert irrelevant change * Remove showcaseview for recenter button * Use single showcaseView instead of sequence * Add single showcase view insted of sequence to be able to edit text style * Make sure it will be displayed only once * Cleanup * Update strings * Change dismiss text style --- app/build.gradle | 2 + .../nrw/commons/nearby/NearbyActivity.java | 91 ++++++++++++++++++- .../nrw/commons/nearby/NearbyMapFragment.java | 32 ++++++- .../NearbyMaterialShowcaseSequence.java | 18 ++++ .../fr/free/nrw/commons/utils/ViewUtil.java | 4 + app/src/main/res/values/strings.xml | 6 ++ 6 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java diff --git a/app/build.gradle b/app/build.gradle index 9c6f62fd4..5d37f8f54 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,8 @@ dependencies { transitive=true } + implementation "com.github.deano2390:MaterialShowcaseView:1.2.0" + implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION" implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION" implementation "com.android.support:design:$SUPPORT_LIB_VERSION" diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 2a423de93..3bf8beacf 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -4,14 +4,18 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; + import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -25,6 +29,7 @@ import com.google.gson.GsonBuilder; import java.util.List; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; @@ -41,6 +46,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import timber.log.Timber; +import uk.co.deanwild.materialshowcaseview.IShowcaseListener; +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener { @@ -56,12 +63,15 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp LinearLayout bottomSheetDetails; @BindView(R.id.transparentView) View transparentView; + @BindView(R.id.fab_recenter) + View fabRecenter; @Inject LocationServiceManager locationManager; @Inject NearbyController nearbyController; - + @Inject + @Named("application_preferences") SharedPreferences applicationPrefs; private LatLng curLatLng; private Bundle bundle; private Disposable placesDisposable; @@ -72,11 +82,18 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp private NearbyListFragment nearbyListFragment; private static final String TAG_RETAINED_MAP_FRAGMENT = NearbyMapFragment.class.getSimpleName(); private static final String TAG_RETAINED_LIST_FRAGMENT = NearbyListFragment.class.getSimpleName(); + private View listButton; // Reference to list button to use in tutorial private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private BroadcastReceiver broadcastReceiver; + + private boolean isListShowcaseAdded = false; + private boolean isMapShowCaseAdded = false; + private LatLng lastKnownLocation; + private MaterialShowcaseView secondSingleShowCaseView; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -126,6 +143,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_nearby, menu); + new Handler().post(() -> { + + listButton = findViewById(R.id.action_display_list); + + secondSingleShowCaseView = new MaterialShowcaseView.Builder(this) + .setTarget(listButton) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_list_icon)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_1) // provide a unique ID used to ensure it is only shown once + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .setListener(new IShowcaseListener() { + @Override + public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) { + + } + + // If dismissed, we can inform fragment to start showcase sequence there + @Override + public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) { + nearbyMapFragment.onNearbyMaterialShowcaseDismissed(); + } + }) + .build(); + + isListShowcaseAdded = true; + + if (isMapShowCaseAdded) { // If map showcase is also ready, start ShowcaseSequence + // Probably this case is not possible. Just added to be careful + setMapViewTutorialShowCase(); + } + }); + return super.onCreateOptionsMenu(menu); } @@ -420,6 +470,45 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp updateMapFragment(false); updateListFragment(); } + + isMapShowCaseAdded = true; + } + + public void setMapViewTutorialShowCase() { + /* + *This showcase view will be the first step of our nearbyMaterialShowcaseSequence. The reason we use a + * single item instead of adding another step to nearbyMaterialShowcaseSequence is that we are not able to + * call withoutShape() method on steps. For mapView we need an showcase view without + * any circle on it, it should cover the whole page. + * */ + MaterialShowcaseView firstSingleShowCaseView = new MaterialShowcaseView.Builder(this) + .setTarget(nearbyMapFragment.mapView) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_whole_nearby_activity)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_2) // provide a unique ID used to ensure it is only shown once + .withoutShape() // no shape on map view since there are no view to focus on + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .setListener(new IShowcaseListener() { + @Override + public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) { + + } + + @Override + public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) { + /* Add other nearbyMaterialShowcaseSequence here, it will make the user feel as they are a + * nearbyMaterialShowcaseSequence whole together. + * */ + secondSingleShowCaseView.show(NearbyActivity.this); + } + }) + .build(); + + if (applicationPrefs.getBoolean("firstRunNearby", true)) { + applicationPrefs.edit().putBoolean("firstRunNearby", false).apply(); + firstSingleShowCaseView.show(this); + } } private void lockNearbyView(boolean lock) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java index 431132436..69041d286 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMapFragment.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Color; +import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; @@ -58,13 +59,14 @@ import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.utils.UriDeserializer; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; import static android.app.Activity.RESULT_OK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; public class NearbyMapFragment extends DaggerFragment { - private MapView mapView; + public MapView mapView; private List baseMarkerOptions; private fr.free.nrw.commons.location.LatLng curLatLng; public fr.free.nrw.commons.location.LatLng[] boundaryCoordinates; @@ -111,6 +113,10 @@ public class NearbyMapFragment extends DaggerFragment { private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04; + private boolean isSecondMaterialShowcaseDismissed; + private boolean isMapReady; + private MaterialShowcaseView thirdSingleShowCaseView; + private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location @Inject @@ -163,7 +169,6 @@ public class NearbyMapFragment extends DaggerFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Timber.d("onCreateView called"); if (curLatLng != null) { Timber.d("curLatLng found, setting up map view..."); @@ -476,6 +481,7 @@ public class NearbyMapFragment extends DaggerFragment { mapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(MapboxMap mapboxMap) { + ((NearbyActivity)getActivity()).setMapViewTutorialShowCase(); NearbyMapFragment.this.mapboxMap = mapboxMap; updateMapSignificantly(); } @@ -519,6 +525,7 @@ public class NearbyMapFragment extends DaggerFragment { private void addNearbyMarkerstoMapBoxMap() { mapboxMap.addMarkers(baseMarkerOptions); + mapboxMap.setOnInfoWindowCloseListener(marker -> { if (marker == selected) { bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); @@ -534,6 +541,7 @@ public class NearbyMapFragment extends DaggerFragment { }); mapboxMap.setOnMarkerClickListener(marker -> { + if (marker instanceof NearbyMarker) { this.selected = marker; NearbyMarker nearbyMarker = (NearbyMarker) marker; @@ -541,6 +549,7 @@ public class NearbyMapFragment extends DaggerFragment { passInfoToSheet(place); bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + } return false; }); @@ -634,7 +643,19 @@ public class NearbyMapFragment extends DaggerFragment { addAnchorToSmallFABs(fabGallery, getActivity().findViewById(R.id.empty_view).getId()); addAnchorToSmallFABs(fabCamera, getActivity().findViewById(R.id.empty_view1).getId()); + thirdSingleShowCaseView = new MaterialShowcaseView.Builder(this.getActivity()) + .setTarget(fabPlus) + .setDismissText(getString(R.string.showcase_view_got_it_button)) + .setContentText(getString(R.string.showcase_view_plus_fab)) + .setDelay(500) // optional but starting animations immediately in onCreate can make them choppy + .singleUse(ViewUtil.SHOWCASE_VIEW_ID_3) // provide a unique ID used to ensure it is only shown once + .setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD)) + .build(); + isMapReady = true; + if (isSecondMaterialShowcaseDismissed) { + thirdSingleShowCaseView.show(getActivity()); + } } @@ -791,6 +812,13 @@ public class NearbyMapFragment extends DaggerFragment { this.bundleForUpdtes = bundleForUpdtes; } + public void onNearbyMaterialShowcaseDismissed() { + isSecondMaterialShowcaseDismissed = true; + if (isMapReady) { + thirdSingleShowCaseView.show(getActivity()); + } + } + @Override public void onStart() { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java new file mode 100644 index 000000000..c6e46611d --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyMaterialShowcaseSequence.java @@ -0,0 +1,18 @@ +package fr.free.nrw.commons.nearby; + +import android.app.Activity; + +import uk.co.deanwild.materialshowcaseview.MaterialShowcaseSequence; +import uk.co.deanwild.materialshowcaseview.ShowcaseConfig; + + +public class NearbyMaterialShowcaseSequence extends MaterialShowcaseSequence { + + public NearbyMaterialShowcaseSequence(Activity activity, String sequenceID) { + super(activity, sequenceID); + ShowcaseConfig config = new ShowcaseConfig(); + config.setDelay(500); // half second between each showcase view + this.setConfig(config); + this.singleUse(sequenceID); // Display tutorial only once + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java index 1c45e8178..0c22a40a2 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -10,6 +10,10 @@ import android.widget.Toast; public class ViewUtil { + public static final String SHOWCASE_VIEW_ID_1 = "SHOWCASE_VIEW_ID_1"; + public static final String SHOWCASE_VIEW_ID_2 = "SHOWCASE_VIEW_ID_2"; + public static final String SHOWCASE_VIEW_ID_3 = "SHOWCASE_VIEW_ID_3"; + public static void showSnackbar(View view, int messageResourceId) { Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show(); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00bfafdad..dcea51bcc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -271,9 +271,15 @@ Cancel Retry + Got it! + These are the places near you that need pictures to illustrate their Wikipedia articles + Tapping this button brings up a list of these places + You can upload a picture for any place from your gallery or camera + No images found! Error occurred while loading images. Uploaded by: %1$s + Share App Coordinates were not specified during image selection From 1ae28e37c32da3aa553d1c36655210fd30f1f98d Mon Sep 17 00:00:00 2001 From: Kaartic Sivaraam Date: Tue, 8 May 2018 06:34:09 +0000 Subject: [PATCH 092/184] CONTRIBUTING: fix formatting of the gist of the guidelines (#1453) * CONTRIBUTING: fix formatting of the gist of the guidelines First level headings for a gist seems to be overkill. So, replace first level headings with an ordered-list which sounds more meaningful. * CONTRIBUTING: specify clearly that 'blame' is a feature of "Git" The contributing file specifies about the ability to know who wrote something without the need of @author javadoc tags but incorrectly attributes the feature to GitHub. Correctly attribute the feature to where it belongs, Git, and specify the name of the feature to help users easily take advantage of it. --- CONTRIBUTING.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a8e7af19..caa02a103 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,23 +5,30 @@ If you're not sure where to start head on to [this wiki page](https://github.com Here's a gist of the guidelines, -# Make separate commits for logically separate changes +1. Make separate commits for logically separate changes -# Describe your changes well in the commit message +1. Describe your changes well in the commit message -The first line of the commit message should be a short description of what has + The first line of the commit message should be a short description of what has changed. It is also good to prefix the first line with "area: " where the "area" is a filename or identifier for the general area of the code being modified. The body should provide a meaningful commit message. -# Write Javadocs +1. Write Javadocs -We require contributors to include Javadocs for all new methods and classes submitted via PRs (after 1 May 2018). This is aimed at making it easier for new contributors to dive into our codebase, especially those who are new to Android development. A few things to note: + We require contributors to include Javadocs for all new methods and classes + submitted via PRs (after 1 May 2018). This is aimed at making it easier for + new contributors to dive into our codebase, especially those who are new to + Android development. A few things to note: -- This should not replace the need for code that is easily-readable in and of itself -- Please make sure that your Javadocs are reasonably descriptive, not just a copy of the method name -- Please do not use `@author` tags - we aim for collective code ownership, and if needed, GitHub allows us to see who wrote something without needing to add these tags + - This should not replace the need for code that is easily-readable in + and of itself + - Please make sure that your Javadocs are reasonably descriptive, not just + a copy of the method name + - Please do not use `@author` tags - we aim for collective code ownership, + and if needed, Git allows us to see who wrote something without needing + to add these tags (`git blame`) -# Write tests for your code (if possible) +1. Write tests for your code (if possible) -# Make sure the Wiki pages don't become stale by updating them (if needed) +1. Make sure the Wiki pages don't become stale by updating them (if needed) From cd212b7daa96960c5aa70fbd7b0088a40897b345 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Tue, 8 May 2018 12:21:13 +0530 Subject: [PATCH 093/184] Feature/switch to butterknife (#1494) * Implemented butterknife in MediaDetailFragment [issue #1491] * Implemented butterknife in MediaDetailPagerFragment [[issue #1491]] * post merge upstream master wip [[issue #1491]] --- .../commons/media/MediaDetailFragment.java | 200 ++++++++++-------- .../media/MediaDetailPagerFragment.java | 7 +- 2 files changed, 112 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index c3a977ab5..9614c4f00 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -9,6 +9,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.Editable; +import android.text.TextUtils; import android.text.TextWatcher; import android.util.TypedValue; import android.view.LayoutInflater; @@ -22,6 +23,9 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -45,7 +49,8 @@ import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.ui.widget.CompatTextView; import timber.log.Timber; -import static android.view.View.*; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_SHORT; public class MediaDetailFragment extends CommonsDaggerSupportFragment { @@ -75,23 +80,37 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Inject MediaWikiApi mwApi; - - private MediaWikiImageView image; - private MediaDetailSpacer spacer; private int initialListTop = 0; - private TextView title; - private TextView desc; - private TextView author; - private TextView license; - private TextView coordinates; - private TextView uploadedDate; - private TextView seeMore; - private LinearLayout nominatedforDeletion; - private LinearLayout categoryContainer; - private LinearLayout authorLayout; - private Button delete; - private ScrollView scrollView; + @BindView(R.id.mediaDetailImage) + MediaWikiImageView image; + @BindView(R.id.mediaDetailSpacer) + MediaDetailSpacer spacer; + @BindView(R.id.mediaDetailTitle) + TextView title; + @BindView(R.id.mediaDetailDesc) + TextView desc; + @BindView(R.id.mediaDetailAuthor) + TextView author; + @BindView(R.id.mediaDetailLicense) + TextView license; + @BindView(R.id.mediaDetailCoordinates) + TextView coordinates; + @BindView(R.id.mediaDetailuploadeddate) + TextView uploadedDate; + @BindView(R.id.seeMore) + TextView seeMore; + @BindView(R.id.nominatedDeletionBanner) + LinearLayout nominatedForDeletion; + @BindView(R.id.mediaDetailCategoryContainer) + LinearLayout categoryContainer; + @BindView(R.id.authorLinearLayout) + LinearLayout authorLayout; + @BindView(R.id.nominateDeletion) + Button delete; + @BindView(R.id.mediaDetailScrollView) + ScrollView scrollView; + private ArrayList categoryNames; private boolean categoriesLoaded = false; private boolean categoriesPresent = false; @@ -101,6 +120,9 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private AsyncTask detailFetchTask; private LicenseList licenseList; + //Had to make this class variable, to implement various onClicks, which access the media, also I fell why make separate variables when one can serve the purpose + private Media media; + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -137,22 +159,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { final View view = inflater.inflate(R.layout.fragment_media_detail, container, false); - image = (MediaWikiImageView) view.findViewById(R.id.mediaDetailImage); - scrollView = (ScrollView) view.findViewById(R.id.mediaDetailScrollView); - - // Detail consists of a list view with main pane in header view, plus category list. - spacer = (MediaDetailSpacer) view.findViewById(R.id.mediaDetailSpacer); - title = (TextView) view.findViewById(R.id.mediaDetailTitle); - desc = (TextView) view.findViewById(R.id.mediaDetailDesc); - author = (TextView) view.findViewById(R.id.mediaDetailAuthor); - license = (TextView) view.findViewById(R.id.mediaDetailLicense); - coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates); - uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate); - seeMore = (TextView) view.findViewById(R.id.seeMore); - nominatedforDeletion = (LinearLayout) view.findViewById(R.id.nominatedDeletionBanner); - delete = (Button) view.findViewById(R.id.nominateDeletion); - categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer); - authorLayout = (LinearLayout) view.findViewById(R.id.authorLinearLayout); + ButterKnife.bind(this,view); if (isFeaturedMedia){ authorLayout.setVisibility(VISIBLE); @@ -196,7 +203,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Override public void onResume() { super.onResume(); - Media media = detailProvider.getMediaAtPosition(index); + media = detailProvider.getMediaAtPosition(index); if (media == null) { // Ask the detail provider to ping us when we're ready Timber.d("MediaDetailFragment not yet ready to display details; registering observer"); @@ -209,17 +216,18 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { Timber.d("MediaDetailFragment ready to display delayed details!"); detailProvider.unregisterDataSetObserver(dataObserver); dataObserver = null; - displayMediaDetails(detailProvider.getMediaAtPosition(index)); + media=detailProvider.getMediaAtPosition(index); + displayMediaDetails(); } }; detailProvider.registerDataSetObserver(dataObserver); } else { Timber.d("MediaDetailFragment ready to display details"); - displayMediaDetails(media); + displayMediaDetails(); } } - private void displayMediaDetails(final Media media) { + private void displayMediaDetails() { //Always load image from Internet to allow viewing the desc, license, and cats image.setMedia(media); @@ -256,7 +264,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { if (success) { extractor.fill(media); setTextFields(media); - setOnClickListeners(media); } else { Timber.d("Failed to load photo details."); } @@ -316,74 +323,81 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { checkDeletion(media); } - private void setOnClickListeners(final Media media) { - if (licenseLink(media) != null) { - license.setOnClickListener(v -> openWebBrowser(licenseLink(media))); + @OnClick(R.id.mediaDetailLicense) + public void onMediaDetailLicenceClicked(){ + if (!TextUtils.isEmpty(licenseLink(media))) { + openWebBrowser(licenseLink(media)); } else { if(isFeaturedMedia) { - Timber.d("Unable to fetch license URL for %s", media.getLicense()); + Timber.d("Unable to fetch license URL for %s", media.getLicense()); } else { Toast toast = Toast.makeText(getContext(), getString(R.string.null_url), Toast.LENGTH_SHORT); toast.show(); } } + } + + @OnClick(R.id.mediaDetailCoordinates) + public void onMediaDetailCoordinatesClicked(){ if (media.getCoordinates() != null) { - coordinates.setOnClickListener(v -> openMap(media.getCoordinates())); + openMap(media.getCoordinates()); } - if (delete.getVisibility() == VISIBLE) { - enableDeleteButton(true); + } - delete.setOnClickListener(v -> { + @OnClick(R.id.nominateDeletion) + public void onDeleteButtonClicked(){ + //Reviewer correct me if i have misunderstood something over here + //But how does this if (delete.getVisibility() == View.VISIBLE) { + // enableDeleteButton(true); makes sense ? + AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); + alert.setMessage("Why should this file be deleted?"); + final EditText input = new EditText(getActivity()); + alert.setView(input); + input.requestFocus(); + alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + String reason = input.getText().toString(); + DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); + deleteTask.execute(); + enableDeleteButton(false); + } + }); + alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }); + AlertDialog d = alert.create(); + input.addTextChangedListener(new TextWatcher() { + private void handleText() { + final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); + if (input.getText().length() == 0) { + okButton.setEnabled(false); + } else { + okButton.setEnabled(true); + } + } - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); - alert.setMessage("Why should this file be deleted?"); - final EditText input = new EditText(getActivity()); - alert.setView(input); - input.requestFocus(); - alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - String reason = input.getText().toString(); - DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason); - deleteTask.execute(); - enableDeleteButton(false); - } - }); - alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }); - AlertDialog d = alert.create(); - input.addTextChangedListener(new TextWatcher() { - private void handleText() { - final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE); - if (input.getText().length() == 0) { - okButton.setEnabled(false); - } else { - okButton.setEnabled(true); - } - } + @Override + public void afterTextChanged(Editable arg0) { + handleText(); + } - @Override - public void afterTextChanged(Editable arg0) { - handleText(); - } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + }); + d.show(); + d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); + } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - }); - d.show(); - d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); - }); - } - if (nominatedforDeletion.getVisibility() == VISIBLE){ - seeMore.setOnClickListener(v -> { - openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); - }); + @OnClick(R.id.seeMore) + public void onSeeMoreClicked(){ + if(nominatedForDeletion.getVisibility()== VISIBLE) { + openWebBrowser(media.getFilePageTitle().getMobileUri().toString()); } } @@ -488,11 +502,11 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private void checkDeletion(Media media){ if (media.getRequestedDeletion()){ delete.setVisibility(GONE); - nominatedforDeletion.setVisibility(VISIBLE); + nominatedForDeletion.setVisibility(VISIBLE); } else{ delete.setVisibility(VISIBLE); - nominatedforDeletion.setVisibility(GONE); + nominatedForDeletion.setVisibility(GONE); } } diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index c0564c603..62d1261cf 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -26,6 +26,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; import javax.inject.Inject; import javax.inject.Named; @@ -53,7 +55,8 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple @Named("default_preferences") SharedPreferences prefs; - private ViewPager pager; + @BindView(R.id.mediaDetailsPager) + ViewPager pager; private Boolean editable; private boolean isFeaturedImage; @@ -72,7 +75,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_media_detail_pager, container, false); - pager = (ViewPager) view.findViewById(R.id.mediaDetailsPager); + ButterKnife.bind(this,view); pager.addOnPageChangeListener(this); final MediaDetailAdapter adapter = new MediaDetailAdapter(getChildFragmentManager()); From d012572b926afe709f08cefaf341c7fb55926c30 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 10 May 2018 10:11:14 +0200 Subject: [PATCH 094/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ar/strings.xml | 1 + app/src/main/res/values-bn/strings.xml | 3 + app/src/main/res/values-de/strings.xml | 8 +++ app/src/main/res/values-diq/strings.xml | 8 +++ app/src/main/res/values-el/strings.xml | 8 +++ app/src/main/res/values-es/strings.xml | 8 +++ app/src/main/res/values-eu/strings.xml | 17 +++-- app/src/main/res/values-fr/strings.xml | 9 +++ app/src/main/res/values-it/strings.xml | 7 +++ app/src/main/res/values-iw/strings.xml | 8 +++ app/src/main/res/values-ja/strings.xml | 73 +++++++++++++++++++--- app/src/main/res/values-ko/strings.xml | 8 +++ app/src/main/res/values-lb/strings.xml | 4 ++ app/src/main/res/values-lv/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 8 +++ app/src/main/res/values-pl/strings.xml | 2 + app/src/main/res/values-pms/strings.xml | 8 +++ app/src/main/res/values-pt-rBR/strings.xml | 8 +++ app/src/main/res/values-pt/strings.xml | 19 ++++-- app/src/main/res/values-ru/strings.xml | 9 +++ app/src/main/res/values-skr/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 20 ++++-- app/src/main/res/values-zh-rTW/strings.xml | 10 ++- app/src/main/res/values-zh/strings.xml | 8 +++ 24 files changed, 231 insertions(+), 25 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 6d9c94c1d..a9127c1eb 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -145,4 +145,5 @@ مرحبا بكم في ويكيمديا كومنز، %1$s! نحن سعداء لأنك هنا. %1$s رسالة على صفحة الحديث %1$s ذكر لك على %2$s. + شارك التطبيق diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 679c50803..e7167393c 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -259,4 +259,7 @@ ইন্টারনেট উপলব্ধ কোন বিজ্ঞপ্তি পাওয়া যায়নি পুনঃচেষ্টা করুন + বুঝেছি! + কোন চিত্র পাওয়া যায়নি! + আপলোড করেছেন: %1$s diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 36e013976..5f751153c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -269,5 +269,13 @@ Fortfahren Abbrechen Erneut versuchen + Verstanden! + Dies sind die Orte in deiner Nähe, die Bilder zur Illustration ihrer Wikipedia-Artikel benötigen. + Das Antippen dieser Schaltfläche zeigt eine Liste mit diesen Orten + Du kannst ein Bild für einen beliebigen Ort von deiner Galerie oder Kamera hochladen + Keine Bilder gefunden! + Beim Laden der Bilder ist ein Fehler aufgetreten. + Hochgeladen von: %1$s App teilen + Während der Bildauswahl wurden keine Koordinaten angegeben diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index 2b66709f0..1f1d69ea3 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -9,11 +9,15 @@ * Mirzali --> + Asayış + Bıngeh + Lokasyon Commons Eyari Namey karberi Parola Cı kewe + Parola, xo vira kerde? Qeyd be Cıkewtış Kerem kerên, bıpawên... @@ -58,6 +62,8 @@ Bar ke Kategoriyan dı cı geyr Star ke + Newe ke + Liste \@string/contributions_subtitle_zero Yew barbiyayış @@ -129,5 +135,7 @@ Keye Bar ke Veciyayış + Bıtexelne Anciya bıcerrebne + Mı fehm kerd! diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 0dae5c65e..ee50aa3d7 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -273,5 +273,13 @@ Συνέχεια Ακύρωση Ξαναπροσπαθήστε + Κατάλαβα! + Αυτά είναι τα μέρη κοντά σας που χρειάζονται φωτογραφίες για να εικονογραφηθούν τα λήμματά τους στη Βικιπαίδεια + Πατώντας αυτό το κουμπί φέρνει μια λίστα αυτών των μερών + Μπορείτε να ανεβάσετε μια εικόνα για οποιοδήποτε μέρος από την γκαλερί ή την κάμερά σας + Δεν βρέθηκαν εικόνες! + Συνέβη σφάλμα κατά το ανέβασμα των εικόνων. + Ανέβηκε από: %1$s Κοινοποίηση εφαρμογής + Οι συντεταγμένες δεν ορίστηκαν κατά την διάρκεια της επιλογής εικόνας diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c1a45b309..69cf2f8b7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -267,4 +267,12 @@ Selecciona el idioma en que quieres enviar traducciones Cancelar Reintentar + Entendido + Estos sitios cercanos a ti necesitan imágenes para ilustrar sus artículos de Wikipedia + Puedes cargar una imagen para cualquier sitio desde la galería o la cámara + No se encontró ninguna imagen. + Se produjo un error al cargar las imágenes. + Cargada por: %1$s + Compartir aplicación + No se especificaron las coordenadas al seleccionar la imagen diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index f44262e05..a109ff541 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -8,11 +8,17 @@ * Theklan --> + Itxura + Orokorra + Feedback + Kokapena Commons + Hobespenak Erabiltzaile izena Pasahitza Saioa hasi + Pasahitza ahaztu duzu? Eman izena Saioa hasten Mesedez itxaron… @@ -54,22 +60,23 @@ Kategoriak bilatu Gorde Eguneratu + Zerrenda GPSa gaitu Oraindik ez da ezer igo - - Oraindik igoerarik ez + + \@string/contributions_subtitle_zero igoera 1 %1$d igoera Ez da kategoriak aukritu %1$s izenarekin - Gehitu kategoriak zure argazkiak Wikimedia Commonsen aurkitzen errazagoak izan daitezen. + Gehitu kategoriak zure argazkiak Wikimedia Commonsen aurkitzen errazagoak izan daitezen.\nHasi idazten kategoriak gehitzeko. Kategoriak Hobespenak Eman izena Honi buruz Open Source softwarea <a href=\"https://github.com/commons-app/apps-android-commons/blob/master/COPYING\">Apache v2 Lizentziaren</a> pean egina. Wikimedia Commons eta bere logoa Wikimedia Fundazioaren marka erregistratuak dira eta Wikimedia Fundazioaren baimenarekin erabiltzen dira. Ez gaude Wikimedia Fundaziora afiliatuta. GitHub-eko <a href=\"https://github.com/commons-app/apps-android-commons\">Iturria</a> eta <a href=\"https://commons-app.github.io/\">webgunea</a>. <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-eko gai</a> berria sortu erroreen berri emateko. - <a href=\"https://wikimediafoundation.org/wiki/Privacy_policy\">Pribatutasun politika</a> + <u>Pribatutasun politika</u> Honi buruz Bidali zure iritzia (e-posta bidez) Posta bezerorik ez da instalatu @@ -81,7 +88,7 @@ Irudi hau %1$s lizentziapean egongo da Irudi hau bidaltzen, nire lan propioa dela aitortzen dut, copyrighta duten materiala edo selfiak ez duela, eta beste motatakoak <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Ohikoaren arauak</a> Jaitsi - Lizentzia + Berezko lizentzia Aurreko izenburu/deskribapena erabili Oraingo kokapena automatikoki lortu Gau modua diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 442fc6bc5..6dd08a30d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -5,6 +5,7 @@ * Happy13241 * Jean-Frédéric * KATRINE1992 +* Melissadeba95 * Metroitendo * Nicolas Raoul * Orikrin1998 @@ -279,5 +280,13 @@ Continuer Annuler Réessayer + C’est bon ! + Il y a des lieux autour de vous qui demandent des images pour illustrer leurs articles Wikipédia + En cliquant sur ce bouton vous afficherez une liste de ces endroits + Vous pouvez téléverser une photo de n\'importe quel endroit de votre gallerie ou de votre appareil photo + Aucune images trouvée. + Une erreur s\'est produite pendant le chargement des images. + Importé par:%1$s Partager les applications + Les coordonnées n\'ont pas été spécifiées pendant la sélection de l\'image diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 306a1e3a4..06bfa701f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -223,4 +223,11 @@ Lingue Annulla Riprova + Capito! + Questi sono i luoghi vicino a te che necessitano di immagini per illustrare le loro voci di Wikipedia + Puoi caricare un\'immagine per ogni luogo dalla tua galleria o fotocamera + Nessuna immagine trovata! + Si è verificato un errore durante il caricamento delle immagini. + Caricato da: %1$s + Condividi applicazione diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 762a3be31..f0cdf1f3d 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -273,5 +273,13 @@ המשך ביטול לנסות שוב + הבנתי! + אלה המקומות בסביבתך שזקוקים לתמונות כדי להמחיש את הערכים שלהם בוויקיפדיה + ניתן ללחוץ על כפתור זה כדי להציג רשימה של המקומות האלה + באפשרותך להעלות תמונה של כל מקום מהגלריה או מהמצלמה שלך + לא נמצאו תמונות! + אירעה שגיאה בטעינת התמונות. + הועלתה על־ידי: %1$s שיתוף היישום + לא צוינו קואורדינטות בעת בחירת התמונה diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index e34c98432..ef45a5d3a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -12,13 +12,18 @@ * Yusuke1109 --> + 表示 + 全般 フィードバック 場所 コモンズ + 設定 利用者名 パスワード + コモンズのベータ版アカウントにログイン ログイン + パスワードを忘れた場合 利用者登録 ログイン中 お待ちください… @@ -49,6 +54,7 @@ 共有 ブラウザーで表示 タイトル + ファイル名をつけてください 説明 ログインできません - ネットワークのエラーです ログインできません - 利用者名を確認してください @@ -64,6 +70,7 @@ カテゴリを検索 保存 更新 + 一覧 お使いのデバイスではGPSが無効になっています。有効にしますか? GPSを有効にする まだ何もアップロードされていません。 @@ -82,6 +89,7 @@ カテゴリ 設定 利用者登録 + 秀逸な画像 このアプリについて ウィキメディア・コモンズ・アプリはウィキメディア・コミュニティの助成金受給者とボランティアによって製作・メンテナンスされているオープンソースソフトウェアです。ウィキメディア財団はこのアプリの製作・開発・メンテナンスに関与していません。 バグとアイディアは <a href=\"https://github.com/commons-app/apps-android-commons/issues\">Github</a> へ。 @@ -96,6 +104,7 @@ 再試行 キャンセル この画像が %1$s ライセンスでアップロードされます。 + この画像の投稿に当たり、私はこれが自分自身の作品であり、著作権のあるコンテンツや自撮りは含まれていないと宣言します。 ダウンロード 既定のライセンス 前回のタイトルと記述を使用 @@ -126,11 +135,19 @@ ウィキメディア・コモンズにはウィキペディアで使用する画像のほぼすべてが保管されています。 あなたの画像は世界中の人々が学習する助けになります! アップロードする画像はあなたご本人が撮影したものかあなたが単独で制作したものに限定します。 - - 自然物 (動植物、山)\n- 道具 (自転車、駅)\n- 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) + 自然物 (動植物、山)\n• 道具 (自転車、駅)\n• 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) + 自然物 (動植物、山) + 道具 (自転車、駅) + 著名人 (市区村長・都道府県知事、自分が会ったオリンピック選手) アップロードが《禁止》のもの: - あなたの友人の自撮り写真や画像\n- インターネットからダウンロードした画像\n- 著作権のあるアプリのスクリーンショット + 自撮りもしくは友達を撮影した写真 + ウェブからダウンロードした画像 + 独自のアプリケーションのスクリーンショット アップロードの例: - 題名: シドニー・オペラハウス\n- 説明: 湾の向こうから見たシドニー・オペラハウス\n- カテゴリ: 西側から見たシドニー・オペラハウス、遠くから見たシドニー・オペラハウス + 題名: シドニーのオペラハウス + 説明: シドニーのオペラハウス。湾を挟んで撮影。 画像を投稿してください。ウィキペディアの記事に彩りを! ウィキペディアの画像はウィキメディア・コモンズに保管されています。 あなたの画像は世界中の人々が学習する助けになります @@ -143,11 +160,11 @@ 説明はありません。 不明なライセンス 更新 - 必要な権限:外部ストレージを読み込みます。これがなければアプリは機能しません。 - 必要な権限:外部ストレージを作成します。これがなければアプリは機能しません。 - オプションの権限:カテゴリ候補の現在の位置を取得する + 必要な権限:外部ストレージを読み込みます。これがなければアプリはギャラリーを開けません。 + 必要な権限:外部ストレージに入力します。これがないとアプリはカメラにアクセスできません。 + オプションの権限:カテゴリ候補のため現在の位置を取得する 承認 - 周りの場所 + 近くの場所 付近の場所が見つかりません 警告 このファイルが既にコモンズにあります。本当にアップロードしますか? @@ -158,6 +175,7 @@ 記述 ここにメディアの説明が入ります。かなり長文になる場合には数行にわたることがあります。それでも見栄えがよいと願っています。 作者 + 秀逸な画像の作者名を記入します。 アップロード日時 ライセンス 緯度経度 @@ -174,14 +192,19 @@ コモンズの商標 コモンズのウェブサイト コモンズのフェイスブックページ + コモンズのGithubソースコード 背景画像 + メディアイメージが失敗しました 画像がありません 画像をアップロード 蔵王連峰 リャマ レインボーブリッジ チューリップ + 自撮りはアップロードできません + 独自の著作権がある画像 ウィキペディアへようこそ + 著作権について シドニーオペラハウス キャンセル 開く @@ -195,28 +218,62 @@ ログアウト チュートリアル 通知 - 場所の権限がないと、近くの場所を表示できません + 秀逸 + 場所の権限がないため、近くの場所を表示できません 説明がありません + コモンズのファイルページ ウィキデータ項目 ウィキペディアの記事 画像をキャッシュする際のエラー ファイル固有の説明的な表題。ファイル名として使われます。平易な言葉を使い、空白を入れることができます。拡張子は含めないでください。 可能な限りメディアを説明してください:どこで撮られましたか?それは何を示していますか?文脈とは何ですか?物や人を説明してください。容易に推測できない情報、例えば風景の場合の時刻を明らかにする。メディアに珍しいことがある場合は、何が珍しいのかを説明してください。 - 権限を取得 + この画像は暗すぎますがアップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 + ピントが合っていませんが、アップロードしますか? ウィキメディア・コモンズは百科事典に適した画像のみ受け付けます。 + 権限を付与 外部ストレージを使用 アプリ内のカメラで撮影した写真を端末に保存する 自分のアカウントにログイン ログファイルを送信する メールで開発者にログファイルを送信する + URLを開くブラウザーが見つかりません + エラーが発生しました。URL が見つかりません + 削除の提案 + この画像の削除が提案されています。 ブラウザーで表示 場所は変更されていません。 位置が無効です。 + 近くの場所を表示するには権限が必要です + 道順を調べる 記事を読む + ウィキメディアコモンズにようこそ、%1$さん! このサイトへ来てくれてありがとうございます。 + %1$さんからアナタのとーくぺ^字にメッセージが届いています + 編集をしてくれてありがとうございます + %1$さんが%2$であなたに言及しています。 + 表示の切り替え + 道順 + ウィキデータ + ウィキペディア + コモンズ <u>評価する</u> <u>FAQ</u> チュートリアルをスキップする + インターネットに接続していません + インターネットに接続しました + 通知の取得に失敗しました + 通知はありません <u>翻訳</u> 言語 + どの言語に編集するか選択 + 次へ キャンセル - 再試行 + やり直す + 了解 + 近くでウィキペディアの記事に使う写真がない場所はこちら + このボタンをタップするとリストを表示します + 場所の写真をアップロードするには、ギャラリーから選ぶことも撮影することもできます + 画像がありません + 画像の読み込み中にエラーが発生しました + アップロードした人: %1$ + アプリをシェアする + 画像の選択中に位置情報を特定できませんでした diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d0e1c21ed..e80999d54 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -266,5 +266,13 @@ 진행 취소 다시 시도 + 알겠습니다! + 이들은 위키백과 글에 사진을 넣을 필요가 있는 당신 주위의 장소들입니다 + 이 버튼을 탭하면 이 장소들의 목록을 가져옵니다 + 갤러리나 카메라 어느 곳이든 사진을 올릴 수 있습니다 + 그림이 없습니다! + 그림을 불러오는 동안 오류가 발생했습니다. + 올린이: %1$s 앱 공유 + 그림 선택 중에 좌표가 지정되지 않았습니다 diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml index 5abca6562..d346b90bd 100644 --- a/app/src/main/res/values-lb/strings.xml +++ b/app/src/main/res/values-lb/strings.xml @@ -240,4 +240,8 @@ Virufueren Ofbriechen Nach eng Kéier probéieren + Verstanen! + Keng Biller fonnt! + Feeler beim Eropluede vu Biller. + Eropgeluede vum: %1$s diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 1eba570d2..b6c5103e2 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -109,4 +109,5 @@ Valodas Turpināt Atcelt + Sapratu! diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 4e44dad60..492e1bc0c 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -263,5 +263,13 @@ Продолжи Откажи Пробај пак + Јасно! + Ова се места во ваша близинана кои им требаат слики за илустрирање на нивните статии на Википедија + Ако допрете на копчево ќе добиете список на тие места + Можете да подигнете слика за било кое од местата од вашата галерија или камера + Не пронајдов ниедна слика! + Се појави грешка при вчитувањето на сликите. + Подигач: %1$s Сподели прилог + Не беа укажани координати при изборот на сликата diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 77cdb547d..ccc5f374f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -227,4 +227,6 @@ Nie znaleziono powiadomień Języki Anuluj + Nie znaleziono grafik! + Wystąpił błąd podczas ładowania grafik. diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 30115f1ad..53ce91cc5 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -263,5 +263,13 @@ Andé anans Anulé Prové torna + Fàit! + A-i é dij pòst davzin a chiel ch\'a l\'han da manca ëd plance për ilustré ij sò artìcoj su Wikipedia + Sgnacand su \'s boton a comparirà na lista ëd si pòst + A peul carié na fòto da \'n pòst qualsëssìa ëd soa galarìa o màchina fòto + Gnun-e plance trovà! + A-i é staje n\'eror durant ël cariament ëd le plance. + Carià da: %1$s Partagé j\'aplicassion + Le coordinà a son nen ëstàite spessificà durant la selession ëd la plancia diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6722ae4bb..23b5e4abf 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -275,5 +275,13 @@ Avançar Cancelar Tentar novamente + Entendido! + Estes são os lugares perto de você que precisam de fotografias para ilustrar os respetivos artigos na Wikipédia + Tocar neste botão fará surgir uma lista destes lugares + Pode carregar uma fotografia para qualquer dos lugares, da sua galeria ou câmara + Não foi encontrada nenhuma imagem! + Ocorreu um erro durante o carregamento das imagens. + Carregada por: %1$s Compartilhar o aplicativo + Não foram especificadas coordenadas durante a seleção da imagem diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index b0717f3dc..3da1296b7 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -16,12 +16,12 @@ Geral Comentários Localização - Wikimedia Commons + Commons Configurações - Nome de utilizador(a) + Nome de utilizador Palavra-passe - Entre com a sua conta do Commons Beta + Entre com a sua conta da wiki Commons Beta Iniciar sessão Esqueceu-se da palavra-passe? Registar-se @@ -118,7 +118,7 @@ Utilizar tema escuro Atribuição-CompartilhaIgual 4.0 Atribuição 4.0 - Atribuição – Compartilhamento pela mesma Licença + Atribuição–CompartilhaIgual 3.0 Atribuição 3.0 CC0 CC BY-SA 3.0 @@ -136,7 +136,7 @@ CC-BY-SA 4.0 CC BY 4.0 CC Zero - Wikimedia Commons armazena a maioria das imagens que são usadas na Wikipédia. + A wiki Wikimedia Commons aloja a maioria das imagens que são usadas na Wikipédia. As suas imagens ajudam a educar pessoas em todo o mundo! Por favor, carregue apenas imagens tiradas ou criadas exclusivamente por si: Objetos naturais (flores, animais, montanhas)\n• Objetos úteis (bicicletas, estações de comboio)\n• Pessoas famosas (o seu presidente da câmara, atletas olímpicos que conheça) @@ -274,4 +274,13 @@ Avançar Cancelar Tentar novamente + Entendido! + Estes são os lugares perto de si que precisam de fotografias para ilustrar os respetivos artigos na Wikipédia + Tocar neste botão fará surgir uma lista destes lugares + Pode carregar uma fotografia para qualquer dos lugares, da sua galeria ou câmara + Não foi encontrada nenhuma imagem! + Ocorreu um erro durante o carregamento das imagens. + Carregada por: %1$s + Partilhar aplicação + Não foram especificadas coordenadas durante a seleção da imagem diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 4dc90489d..ce71af94b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -285,4 +285,13 @@ Выполняется Отмена Повторить + Понятно! + Это места поблизости, статьи о которых нуждаются в иллюстрациях + Нажатие этой кнопки сгенерирует список таких мест + Вы можете загрузить изображение для любого из этих мест, сделав снимок камерой или выбрав уже существующее изображение из галереи + Изображений не найдено! + Произошла ошибка при загрузке изображений. + Загружено участником %1$s + Поделиться приложением + Во время выбора изображения не были указаны координаты diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index 796ae8555..73a5b7e51 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -129,4 +129,5 @@ اڳوں تے تھیوو منسوخ ولدا کوشش کرو + گھن گھندا diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 24ef60b61..17a324a97 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -90,9 +90,9 @@ Kategorier Inställningar Registrera - Utvalda bild + Utvalda bilder Om - Wikimedia Commons är en app med öppen källkod som skapas och underhålls av frivilliga från Wikimedias gemenskap. Wikimedia Foundation är inte involverad i skapandet, utvecklingen eller underhållet av appen. + Wikimedia Commons-appen är en app med öppen källkod som skapas och underhålls av frivilliga från Wikimedias gemenskap. Wikimedia Foundation är inte involverad i skapandet, utvecklingen eller underhållet av appen. Skapa ett nytt <a href=\"https://github.com/commons-app/apps-android-commons/issues\">ärende på GitHub</a> för att rapportera buggar och förslag. <u>Integritetspolicy</u> <u>Erkännande</u> @@ -105,7 +105,7 @@ Försök igen Avbryt Denna bild kommer att licensieras under %1$s - Genom att skicka in denna bild intygar jag att detta är mitt eget verk, som inte innehåller upphovsrättsskyddat material eller selfies samt annars följer <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Commons-policys</a>. + Genom att skicka in denna bild intygar jag att detta är mitt eget verk, som inte innehåller upphovsrättsskyddat material eller selfies samt följer <a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\">Wikimedia Commons-policys</a>. Ladda ned Standardlicens Använd föregående titel/beskrivning @@ -135,7 +135,7 @@ CC Zero Wikimedia Commons lagrar de flesta bilderna som används på Wikipedia. Dina bilder hjälper till att utbilda\nmänniskor runt hela världen! - Ladda upp bilder som endast du har tagit eller skapat: + Ladda endast upp bilder som du har tagit eller skapat själv: Naturliga föremål (blommor, djur, berg)\n• Användbara föremål (cyklar, tågstationer)\n• Berömda personer (din borgmästare, olympiska atleter du har träffat) Naturliga föremål (blommor, djur, berg) Användbar föremål (cyklar, tågstationer) @@ -163,8 +163,8 @@ Ingen beskrivning Okänd licens Uppdatera - Nödvändig behörighet: Läsa extern lagring. Appen kan inte komma åt ditt galleri utan detta. - Nödvändig behörighet: Skriva till extern lagring. Appen kan inte komma åt din kamera utan detta. + Nödvändig behörighet: Läs extern lagring. Appen kan inte komma åt ditt galleri utan detta. + Nödvändig behörighet: Skriv till extern lagring. Appen kan inte komma åt din kamera utan detta. Valfri behörighet: Hämta aktuell plats för kategoriförslag OK Platser i närheten @@ -271,5 +271,13 @@ Fortsätt Avbryt Försök igen + Uppfattat! + Detta är platserna nära dig som behöver bilder för att illustrera deras Wikipedia-artiklar + Klicka på den här knappen för att få upp en lista med dessa platser + Du kan ladda upp en bild från vilken plats som helst från ditt galleri eller kamera + Inga bilder hittades! + Ett fel uppstod vid inläsning av bilder. + Uppladdad av: %1$s Dela app + Koordinater specificerades inte vid bildvalet diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index a2878cddf..80b595f5d 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -32,7 +32,7 @@ 未能核對身分! 開始上傳! 已上傳%1$s! - 點選檢視您上傳的項目 + 輕觸來檢視您上傳的項目 開始上傳%1$s 正在上傳%1$s 即將完成上傳 %1$s @@ -271,5 +271,13 @@ 已進行 取消 重試 + 了解! + 這些是在您的附近,並且需要圖片來圖解有關它們的維基百科條目之地點 + 輕觸此按鈕來帶出這些地點的清單 + 您可從您的圖庫或相機,來上傳任何地點的圖片 + 找不到圖片! + 當載入圖片時發生錯誤。 + 由:%1$s 上傳 分享應用程式 + 當選擇圖片時未指定座標 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index d3d049ea2..29a1ae898 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -269,5 +269,13 @@ 已处理 取消 重试 + 明白了! + 这些是您附近需要图片以阐明维基百科条目的地方 + 点按此按钮会出现这些地点的列表 + 您可以从您的图库或照相机中上传任意地点的图片 + 找不到图片! + 加载图片时出错。 + 由%1$s上传 分享应用 + 图片选择时,坐标并未指定 From 8bdc4f6b95a33ece82d68136446faa9c02d93a0a Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sat, 12 May 2018 16:49:43 +0530 Subject: [PATCH 095/184] Bug fix #1504 (#1506) * Bug fix #1504 * Filtered messages with ConnectException [issue #1504] * A generalised message for exceptions in Nearby Activity [issue #1504] --- .../nrw/commons/nearby/NearbyActivity.java | 29 ++++++++++++++++--- .../nrw/commons/nearby/NearbyController.java | 3 +- .../free/nrw/commons/nearby/NearbyPlaces.java | 10 +------ app/src/main/res/values/strings.xml | 1 + 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 3bf8beacf..04886fda4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -16,6 +16,7 @@ import android.support.design.widget.BottomSheetBehavior; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog; +import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -23,9 +24,14 @@ import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; +import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import io.reactivex.functions.Consumer; +import java.io.IOException; +import java.net.ConnectException; +import java.net.UnknownHostException; import java.util.List; import javax.inject.Inject; @@ -427,8 +433,14 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces); - } else if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { + .subscribe(this::populatePlaces, + throwable -> { + Timber.d(throwable); + showErrorMessage(getString(R.string.error_fetching_nearby_places)); + progressBar.setVisibility(View.GONE); + }); + } else if (locationChangeType + .equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, new UriSerializer()) .create(); @@ -451,7 +463,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp if (placeList.size() == 0) { ViewUtil.showSnackbar(findViewById(R.id.container), R.string.no_nearby); } - + bundle.putString("PlaceList", gsonPlaceList); //bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("BoundaryCoord", gsonBoundaryCoordinates); @@ -580,7 +592,12 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp .loadAttractionsFromLocation(curLatLng)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::populatePlaces); + .subscribe(this::populatePlaces, + throwable -> { + Timber.d(throwable); + showErrorMessage(getString(R.string.error_fetching_nearby_places)); + progressBar.setVisibility(View.GONE); + }); nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.updateMapSignificantly(); updateListFragment(); @@ -646,4 +663,8 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp public void prepareViewsForSheetPosition(int bottomSheetState) { // TODO } + + private void showErrorMessage(String message) { + ViewUtil.showLongToast(NearbyActivity.this, message); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index 015d22135..bd042b4d7 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -7,6 +7,7 @@ import android.support.graphics.drawable.VectorDrawableCompat; import com.mapbox.mapboxsdk.annotations.IconFactory; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -44,7 +45,7 @@ public class NearbyController { * @return NearbyPlacesInfo a variable holds Place list without distance information * and boundary coordinates of current Place List */ - public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng) { + public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng) throws IOException { Timber.d("Loading attractions near %s", curLatLng); NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo(); diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java index a2f4b2352..d05d81251 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java @@ -40,10 +40,9 @@ public class NearbyPlaces { } } - List getFromWikidataQuery(LatLng curLatLng, String lang) { + List getFromWikidataQuery(LatLng curLatLng, String lang) throws IOException { List places = Collections.emptyList(); - try { // increase the radius gradually to find a satisfactory number of nearby places while (radius <= MAX_RADIUS) { places = getFromWikidataQuery(curLatLng, lang, radius); @@ -54,13 +53,6 @@ public class NearbyPlaces { radius *= RADIUS_MULTIPLIER; } } - } catch (IOException e) { - Timber.d(e.toString()); - // errors tend to be caused by too many results (and time out) - // try a small radius next time - Timber.d("back to initial radius: %f", radius); - radius = INITIAL_RADIUS; - } // make sure we will be able to send at least one request next time if (radius > MAX_RADIUS) { radius = MAX_RADIUS; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dcea51bcc..6e30baa10 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -282,5 +282,6 @@ Share App Coordinates were not specified during image selection + Error fetching nearby places. From 2b867f0f9b22f802e56efe184468307669bda421 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 14 May 2018 08:13:34 +0200 Subject: [PATCH 096/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-bn/strings.xml | 1 + app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-el/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-iw/strings.xml | 1 + app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-mk/strings.xml | 1 + app/src/main/res/values-pms/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-pt/strings.xml | 1 + app/src/main/res/values-qq/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 9 +++++++++ app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values-zh/strings.xml | 1 + 15 files changed, 23 insertions(+) diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index e7167393c..7c76ebaea 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -262,4 +262,5 @@ বুঝেছি! কোন চিত্র পাওয়া যায়নি! আপলোড করেছেন: %1$s + কাছাকাছি স্থানগুলি আনতে ত্রুটি। diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5f751153c..9f47ce42e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -278,4 +278,5 @@ Hochgeladen von: %1$s App teilen Während der Bildauswahl wurden keine Koordinaten angegeben + Fehler beim Abrufen der Orte in der Nähe. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index ee50aa3d7..e372df836 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -282,4 +282,5 @@ Ανέβηκε από: %1$s Κοινοποίηση εφαρμογής Οι συντεταγμένες δεν ορίστηκαν κατά την διάρκεια της επιλογής εικόνας + Σφάλμα κατά την εύρεση κοντινών μερών. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 69cf2f8b7..9e5dae650 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -275,4 +275,5 @@ Cargada por: %1$s Compartir aplicación No se especificaron las coordenadas al seleccionar la imagen + Error al recuperar los lugares cercanos. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6dd08a30d..bfb14baf1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -289,4 +289,5 @@ Importé par:%1$s Partager les applications Les coordonnées n\'ont pas été spécifiées pendant la sélection de l\'image + Erreur durant l\'exploration du voisinage. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index f0cdf1f3d..9ba67e4ee 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -282,4 +282,5 @@ הועלתה על־ידי: %1$s שיתוף היישום לא צוינו קואורדינטות בעת בחירת התמונה + שגיאה באחזור המקומות בסביבתך. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index e80999d54..883665c85 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -275,4 +275,5 @@ 올린이: %1$s 앱 공유 그림 선택 중에 좌표가 지정되지 않았습니다 + 주변 장소를 가져오는데 오류가 있습니다. diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 492e1bc0c..a344fcad2 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -272,4 +272,5 @@ Подигач: %1$s Сподели прилог Не беа укажани координати при изборот на сликата + Грешка при добивањето на околните места. diff --git a/app/src/main/res/values-pms/strings.xml b/app/src/main/res/values-pms/strings.xml index 53ce91cc5..8b2bd292c 100644 --- a/app/src/main/res/values-pms/strings.xml +++ b/app/src/main/res/values-pms/strings.xml @@ -272,4 +272,5 @@ Carià da: %1$s Partagé j\'aplicassion Le coordinà a son nen ëstàite spessificà durant la selession ëd la plancia + Eror durant l\'esplorassion dj\'anviron. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 23b5e4abf..849c4e6b1 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -284,4 +284,5 @@ Carregada por: %1$s Compartilhar o aplicativo Não foram especificadas coordenadas durante a seleção da imagem + Erro ao buscar lugares próximos. diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 3da1296b7..e59582fa0 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -283,4 +283,5 @@ Carregada por: %1$s Partilhar aplicação Não foram especificadas coordenadas durante a seleção da imagem + Erro ao localizar locais próximos. diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index 37c2978bf..d84ce08ab 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -99,6 +99,7 @@ Message explaining what kind of images not to submit. Message asking user if they understand what kinds of images to upload. Button text for confirming the user understands what kinds of images to upload.\n{{Identical|Yes}} + \'\'This message is empty, and it\'s probably invalid. See bug report: https://github.com/commons-app/apps-android-commons/issues/1333 .\'\' Label for categories list in media detail panel.\n{{Identical|Category}} Placeholder for categories list in media detail panel, while loading from network.\n{{Identical|Loading}} Placeholder for categories list in media detail panel, if no categories found.\n{{Identical|None selected}} diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 95548b662..dadd40917 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -271,4 +271,13 @@ İlerle Vazgeç Tekrar Deneyin + Anladım! + Vikipedi maddelerine eklemek için fotoğrafa ihtiyaç duyan size yakın yerler + Bu tuşa dokunmak bu yerlerin bir listesini getirir + Galerinizden veya kameranızla herhangi bir yer için resim yükleyebilirsiniz. + Resim bulunamadı! + Resimler yüklenirken hata oluştu. + Yükleyen: %1$s + Uygulamayı Paylaş + Koordinatlar görüntü seçimi sırasında belirlenmedi diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 80b595f5d..4581d45ce 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -280,4 +280,5 @@ 由:%1$s 上傳 分享應用程式 當選擇圖片時未指定座標 + 索取附近地點時出錯。 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 29a1ae898..2079eb925 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -278,4 +278,5 @@ 由%1$s上传 分享应用 图片选择时,坐标并未指定 + 检索附近地点时出错。 From f99363c06c8d9ea000a90421000c3760a9982892 Mon Sep 17 00:00:00 2001 From: Vivek Maskara Date: Tue, 15 May 2018 12:55:37 +0530 Subject: [PATCH 097/184] Fix security exception crash while accessing network location provider (#1498) * Fix security exception crash while accessing network location provider * Added java docs --- .../location/LocationServiceManager.java | 33 ++++++++++++---- .../nrw/commons/nearby/NearbyActivity.java | 39 +++++++++++++++++-- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java index 73ded852f..49c422633 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java @@ -1,6 +1,7 @@ package fr.free.nrw.commons.location; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; @@ -10,9 +11,10 @@ import android.location.LocationManager; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; -import android.util.Log; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import timber.log.Timber; @@ -29,6 +31,7 @@ public class LocationServiceManager implements LocationListener { private Location lastLocation; private final List locationListeners = new CopyOnWriteArrayList<>(); private boolean isLocationManagerRegistered = false; + private Set locationExplanationDisplayed = new HashSet<>(); /** * Constructs a new instance of LocationServiceManager. @@ -51,7 +54,6 @@ public class LocationServiceManager implements LocationListener { /** * Returns whether the location permission is granted. - * * @return true if the location permission is granted */ public boolean isLocationPermissionGranted() { @@ -73,10 +75,23 @@ public class LocationServiceManager implements LocationListener { LOCATION_REQUEST); } + /** + * The permission explanation dialog box is now displayed just once for a particular activity. We are subscribing + * to updates from multiple providers so its important to show the dialog just once. Otherwise it will be displayed + * once for every provider, which in our case currently is 2. + * @param activity + * @return + */ public boolean isPermissionExplanationRequired(Activity activity) { - return !activity.isFinishing() && - ActivityCompat.shouldShowRequestPermissionRationale(activity, - Manifest.permission.ACCESS_FINE_LOCATION); + if (activity.isFinishing()) { + return false; + } + boolean showRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION); + if (showRequestPermissionRationale && !locationExplanationDisplayed.contains(activity)) { + locationExplanationDisplayed.add(activity); + return true; + } + return false; } /** @@ -84,8 +99,9 @@ public class LocationServiceManager implements LocationListener { * (e.g. when Location permission just granted) * @return last known LatLng */ + @SuppressLint("MissingPermission") public LatLng getLKL() { - if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + if (isLocationPermissionGranted()) { Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (lastKL == null) { lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); @@ -107,9 +123,10 @@ public class LocationServiceManager implements LocationListener { * Registers a LocationManager to listen for current location. */ public void registerLocationManager() { - if (!isLocationManagerRegistered) + if (!isLocationManagerRegistered) { isLocationManagerRegistered = requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER) && requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); + } } /** @@ -142,7 +159,7 @@ public class LocationServiceManager implements LocationListener { * @return LOCATION_SIGNIFICANTLY_CHANGED if location changed significantly * LOCATION_SLIGHTLY_CHANGED if location changed slightly */ - protected LocationChangeType isBetterLocation(Location location, Location currentBestLocation) { + private LocationChangeType isBetterLocation(Location location, Location currentBestLocation) { if (currentBestLocation == null) { // A new location is always better than no location diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 04886fda4..35e15b0d9 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -322,7 +322,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp protected void onStart() { super.onStart(); locationManager.addLocationListener(this); - locationManager.registerLocationManager(); + registerLocationUpdates(); } @Override @@ -400,7 +400,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp return; } - locationManager.registerLocationManager(); + registerLocationUpdates(); LatLng lastLocation = locationManager.getLastLocation(); if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed @@ -450,6 +450,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp } } + /** + * This method first checks if the location permissions has been granted and then register the location manager for updates. + */ + private void registerLocationUpdates() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (locationManager.isLocationPermissionGranted()) { + locationManager.registerLocationManager(); + } else { + // Should we show an explanation? + if (locationManager.isPermissionExplanationRequired(this)) { + new AlertDialog.Builder(this) + .setMessage(getString(R.string.location_permission_rationale_nearby)) + .setPositiveButton("OK", (dialog, which) -> { + requestLocationPermissions(); + dialog.dismiss(); + }) + .setNegativeButton("Cancel", (dialog, id) -> { + showLocationPermissionDeniedErrorDialog(); + dialog.cancel(); + }) + .create() + .show(); + + } else { + // No explanation needed, we can request the permission. + requestLocationPermissions(); + } + } + } else { + locationManager.registerLocationManager(); + } + } + private void populatePlaces(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) { List placeList = nearbyPlacesInfo.placeList; LatLng[] boundaryCoordinates = nearbyPlacesInfo.boundaryCoordinates; @@ -530,7 +563,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp locationManager.removeLocationListener(this); } else { lockNearbyView = false; - locationManager.registerLocationManager(); + registerLocationUpdates(); locationManager.addLocationListener(this); } } From 677f85a09703da359c33bd9189f339b1e5aed147 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 17 May 2018 08:24:27 +0200 Subject: [PATCH 098/184] Localisation updates from https://translatewiki.net. --- app/src/main/res/values-ast/strings.xml | 14 ++++++++++++++ app/src/main/res/values-diq/strings.xml | 8 ++++++-- app/src/main/res/values-hu/strings.xml | 12 ++++++++++-- app/src/main/res/values-is/strings.xml | 10 ++++++++++ app/src/main/res/values-ru/strings.xml | 19 ++++++++----------- app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 7 +++++++ 8 files changed, 57 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 532a4897e..947bc441a 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -84,6 +84,7 @@ Categoríes Configuración Date d\'alta + Imáxenes destacaes Tocante a La app de Wikimedia Commons ye software de códigu abiertu, creáu y calteníu por becaos y voluntarios de la comunidá de Wikimedia. La Fundación Wikimedia nun participa na creación, desendolcu nin caltenimientu de la app. Crea una nueva <a href=\"https://github.com/commons-app/apps-android-commons/issues\">incidencia en GitHub</a> pa informar de problemes y suxerencies. @@ -169,6 +170,8 @@ Títulu del mediu Descripción Equí va la descripción del mediu. Esto pué ser llargo enforma, y necesitará espardese per delles llinies. Sicasí, esperamos que se vea bien. + Autor + El nome d\'usuariu del autor de la imaxe destacada va equí. Data d\'unviu Llicencia Coordenaes @@ -211,6 +214,7 @@ Salir Tutorial Avisos + Destacada Los sitios cercanos nun pueden amosase ensin los permisos d\'allugamientu nun s\'atoparon descripciones Páxina del ficheru en Commons @@ -259,4 +263,14 @@ Siguir Encaboxar Retentar + Entendílo + Estos son sitios cercanos a ti que precisen imaxes para ilustrar los sos artículos de Wikipedia + Tocando esti botón amuésase la llista d\'esos llugares + Puedes xubir una imaxe pa cualquier sitiu dende la galería o la cámara + Nun s\'alcontró nenguna imaxe + Asocedió un error al cargar les imáxenes. + Xubida por: %1$s + Compartir app + Nun s\'especificaron les coordenaes al escoyer la imaxe + Error al llograr los llugares cercanos. diff --git a/app/src/main/res/values-diq/strings.xml b/app/src/main/res/values-diq/strings.xml index 1f1d69ea3..53bd88bac 100644 --- a/app/src/main/res/values-diq/strings.xml +++ b/app/src/main/res/values-diq/strings.xml @@ -13,6 +13,7 @@ Bıngeh Lokasyon Commons + Eyari Namey karberi Parola @@ -84,7 +85,8 @@ Qeyd be Heq te cı Qandê yew <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub-cıkewtış</a>ê neweyi rê rapor û teklifan bıaferne. - <a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Politikay nımıtışi</a> + <u>Politikaya nımıtışi</u> + <u>İştırakkerdoği</u> Heq te cı Peyd rışten bırış (E-posta ra) E-posta eyar nêbi @@ -92,7 +94,7 @@ Anciya bıcerrebne Bıtexelne Ron - Lisans + Lisanso hesebiyaye Attribution-ShareAlike 3.0 Attribution 3.0 CC0 @@ -127,6 +129,8 @@ E Sername + Şınasnayış + Nuştekar Lisans Koordinati Korbıze diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 81e655b95..d9580dca1 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -162,8 +162,8 @@ Nincs leírás Ismeretlen licenc Frissítés - Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. - Szükséges engedély: Külső tárhely írása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely olvasása. Az alkalmazás nem működik enélkül. + Szükséges engedély: Külső tárhely írása. Az alkalmazás nem tudja használni a kamerát enélkül. Lehetséges engedély: Jelenlegi hely megszerzése, a kategóriajavaslatok lehetőségéért. OK Közeli helyek @@ -242,6 +242,7 @@ A hely nem változott. A hely nem érhető el. Közeli helyek listájának megtekintéséhez engedély szükséges + SZÓCIKK OLVASÁSA Üdvözlünk a Wikimedia Commonson, %1$s! Örülünk, hogy itt vagy. %1$s üzenetet hagyott a vitalapodon Köszönjük a szerkesztésedet! @@ -258,5 +259,12 @@ Folytatás Mégse Újra + Ezek a helyek vannak a közeledben, amikről van Wikipédia szócikk és nincs bennük kép. + A gombra koppintva bejön egy lista, ami ezeket a helyeket mutatja. + Bármelyik helyhez feltölthetsz képet a galériádból vagy készíthetsz újat a kamerával. + Nem található kép! + Képbetöltés közben hiba történt Alkalmazás megosztása + A koordináták nem lettek megadva a kép kiválasztásakor. + Hiba a közeli helyek elérésekor. diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index ba5bdfe42..f1b020965 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -263,4 +263,14 @@ Halda áfram Hætta við Reyna aftur + Náði því! + Þetta eru þeir staðir í næsta nágrenni við þig sem vantar myndir til að skýra með Wikipedia-greinar + Ef ýtt er á þennan hnapp birtist listi yfir þessa staði + Þú getur sent inn mynd úr myndasafninu þínu eða myndavélinni + Engir myndir fundust! + Villa kom upp við að hlaða inn myndum. + Sent inn af: %1$s + Deila forriti + Hnit voru ekki tilgreind við val myndar + Villa við að sækja nálæga staði. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce71af94b..0d5a0ee3e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -46,11 +46,7 @@ Завершение загрузки %1$s Загрузка %1$s не удалась Нажмите для просмотра - - %1$d файл загружается - %1$d файла загружается - %1$d файлов загружается - + %1$d {{PLURAL:%1$d|one=файл загружается|few=файла загружается|файлов загружается}} Мои недавние загрузки В очереди Ошибка загрузки. @@ -115,7 +111,7 @@ Почтовый клиент не установлен Недавно использованные категории Ожидание первой синхронизации… - Вы ещё не загрузили ни одной фотографии. + Вы ещё не загрузили ни одного изображения. Повторить Отмена Это изображение будет лицензировано под %1$s @@ -123,7 +119,7 @@ Скачать Лицензия по умолчанию Использовать предыдущие название/описание - Автоматически получить текущее местоположение + Анализ местоположения Получить текущее местоположение, чтобы были предложены категории, если изображение не содержит геотегов Ночной режим Использовать тёмную тему @@ -148,7 +144,7 @@ CC BY 4.0 CC Zero Викисклад содержит бо́льшую часть изображений, которые используются в Википедии. - Ваши изображения помогают образованию людей во всём мире! + Ваши изображения могут помочь образованию людей во всём мире! Пожалуйста, загрузите фотографии, которые были сняты или созданы исключительно вами: Природные объекты (например, цветы, животные, горы)\n• Полезные предметы (например, велосипеды, вокзалы)\n• Известные люди (например, ваш мэр, спортсмены-олимпийцы, которых вы встретили) Природные объекты (например, цветы, животные, горы) @@ -166,7 +162,7 @@ Категории: Sydney Opera House from the west, Sydney Opera House remote views Загрузите свои изображения. Помогите Википедии оживить статьи! Изображения в Википедии хранятся на Викискладе. - Ваши изображения помогают образованию людей во всём мире. + Ваши изображения могут помочь образованию людей во всём мире. Избегайте материалов, защищённых авторским правом, например, найденных в Интернете, изображений плакатов, книжных обложек и т.п. Вам это понятно? Да! @@ -211,7 +207,7 @@ Facebook-страница Commons Исходные коды Commons на гитхабе Фоновое изображение - Ошибка медиаизображения + Ошибка медиафайла Изображение не найдено Загрузить изображение Гора Зао @@ -246,7 +242,7 @@ Пожалуйста, подробно опишите загружаемый файл: где он был снят? что на нём изображено? каков его контекст? Пожалуйста опишите изображённых персон или объекты. Добавьте информацию, о которой нельзя легко догадаться, например, время суток, когда снимался файл. Если снято что-то необычное, постарайтесь пояснить, что именно в этом необычного. Это изображение слишком тёмное. Вы уверены, что хотите его загрузить? Викисклад подходит только для фотографий, имеющих энциклопедическую ценность. Это изображение размыто. Вы уверены, что хотите его загрузить? Викисклад подходит только для фотографий, имеющих энциклопедическую ценность. - Дать разрешение + Разрешить Использовать внешнее хранилище Сохранять изображения, сделанные с помощью встроенной камеры на устройстве Войдите в свою учётную запись @@ -294,4 +290,5 @@ Загружено участником %1$s Поделиться приложением Во время выбора изображения не были указаны координаты + Ошибка получения мест поблизости diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 17a324a97..1d2fc868e 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -280,4 +280,5 @@ Uppladdad av: %1$s Dela app Koordinater specificerades inte vid bildvalet + Fel uppstod när platser i närheten hämtades. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dadd40917..c9dd60b41 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -280,4 +280,5 @@ Yükleyen: %1$s Uygulamayı Paylaş Koordinatlar görüntü seçimi sırasında belirlenmedi + Yakındaki yerler alınırken hata oluştu. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a4ed20320..1aba51e02 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -279,4 +279,11 @@ Виконується Скасувати Повторити + Зрозуміло + Натискання цієї кнопки згенерує список таких місць + Зображень не знайдено! + Сталася помилка при завантаженні зображень. + Завантажено: %1$s + Поділитися програмою + Помилка отримання місць поблизу. From 1520fc01f7b36b55a4f18275c00c9ddb9fc7af1f Mon Sep 17 00:00:00 2001 From: albendz <12453997+albendz@users.noreply.github.com> Date: Sat, 19 May 2018 09:15:43 -0700 Subject: [PATCH 099/184] Issue #1408: Try to get the localized version of the wikipedia article (#1445) * Try to get the localized version of the wikipedia article before defaulting to the English version. Tested with Spanish on physical Android device. Other notes: Difficulties building with gradle due to dexcount plugin: https://github.com/KeepSafe/dexcount-gradle-plugin/issues/234. In testing, disabled the plugin. * Update article fetch to not include unnecessary SERVICE line --- app/src/main/resources/queries/nearby_query.rq | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/resources/queries/nearby_query.rq b/app/src/main/resources/queries/nearby_query.rq index 0453005e8..b11f0985a 100644 --- a/app/src/main/resources/queries/nearby_query.rq +++ b/app/src/main/resources/queries/nearby_query.rq @@ -39,6 +39,11 @@ SELECT # Get emoji OPTIONAL { ?classId wdt:P487 ?emoji0. } OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. } + + OPTIONAL { + ?wikipediaArticle schema:about ?item ; + schema:isPartOf . + } OPTIONAL { ?wikipediaArticle schema:about ?item ; schema:isPartOf . From 01cb9ccd704f288a7d6f9ab0bcf3adc4fb1b097a Mon Sep 17 00:00:00 2001 From: Elliott Eggleston Date: Sat, 19 May 2018 15:00:06 -0500 Subject: [PATCH 100/184] Wmhack2018 (#1536) * Add new activity to manifest * Create review activity layout base * Add a new menu item to drawer for peer review * Add a top menu with randomizer icon to review activity * Add strings for review button * Add activity to ActivityBuilderModule for injection * Add a new drawer item to start review acitivty * Create base of the Review Activity * Add fragment pager * Add new fragment for injection * Create a fragment pager layout * Wikimedia hackathon 2018 (#1533) * First draft of fn to get random recent image * Use log entries for requests to beta, try to connect refresh button FIXME: runs http request on main thread, breaks * Tweak button connection * Add ReviewController class * Fix fragments * Wmhack2018 (#1534) * tiny fixes * Load pictures into activities * Re-use same class for all review fragments (#1537) And try to add pager indicator * [WIP] category check * [WIP] add on-click actions to ReviewActivity * [WIP] add SendThankTask * Make it beautiful * Use standalone category extraction code in MediaDataExtractor * Add categories to category review page --- app/src/main/AndroidManifest.xml | 4 + .../free/nrw/commons/MediaDataExtractor.java | 18 +- .../free/nrw/commons/delete/DeleteTask.java | 44 ++--- .../nrw/commons/di/ActivityBuilderModule.java | 4 + .../di/CommonsApplicationComponent.java | 8 +- .../nrw/commons/di/FragmentBuilderModule.java | 4 + .../commons/media/MediaDetailFragment.java | 6 + .../media/RecentChangesImageUtils.java | 32 ++++ .../mwapi/ApacheHttpClientMediaWikiApi.java | 87 ++++++++- .../free/nrw/commons/mwapi/MediaWikiApi.java | 7 + .../nrw/commons/review/CheckCategoryTask.java | 130 +++++++++++++ .../nrw/commons/review/ReviewActivity.java | 173 ++++++++++++++++++ .../nrw/commons/review/ReviewController.java | 52 ++++++ .../commons/review/ReviewImageFragment.java | 92 ++++++++++ .../commons/review/ReviewPagerAdapter.java | 51 ++++++ .../nrw/commons/review/SendThankTask.java | 140 ++++++++++++++ .../commons/theme/NavigationBaseActivity.java | 6 + .../commons/utils/MediaDataExtractorUtil.java | 28 +++ .../main/res/drawable/ic_check_black_24dp.xml | 9 + .../res/drawable/ic_refresh_black_24dp.xml | 9 + .../res/drawable/tab_indicator_default.xml | 12 ++ .../res/drawable/tab_indicator_selected.xml | 8 + app/src/main/res/drawable/tab_selector.xml | 8 + app/src/main/res/layout/activity_review.xml | 65 +++++++ .../main/res/layout/fragment_review_image.xml | 89 +++++++++ app/src/main/res/menu/drawer.xml | 5 + .../main/res/menu/review_randomizer_menu.xml | 10 + app/src/main/res/values/strings.xml | 30 +++ 28 files changed, 1086 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/media/RecentChangesImageUtils.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/CheckCategoryTask.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/ReviewController.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/ReviewImageFragment.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/ReviewPagerAdapter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/MediaDataExtractorUtil.java create mode 100644 app/src/main/res/drawable/ic_check_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_refresh_black_24dp.xml create mode 100644 app/src/main/res/drawable/tab_indicator_default.xml create mode 100644 app/src/main/res/drawable/tab_indicator_selected.xml create mode 100644 app/src/main/res/drawable/tab_selector.xml create mode 100644 app/src/main/res/layout/activity_review.xml create mode 100644 app/src/main/res/layout/fragment_review_image.xml create mode 100644 app/src/main/res/menu/review_randomizer_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 17f6770d2..a4c944a2d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -96,6 +96,10 @@ android:label="@string/title_activity_featured_images" android:parentActivityName=".contributions.ContributionsActivity" /> + + { notificationBuilder = new NotificationCompat.Builder(context); Toast toast = new Toast(context); toast.setGravity(Gravity.CENTER,0,0); - toast = Toast.makeText(context,"Trying to nominate "+media.getDisplayTitle()+ " for deletion",Toast.LENGTH_SHORT); + toast = Toast.makeText(context,"Trying to nominate "+media.getDisplayTitle()+ " for deletion", Toast.LENGTH_SHORT); toast.show(); } @@ -64,7 +64,7 @@ public class DeleteTask extends AsyncTask { String editToken; String authCookie; - String summary = "Nominating " + media.getFilename() +" for deletion."; + String summary = context.getString(R.string.nominating_file_for_deletion, media.getFilename()); authCookie = sessionManager.getAuthCookie(); mwApi.setAuthCookie(authCookie); @@ -97,19 +97,19 @@ public class DeleteTask extends AsyncTask { publishProgress(1); mwApi.prependEdit(editToken,fileDeleteString+"\n", - media.getFilename(),summary); + media.getFilename(), summary); publishProgress(2); mwApi.edit(editToken,subpageString+"\n", - "Commons:Deletion_requests/"+media.getFilename(),summary); + "Commons:Deletion_requests/"+media.getFilename(), summary); publishProgress(3); mwApi.appendEdit(editToken,logPageString+"\n", - "Commons:Deletion_requests/"+date,summary); + "Commons:Deletion_requests/"+date, summary); publishProgress(4); mwApi.appendEdit(editToken,userPageString+"\n", - "User_Talk:"+sessionManager.getCurrentAccount().name,summary); + "User_Talk:"+sessionManager.getCurrentAccount().name, summary); publishProgress(5); } catch (Exception e) { @@ -123,29 +123,21 @@ public class DeleteTask extends AsyncTask { protected void onProgressUpdate (Integer... values){ super.onProgressUpdate(values); + int[] messages = new int[]{ + R.string.getting_edit_token, + R.string.nominate_for_deletion_edit_file_page, + R.string.nominate_for_deletion_create_deletion_request, + R.string.nominate_for_deletion_edit_deletion_request_log, + R.string.nominate_for_deletion_notify_user, + R.string.nominate_for_deletion_done + }; + String message = ""; - switch (values[0]){ - case 0: - message = "Getting token"; - break; - case 1: - message = "Adding delete message to file"; - break; - case 2: - message = "Creating Delete requests sub-page"; - break; - case 3: - message = "Adding file to Delete requests log"; - break; - case 4: - message = "Notifying User on Talk page"; - break; - case 5: - message = "Done"; - break; + if (0 < values[0] && values[0] < messages.length) { + message = context.getString(messages[values[0]]); } - notificationBuilder.setContentTitle("Nominating "+media.getDisplayTitle()+" for deletion") + notificationBuilder.setContentTitle(context.getString(R.string.nominating_file_for_deletion, media.getFilename())) .setStyle(new NotificationCompat.BigTextStyle() .bigText(message)) .setSmallIcon(R.drawable.ic_launcher) diff --git a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java index 51aa85903..e062dbcc9 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java +++ b/app/src/main/java/fr/free/nrw/commons/di/ActivityBuilderModule.java @@ -10,6 +10,7 @@ import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; +import fr.free.nrw.commons.review.ReviewActivity; import fr.free.nrw.commons.settings.SettingsActivity; import fr.free.nrw.commons.upload.MultipleShareActivity; import fr.free.nrw.commons.upload.ShareActivity; @@ -50,4 +51,7 @@ public abstract class ActivityBuilderModule { @ContributesAndroidInjector abstract CategoryImagesActivity bindFeaturedImagesActivity(); + + @ContributesAndroidInjector + abstract ReviewActivity bindReviewActivity(); } diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index 91f6d4ccb..99ad9a346 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -9,11 +9,11 @@ import dagger.android.support.AndroidSupportInjectionModule; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.contributions.Contribution; -import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.contributions.ContributionsSyncAdapter; import fr.free.nrw.commons.delete.DeleteTask; import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; +import fr.free.nrw.commons.review.CheckCategoryTask; +import fr.free.nrw.commons.review.SendThankTask; import fr.free.nrw.commons.settings.SettingsFragment; import fr.free.nrw.commons.nearby.PlaceRenderer; @@ -40,6 +40,10 @@ public interface CommonsApplicationComponent extends AndroidInjector getNotifications() { @@ -616,11 +653,59 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { } private Date parseMWDate(String mwDate) { - SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); // Assuming MW always gives me UTC try { return isoFormat.parse(mwDate); } catch (ParseException e) { throw new RuntimeException(e); } } + + private String formatMWDate(Date date) { + return isoFormat.format(date); + } + + public Media getRecentRandomImage() throws IOException { + Media media = null; + int tries = 0; + Random r = new Random(); + + while (media == null && tries < MAX_RANDOM_TRIES) { + Date now = new Date(); + Date startDate = new Date(now.getTime() - r.nextInt(RANDOM_SECONDS) * 1000L); + ApiResult apiResult = null; + try { + MWApi.RequestBuilder requestBuilder = api.action("query") + .param("list", "recentchanges") + .param("rcstart", formatMWDate(startDate)) + .param("rcnamespace", FILE_NAMESPACE) + .param("rcprop", "title|ids") + .param("rctype", "new|log") + .param("rctoponly", "1"); + + apiResult = requestBuilder.get(); + } catch (IOException e) { + Timber.e("Failed to obtain recent random", e); + } + if (apiResult != null) { + ApiResult recentChangesNode = apiResult.getNode("/api/query/recentchanges"); + if (recentChangesNode != null + && recentChangesNode.getDocument() != null + && recentChangesNode.getDocument().getChildNodes() != null + && recentChangesNode.getDocument().getChildNodes().getLength() > 0) { + NodeList childNodes = recentChangesNode.getDocument().getChildNodes(); + String imageTitle = RecentChangesImageUtils.findImageInRecentChanges(childNodes); + if (imageTitle != null) { + boolean deletionStatus = pageExists("Commons:Deletion_requests/" + imageTitle); + if (!deletionStatus) { + // strip File: prefix + imageTitle = imageTitle.replace("File:", ""); + media = new Media(imageTitle); + } + } + } + } + tries++; + } + return media; + } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index c0bd2fd87..4046530d1 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -75,7 +75,14 @@ public interface MediaWikiApi { @NonNull Single getUploadCount(String userName); + boolean thank(String editToken, String revision) throws IOException; + + String firstRevisionOfFile(String filename) throws IOException; + interface ProgressListener { void onProgress(long transferred, long total); } + + @Nullable + Media getRecentRandomImage() throws IOException; } diff --git a/app/src/main/java/fr/free/nrw/commons/review/CheckCategoryTask.java b/app/src/main/java/fr/free/nrw/commons/review/CheckCategoryTask.java new file mode 100644 index 000000000..d2086e5bd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/CheckCategoryTask.java @@ -0,0 +1,130 @@ +package fr.free.nrw.commons.review; + +import android.app.NotificationManager; +import android.content.Context; +import android.os.AsyncTask; +import android.support.v4.app.NotificationCompat; +import android.view.Gravity; +import android.widget.Toast; + +import javax.inject.Inject; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.auth.SessionManager; +import fr.free.nrw.commons.di.ApplicationlessInjection; +import fr.free.nrw.commons.mwapi.MediaWikiApi; +import timber.log.Timber; + +import static android.support.v4.app.NotificationCompat.DEFAULT_ALL; +import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH; + +// Example code: +// CheckCategoryTask deleteTask = new CheckCategoryTask(getActivity(), media); + +public class CheckCategoryTask extends AsyncTask { + + @Inject + MediaWikiApi mwApi; + @Inject + SessionManager sessionManager; + + public static final int NOTIFICATION_CHECK_CATEGORY = 0x101; + + private NotificationManager notificationManager; + private NotificationCompat.Builder notificationBuilder; + private Context context; + private Media media; + + public CheckCategoryTask(Context context, Media media){ + this.context = context; + this.media = media; + } + + @Override + protected void onPreExecute(){ + ApplicationlessInjection + .getInstance(context.getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); + + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationBuilder = new NotificationCompat.Builder(context); + Toast toast = new Toast(context); + toast.setGravity(Gravity.CENTER,0,0); + toast = Toast.makeText(context, context.getString(R.string.check_category_toast, media.getDisplayTitle()), Toast.LENGTH_SHORT); + toast.show(); + } + + @Override + protected Boolean doInBackground(Void ...voids) { + publishProgress(0); + + String editToken; + String authCookie; + String summary = context.getString(R.string.check_category_edit_summary); + + authCookie = sessionManager.getAuthCookie(); + mwApi.setAuthCookie(authCookie); + + try { + editToken = mwApi.getEditToken(); + if (editToken.equals("+\\")) { + return false; + } + publishProgress(1); + + mwApi.appendEdit(editToken, "\n{{subst:chc}}\n", media.getFilename(), summary); + publishProgress(2); + } + catch (Exception e) { + Timber.d(e.getMessage()); + return false; + } + return true; + } + + @Override + protected void onProgressUpdate (Integer... values){ + super.onProgressUpdate(values); + + int[] messages = new int[]{R.string.getting_edit_token, R.string.check_category_adding_template}; + String message = ""; + if (0 < values[0] && values[0] < messages.length) { + message = context.getString(messages[values[0]]); + } + + notificationBuilder.setContentTitle(context.getString(R.string.check_category_notification_title, media.getDisplayTitle())) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(message)) + .setSmallIcon(R.drawable.ic_launcher) + .setProgress(messages.length, values[0], false) + .setOngoing(true); + notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build()); + } + + @Override + protected void onPostExecute(Boolean result) { + String message = ""; + String title = ""; + + if (result){ + title = context.getString(R.string.check_category_success_title); + message = context.getString(R.string.check_category_success_message, media.getDisplayTitle()); + } + else { + title = context.getString(R.string.check_category_failure_title); + message = context.getString(R.string.check_category_failure_message, media.getDisplayTitle()); + } + + notificationBuilder.setDefaults(DEFAULT_ALL) + .setContentTitle(title) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(message)) + .setSmallIcon(R.drawable.ic_launcher) + .setProgress(0,0,false) + .setOngoing(false) + .setPriority(PRIORITY_HIGH); + notificationManager.notify(NOTIFICATION_CHECK_CATEGORY, notificationBuilder.build()); + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java b/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java new file mode 100644 index 000000000..4d51b97f3 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewActivity.java @@ -0,0 +1,173 @@ +package fr.free.nrw.commons.review; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import android.os.Handler; +import android.support.design.widget.NavigationView; +import android.support.v4.view.ViewPager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.widget.Toolbar; + +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; + +import com.viewpagerindicator.CirclePageIndicator; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import butterknife.BindView; +import butterknife.ButterKnife; +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.auth.AuthenticatedActivity; +import fr.free.nrw.commons.mwapi.MediaResult; +import fr.free.nrw.commons.mwapi.MediaWikiApi; +import fr.free.nrw.commons.utils.MediaDataExtractorUtil; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by root on 18.05.2018. + */ + +public class ReviewActivity extends AuthenticatedActivity { + + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.navigation_view) + NavigationView navigationView; + @BindView(R.id.drawer_layout) + DrawerLayout drawerLayout; + + @BindView(R.id.reviewPager) + ViewPager pager; + + @Inject MediaWikiApi mwApi; + + private ReviewPagerAdapter reviewPagerAdapter; + + //private ReviewCallback reviewCallback; + private ReviewController reviewController; + + @BindView(R.id.reviewPagerIndicator) + public CirclePageIndicator pagerIndicator; + + @Override + protected void onAuthCookieAcquired(String authCookie) { + + } + + @Override + protected void onAuthFailure() { + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_review); + ButterKnife.bind(this); + initDrawer(); + + reviewController = new ReviewController(); + + + reviewPagerAdapter = new ReviewPagerAdapter(getSupportFragmentManager()); + pager.setAdapter(reviewPagerAdapter); + reviewPagerAdapter.getItem(0); + pagerIndicator.setViewPager(pager); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.review_randomizer_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.action_review_randomizer) { + Observable.fromCallable(() -> { + Media result = null; + try { + result = mwApi.getRecentRandomImage(); + + //String thumBaseUrl = Utils.makeThumbBaseUrl(result.getFilename()); + //reviewPagerAdapter.currentThumbBasedUrl = thumBaseUrl; + + //Log.d("review", result.getWikiSource()); + + } catch (IOException e) { + Log.d("review", e.toString()); + } + return result; + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::updateImage); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void updateImage(Media result) { + reviewController.onImageRefreshed(result.getFilename()); //file name is updated + reviewPagerAdapter.updateFilename(); + pager.setCurrentItem(0); + Observable.fromCallable(() -> { + MediaResult media = mwApi.fetchMediaByFilename("File:" + result.getFilename()); + return MediaDataExtractorUtil.extractCategories(media.getWikiSource()); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::updateCategories); + } + + private void updateCategories(ArrayList categories) { + reviewController.onCategoriesRefreshed(categories); + reviewPagerAdapter.updateCategories(); + } + + /** + * References ReviewPagerAdapter to null before the activity is destroyed + */ + @Override + public void onDestroy() { + //adapter.setCallback(null); + super.onDestroy(); + } + + /** + * Consumers should be simply using this method to use this activity. + * @param context + * @param title Page title + */ + public static void startYourself(Context context, String title) { + Intent reviewActivity = new Intent(context, ReviewActivity.class); + context.startActivity(reviewActivity); + } + + interface ReviewCallback { + void onImageRefreshed(String itemTitle); + void onQuestionChanged(); + void onSurveyFinished(); + void onImproperImageReported(); + void onLicenceViolationReported(); + void onWrongCategoryReported(); + void onThankSent(); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewController.java b/app/src/main/java/fr/free/nrw/commons/review/ReviewController.java new file mode 100644 index 000000000..2bde33ecd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewController.java @@ -0,0 +1,52 @@ +package fr.free.nrw.commons.review; + +import java.util.ArrayList; + +/** + * Created by root on 19.05.2018. + */ + +public class ReviewController implements ReviewActivity.ReviewCallback { + public static String fileName; + protected static ArrayList categories; + + @Override + public void onImageRefreshed(String fileName) { + ReviewController.fileName = fileName; + ReviewController.categories = new ArrayList<>(); + } + + public void onCategoriesRefreshed(ArrayList categories) { + ReviewController.categories = categories; + } + + @Override + public void onQuestionChanged() { + + } + + @Override + public void onSurveyFinished() { + + } + + @Override + public void onImproperImageReported() { + + } + + @Override + public void onLicenceViolationReported() { + + } + + @Override + public void onWrongCategoryReported() { + + } + + @Override + public void onThankSent() { + + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewImageFragment.java b/app/src/main/java/fr/free/nrw/commons/review/ReviewImageFragment.java new file mode 100644 index 000000000..bab8df6df --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewImageFragment.java @@ -0,0 +1,92 @@ +package fr.free.nrw.commons.review; + +import android.app.AlertDialog; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.facebook.drawee.view.SimpleDraweeView; + +import java.util.ArrayList; + +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; +import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; + +/** + * Created by root on 19.05.2018. + */ + +public class ReviewImageFragment extends CommonsDaggerSupportFragment { + + public static final int SPAM = 0; + public static final int COPYRIGHT = 1; + public static final int CATEGORY = 2; + + private int position; + private String fileName; + private String catString; + private View catsView; + private SimpleDraweeView simpleDraweeView; + + public void update(int position, String fileName) { + this.position = position; + this.fileName = fileName; + + if (simpleDraweeView!=null) { + simpleDraweeView.setImageURI(Utils.makeThumbBaseUrl(fileName)); + } + } + + public void updateCategories(Iterable categories) { + catString = TextUtils.join(", ", categories); + if (catsView != null) { + ((TextView) catsView).setText(catString); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + position = getArguments().getInt("position"); + View layoutView = inflater.inflate(R.layout.fragment_review_image, container, + false); + View textView = layoutView.findViewById(R.id.reviewQuestion); + catsView = layoutView.findViewById(R.id.reviewCategories); + String question; + switch(position) { + case COPYRIGHT: + question = getString(R.string.review_copyright); + break; + case CATEGORY: + question = getString(R.string.review_category); + catsView.setVisibility(View.VISIBLE); + break; + case SPAM: + question = getString(R.string.review_spam); + break; + default: + question = "How did we get here?"; + } + ((TextView) textView).setText(question); + simpleDraweeView = layoutView.findViewById(R.id.imageView); + + if (fileName != null) { + simpleDraweeView.setImageURI(Utils.makeThumbBaseUrl(fileName)); + } + if (catString != null) { + ((TextView) catsView).setText(catString); + } + return layoutView; + } + +} diff --git a/app/src/main/java/fr/free/nrw/commons/review/ReviewPagerAdapter.java b/app/src/main/java/fr/free/nrw/commons/review/ReviewPagerAdapter.java new file mode 100644 index 000000000..06d07c7c9 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/ReviewPagerAdapter.java @@ -0,0 +1,51 @@ +package fr.free.nrw.commons.review; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +/** + * Created by nes on 19.05.2018. + */ + +public class ReviewPagerAdapter extends FragmentStatePagerAdapter { + private int currentPosition; + ReviewImageFragment[] reviewImageFragments; + + + public ReviewPagerAdapter(FragmentManager fm) { + super(fm); + reviewImageFragments = new ReviewImageFragment[] { + new ReviewImageFragment(), + new ReviewImageFragment(), + new ReviewImageFragment() + }; + } + + @Override + public int getCount() { + return 3; + } + + public void updateFilename() { + for (int i = 0; i < getCount(); i++) { + ReviewImageFragment fragment = reviewImageFragments[i]; + fragment.update(i, ReviewController.fileName); + } + } + + public void updateCategories() { + ReviewImageFragment categoryFragment = reviewImageFragments[ReviewImageFragment.CATEGORY]; + categoryFragment.updateCategories(ReviewController.categories); + } + + @Override + public Fragment getItem(int position) { + Bundle bundle = new Bundle(); + bundle.putInt("position", position); + reviewImageFragments[position].setArguments(bundle); + return reviewImageFragments[position]; + } + +} diff --git a/app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java b/app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java new file mode 100644 index 000000000..0f723217f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/review/SendThankTask.java @@ -0,0 +1,140 @@ +package fr.free.nrw.commons.review; + +import android.app.NotificationManager; +import android.content.Context; +import android.os.AsyncTask; +import android.support.v4.app.NotificationCompat; +import android.view.Gravity; +import android.widget.Toast; + +import javax.inject.Inject; + +import fr.free.nrw.commons.Media; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.auth.SessionManager; +import fr.free.nrw.commons.di.ApplicationlessInjection; +import fr.free.nrw.commons.mwapi.MediaWikiApi; +import timber.log.Timber; + +import static android.support.v4.app.NotificationCompat.DEFAULT_ALL; +import static android.support.v4.app.NotificationCompat.PRIORITY_HIGH; + +// example code: +// +// media = new Media("File:Iru.png"); +// Observable.fromCallable(() -> mwApi.firstRevisionOfFile(media.getFilename())) +// .subscribeOn(Schedulers.io()) +// .observeOn(AndroidSchedulers.mainThread()) +// .subscribe(revision -> { +// SendThankTask task = new SendThankTask(getActivity(), media, revision); +// task.execute(); +// }); + +public class SendThankTask extends AsyncTask { + + @Inject + MediaWikiApi mwApi; + @Inject + SessionManager sessionManager; + + public static final int NOTIFICATION_SEND_THANK = 0x102; + + private NotificationManager notificationManager; + private NotificationCompat.Builder notificationBuilder; + private Context context; + private Media media; + private String revision; + + public SendThankTask(Context context, Media media, String revision){ + this.context = context; + this.media = media; + this.revision = revision; + } + + @Override + protected void onPreExecute(){ + ApplicationlessInjection + .getInstance(context.getApplicationContext()) + .getCommonsApplicationComponent() + .inject(this); + + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationBuilder = new NotificationCompat.Builder(context); + Toast toast = new Toast(context); + toast.setGravity(Gravity.CENTER,0,0); + toast = Toast.makeText(context, context.getString(R.string.send_thank_toast, media.getDisplayTitle()), Toast.LENGTH_SHORT); + toast.show(); + } + + @Override + protected Boolean doInBackground(Void ...voids) { + publishProgress(0); + + String editToken; + String authCookie; + + authCookie = sessionManager.getAuthCookie(); + mwApi.setAuthCookie(authCookie); + + try { + editToken = mwApi.getEditToken(); + if (editToken.equals("+\\")) { + return false; + } + publishProgress(1); + + mwApi.thank(editToken, revision); + + publishProgress(2); + } + catch (Exception e) { + Timber.d(e.getMessage()); + return false; + } + return true; + } + + @Override + protected void onProgressUpdate (Integer... values){ + super.onProgressUpdate(values); + + int[] messages = new int[]{R.string.getting_edit_token, R.string.send_thank_send}; + String message = ""; + if (0 < values[0] && values[0] < messages.length) { + message = context.getString(messages[values[0]]); + } + + notificationBuilder.setContentTitle(context.getString(R.string.send_thank_notification_title)) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(message)) + .setSmallIcon(R.drawable.ic_launcher) + .setProgress(messages.length, values[0], false) + .setOngoing(true); + notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build()); + } + + @Override + protected void onPostExecute(Boolean result) { + String message = ""; + String title = ""; + + if (result){ + title = context.getString(R.string.send_thank_success_title); + message = context.getString(R.string.send_thank_success_message, media.getDisplayTitle()); + } + else { + title = context.getString(R.string.send_thank_failure_title); + message = context.getString(R.string.send_thank_failure_message, media.getDisplayTitle()); + } + + notificationBuilder.setDefaults(DEFAULT_ALL) + .setContentTitle(title) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(message)) + .setSmallIcon(R.drawable.ic_launcher) + .setProgress(0,0,false) + .setOngoing(false) + .setPriority(PRIORITY_HIGH); + notificationManager.notify(NOTIFICATION_SEND_THANK, notificationBuilder.build()); + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java index 4a7322b57..8fc12d068 100644 --- a/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/theme/NavigationBaseActivity.java @@ -30,6 +30,7 @@ import fr.free.nrw.commons.contributions.ContributionsActivity; import fr.free.nrw.commons.category.CategoryImagesActivity; import fr.free.nrw.commons.nearby.NearbyActivity; import fr.free.nrw.commons.notification.NotificationActivity; +import fr.free.nrw.commons.review.ReviewActivity; import fr.free.nrw.commons.settings.SettingsActivity; import timber.log.Timber; @@ -160,6 +161,11 @@ public abstract class NavigationBaseActivity extends BaseActivity drawerLayout.closeDrawer(navigationView); CategoryImagesActivity.startYourself(this, getString(R.string.title_activity_featured_images), FEATURED_IMAGES_CATEGORY); return true; + + case R.id.action_review: + drawerLayout.closeDrawer(navigationView); + ReviewActivity.startYourself(this, getString(R.string.title_activity_review)); + return true; default: Timber.e("Unknown option [%s] selected from the navigation menu", itemId); return false; diff --git a/app/src/main/java/fr/free/nrw/commons/utils/MediaDataExtractorUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/MediaDataExtractorUtil.java new file mode 100644 index 000000000..63421a8e4 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/MediaDataExtractorUtil.java @@ -0,0 +1,28 @@ +package fr.free.nrw.commons.utils; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MediaDataExtractorUtil { + + /** + * We could fetch all category links from API, but we actually only want the ones + * directly in the page source so they're editable. In the future this may change. + * + * @param source wikitext source code + */ + public static ArrayList extractCategories(String source) { + ArrayList categories = new ArrayList<>(); + Pattern regex = Pattern.compile("\\[\\[\\s*Category\\s*:([^]]*)\\s*\\]\\]", Pattern.CASE_INSENSITIVE); + Matcher matcher = regex.matcher(source); + while (matcher.find()) { + String cat = matcher.group(1).trim(); + categories.add(cat); + } + + return categories; + } + + +} diff --git a/app/src/main/res/drawable/ic_check_black_24dp.xml b/app/src/main/res/drawable/ic_check_black_24dp.xml new file mode 100644 index 000000000..3c728c59f --- /dev/null +++ b/app/src/main/res/drawable/ic_check_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_refresh_black_24dp.xml b/app/src/main/res/drawable/ic_refresh_black_24dp.xml new file mode 100644 index 000000000..8229a9a64 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tab_indicator_default.xml b/app/src/main/res/drawable/tab_indicator_default.xml new file mode 100644 index 000000000..341f4d706 --- /dev/null +++ b/app/src/main/res/drawable/tab_indicator_default.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_indicator_selected.xml b/app/src/main/res/drawable/tab_indicator_selected.xml new file mode 100644 index 000000000..41c1bcf73 --- /dev/null +++ b/app/src/main/res/drawable/tab_indicator_selected.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tab_selector.xml b/app/src/main/res/drawable/tab_selector.xml new file mode 100644 index 000000000..001747c31 --- /dev/null +++ b/app/src/main/res/drawable/tab_selector.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_review.xml b/app/src/main/res/layout/activity_review.xml new file mode 100644 index 000000000..a0b813f55 --- /dev/null +++ b/app/src/main/res/layout/activity_review.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_review_image.xml b/app/src/main/res/layout/fragment_review_image.xml new file mode 100644 index 000000000..7abf88f01 --- /dev/null +++ b/app/src/main/res/layout/fragment_review_image.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + +