diff --git a/app/build.gradle b/app/build.gradle index 480916ee8..6f225dc2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,7 @@ 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.mapbox.mapboxsdk:mapbox-android-sdk:5.2.1@aar'){ + implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){ transitive=true } @@ -26,6 +26,7 @@ dependencies { 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" + implementation "com.android.support:customtabs:$SUPPORT_LIB_VERSION" implementation "com.android.support:cardview-v7:$SUPPORT_LIB_VERSION" @@ -48,7 +49,7 @@ dependencies { compile 'com.facebook.stetho:stetho:1.5.0' testCompile 'junit:junit:4.12' - testCompile 'org.robolectric:robolectric:3.4' + testCompile 'org.robolectric:robolectric:3.7.1' testCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.8.1' @@ -77,7 +78,7 @@ dependencies { androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" testImplementation 'junit:junit:4.12' - testImplementation 'org.robolectric:robolectric:3.4' + testImplementation 'org.robolectric:robolectric:3.7.1' testImplementation 'org.mockito:mockito-all:1.10.19' testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1' 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 a2f67a3bf..27816d762 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java @@ -3,6 +3,8 @@ package fr.free.nrw.commons; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.customtabs.CustomTabsIntent; +import android.support.v4.content.ContextCompat; import android.view.View; import android.widget.TextView; @@ -47,22 +49,29 @@ public class AboutActivity extends NavigationBaseActivity { intent.setPackage("com.facebook.katana"); startActivity(intent); } catch (Exception e) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.facebook.com/" + "1921335171459985"))); + Utils.handleWebUrl(this,Uri.parse("https://www.facebook.com/" + "1921335171459985")); } - } @OnClick(R.id.github_launch_icon) public void launchGithub(View view) { - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/commons-app/apps-android-commons\\")); - startActivity(browserIntent); + Utils.handleWebUrl(this,Uri.parse("https://commons-app.github.io/\\")); } @OnClick(R.id.website_launch_icon) public void launchWebsite(View view) { - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://commons-app.github.io/\\")); - startActivity(browserIntent); + Utils.handleWebUrl(this,Uri.parse("https://commons-app.github.io/\\")); } + + @OnClick(R.id.about_credits) + public void launchCredits(View view) { + Utils.handleWebUrl(this,Uri.parse("https://github.com/commons-app/apps-android-commons/blob/master/CREDITS/\\")); + } + + @OnClick(R.id.about_privacy_policy) + public void launchPrivacyPolicy(View view) { + Utils.handleWebUrl(this,Uri.parse("https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\\")); + } + + } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 817c39f24..9f91bff12 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -1,8 +1,12 @@ package fr.free.nrw.commons; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.customtabs.CustomTabsIntent; +import android.support.v4.content.ContextCompat; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; @@ -11,6 +15,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; +import java.net.URL; import java.net.URLEncoder; import java.util.Locale; import java.util.regex.Matcher; @@ -159,4 +164,15 @@ public class Utils { return stringBuilder.toString(); } + + public static void handleWebUrl(Context context,Uri url){ + CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); + builder.setToolbarColor(ContextCompat.getColor(context, R.color.primaryColor)); + builder.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.primaryDarkColor)); + builder.setExitAnimations(context, android.R.anim.slide_in_left, android.R.anim.slide_out_right); + CustomTabsIntent customTabsIntent = builder.build(); + customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + customTabsIntent.launchUrl(context, url); + } + } 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 3e90fbf5e..cbdff2e0b 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 @@ -4,6 +4,7 @@ import android.accounts.Account; import android.accounts.AccountAuthenticatorActivity; import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; +import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.content.SharedPreferences; @@ -17,10 +18,12 @@ 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; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; @@ -69,6 +72,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { @BindView(R.id.loginTwoFactor) EditText twoFactorEdit; @BindView(R.id.error_message_container) ViewGroup errorMessageContainer; @BindView(R.id.error_message) TextView errorMessage; + @BindView(R.id.login_credentials) TextView loginCredentials; @BindView(R.id.two_factor_container)TextInputLayout twoFactorContainer; ProgressDialog progressDialog; private AppCompatDelegate delegate; @@ -91,14 +95,39 @@ public class LoginActivity extends AccountAuthenticatorActivity { ButterKnife.bind(this); usernameEdit.addTextChangedListener(textWatcher); + usernameEdit.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + hideKeyboard(v); + } + }); + passwordEdit.addTextChangedListener(textWatcher); + passwordEdit.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + hideKeyboard(v); + } + }); + twoFactorEdit.addTextChangedListener(textWatcher); passwordEdit.setOnEditorActionListener(newLoginInputActionListener()); loginButton.setOnClickListener(view -> performLogin()); signupButton.setOnClickListener(view -> signUp()); + + if(BuildConfig.FLAVOR == "beta"){ + loginCredentials.setText(getString(R.string.login_credential)); + } else { + loginCredentials.setVisibility(View.GONE); + } } + + public void hideKeyboard(View view) { + InputMethodManager inputMethodManager =(InputMethodManager)this.getSystemService(Activity.INPUT_METHOD_SERVICE); + 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 7c2e910c4..fd3d02c31 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,17 +1,23 @@ package fr.free.nrw.commons.category; + +import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; 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; 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; @@ -37,6 +43,7 @@ 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; @@ -72,6 +79,7 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { private OnCategoriesSaveHandler onCategoriesSaveHandler; private HashMap> categoriesCache; private List selectedCategories = new ArrayList<>(); + private TitleTextWatcher textWatcher = new TitleTextWatcher(); private final CategoriesAdapterFactory adapterFactory = new CategoriesAdapterFactory(item -> { if (item.isSelected()) { @@ -102,6 +110,15 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { categoriesAdapter = adapterFactory.create(items); categoriesList.setAdapter(categoriesAdapter); + + categoriesFilter.addTextChangedListener(textWatcher); + + categoriesFilter.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + hideKeyboard(v); + } + }); + RxTextView.textChanges(categoriesFilter) .takeUntil(RxView.detaches(categoriesFilter)) .debounce(500, TimeUnit.MILLISECONDS) @@ -110,6 +127,18 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { return rootView; } + public void hideKeyboard(View view) { + InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + @Override + public void onDestroyView() { + categoriesFilter.removeTextChangedListener(textWatcher); + super.onDestroyView(); + } + + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); @@ -351,4 +380,21 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { .create() .show(); } + + private class TitleTextWatcher implements TextWatcher { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + } + + @Override + public void afterTextChanged(Editable editable) { + if (getActivity() != null) { + getActivity().invalidateOptionsMenu(); + } + } + } } 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 0e67afc2f..7aecee337 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,6 +10,7 @@ import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.view.Menu; import android.view.MenuInflater; @@ -60,7 +61,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp private NearbyActivityMode viewMode; private Disposable placesDisposable; private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed - + @BindView(R.id.swipe_container) SwipeRefreshLayout swipeLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -70,6 +71,13 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp bundle = new Bundle(); initDrawer(); initViewState(); + swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + lockNearbyView(false); + refreshView(true); + } + }); } private void initViewState() { @@ -309,7 +317,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp } else { setListFragment(); } - + swipeLayout.setRefreshing(false); hideProgressBar(); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyInfoDialog.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyInfoDialog.java index b383fd9b9..69fce546c 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyInfoDialog.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyInfoDialog.java @@ -3,7 +3,9 @@ package fr.free.nrw.commons.nearby; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.customtabs.CustomTabsIntent; import android.support.v4.app.FragmentActivity; +import android.support.v4.content.ContextCompat; import android.support.v7.widget.PopupMenu; import android.view.LayoutInflater; import android.view.MenuItem; @@ -17,6 +19,7 @@ import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import fr.free.nrw.commons.R; +import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.ui.widget.OverlayDialog; import fr.free.nrw.commons.utils.DialogUtil; @@ -141,8 +144,7 @@ public class NearbyInfoDialog extends OverlayDialog { } private void openWebView(Uri link) { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, link); - startActivity(browserIntent); + Utils.handleWebUrl(getContext(),link); } @OnClick(R.id.emptyLayout) 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 dc9d733f4..cdb9e97d3 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 @@ -5,11 +5,13 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.pedrogomez.renderers.RVRendererAdapter; +import java.util.Collections; import java.util.List; import javax.inject.Inject; @@ -45,8 +47,9 @@ public class NotificationActivity extends NavigationBaseActivity { } private void initListView() { - recyclerView = findViewById(R.id.listView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); + DividerItemDecoration itemDecor = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); + recyclerView.addItemDecoration(itemDecor); addNotifications(); } @@ -58,6 +61,7 @@ public class NotificationActivity extends NavigationBaseActivity { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(notificationList -> { + Collections.reverse(notificationList); Timber.d("Number of notifications is %d", notificationList.size()); setAdapter(notificationList); }, throwable -> Timber.e(throwable, "Error occurred while loading notifications")); 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 99c9f253b..fa0e43957 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 @@ -5,6 +5,7 @@ import android.accounts.AccountManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.support.annotation.NonNull; import android.support.design.widget.NavigationView; import android.support.v4.widget.DrawerLayout; @@ -119,8 +120,9 @@ public abstract class NavigationBaseActivity extends BaseActivity return true; case R.id.action_feedback: drawerLayout.closeDrawer(navigationView); - Intent feedbackIntent = new Intent(Intent.ACTION_SEND); + Intent feedbackIntent = new Intent(Intent.ACTION_SENDTO); feedbackIntent.setType("message/rfc822"); + feedbackIntent.setData(Uri.parse("mailto:")); feedbackIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{CommonsApplication.FEEDBACK_EMAIL}); feedbackIntent.putExtra(Intent.EXTRA_SUBJECT, 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 0b6e527e5..5b39b92f7 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 @@ -1,5 +1,6 @@ package fr.free.nrw.commons.upload; +import android.app.Activity; import android.content.Context; import android.graphics.Point; import android.net.Uri; @@ -10,6 +11,7 @@ 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; @@ -177,9 +179,21 @@ public class MultipleUploadListFragment extends Fragment { photosGrid.setColumnWidth(photoSize.x); baseTitle.addTextChangedListener(textWatcher); + + baseTitle.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + hideKeyboard(v); + } + }); + return view; } + public void hideKeyboard(View view) { + InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + @Override public void onDestroyView() { baseTitle.removeTextChangedListener(textWatcher); diff --git a/app/src/main/res/layout-land/activity_login.xml b/app/src/main/res/layout-land/activity_login.xml index 9ecaf9855..a87084f66 100644 --- a/app/src/main/res/layout-land/activity_login.xml +++ b/app/src/main/res/layout-land/activity_login.xml @@ -13,12 +13,12 @@ @@ -40,11 +40,26 @@ android:textColor="@android:color/white" android:textSize="@dimen/heading_text_size" /> + + @@ -56,6 +71,7 @@ android:layout_marginLeft="@dimen/standard_gap" android:layout_marginRight="@dimen/standard_gap" android:layout_marginStart="@dimen/standard_gap" + android:gravity="center" android:paddingBottom="@dimen/small_gap" android:paddingTop="@dimen/small_gap" android:textColor="@color/secondaryDarkColor" @@ -149,8 +165,8 @@