Merge from commons-app/master

This commit is contained in:
misaochan 2018-05-25 19:17:55 +10:00
commit 7cbc2a674c
31 changed files with 683 additions and 181 deletions

View file

@ -271,11 +271,11 @@ public class LoginActivity extends AccountAuthenticatorActivity {
showMessageAndCancelDialog(R.string.login_failed_network);
} else if (result.toLowerCase(Locale.getDefault()).contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) {
// Matches nosuchuser, nosuchusershort, noname
showMessageAndCancelDialog(R.string.login_failed_username);
showMessageAndCancelDialog(R.string.login_failed_wrong_credentials);
emptySensitiveEditFields();
} else if (result.toLowerCase(Locale.getDefault()).contains("wrongpassword".toLowerCase())) {
// Matches wrongpassword, wrongpasswordempty
showMessageAndCancelDialog(R.string.login_failed_password);
showMessageAndCancelDialog(R.string.login_failed_wrong_credentials);
emptySensitiveEditFields();
} else if (result.toLowerCase(Locale.getDefault()).contains("throttle".toLowerCase())) {
// Matches unknown throttle error codes

View file

@ -0,0 +1,36 @@
package fr.free.nrw.commons.glide;
import android.support.annotation.NonNull;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.resource.SimpleResource;
import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException;
import java.io.IOException;
import java.io.InputStream;
/**
* Decodes an SVG internal representation from an {@link InputStream}.
*/
public class SvgDecoder implements ResourceDecoder<InputStream, SVG> {
@Override
public boolean handles(@NonNull InputStream source, @NonNull Options options) {
// TODO: Can we tell?
return true;
}
public Resource<SVG> decode(@NonNull InputStream source, int width, int height,
@NonNull Options options)
throws IOException {
try {
SVG svg = SVG.getFromInputStream(source);
return new SimpleResource<>(svg);
} catch (SVGParseException ex) {
throw new IOException("Cannot load SVG from stream", ex);
}
}
}

View file

@ -0,0 +1,28 @@
package fr.free.nrw.commons.glide;
import android.graphics.Picture;
import android.graphics.drawable.PictureDrawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.resource.SimpleResource;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.caverock.androidsvg.SVG;
/**
* Convert the {@link SVG}'s internal representation to an Android-compatible one
* ({@link Picture}).
*/
public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> {
@Nullable
@Override
public Resource<PictureDrawable> transcode(@NonNull Resource<SVG> toTranscode,
@NonNull Options options) {
SVG svg = toTranscode.get();
Picture picture = svg.renderToPicture();
PictureDrawable drawable = new PictureDrawable(picture);
return new SimpleResource<>(drawable);
}
}

View file

@ -0,0 +1,51 @@
package fr.free.nrw.commons.glide;
import android.graphics.drawable.PictureDrawable;
import android.widget.ImageView;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.ImageViewTarget;
import com.bumptech.glide.request.target.Target;
/**
* Listener which updates the {@link ImageView} to be software rendered, because
* {@link com.caverock.androidsvg.SVG SVG}/{@link android.graphics.Picture Picture} can't render on
* a hardware backed {@link android.graphics.Canvas Canvas}.
*/
public class SvgSoftwareLayerSetter implements RequestListener<PictureDrawable> {
/**
* Sets the layer type to none if the load fails
* @param e
* @param model
* @param target
* @param isFirstResource
* @return
*/
@Override
public boolean onLoadFailed(GlideException e, Object model, Target<PictureDrawable> target,
boolean isFirstResource) {
ImageView view = ((ImageViewTarget<?>) target).getView();
view.setLayerType(ImageView.LAYER_TYPE_NONE, null);
return false;
}
/**
* Sets the layer type to software when the resource is ready
* @param resource
* @param model
* @param target
* @param dataSource
* @param isFirstResource
* @return
*/
@Override
public boolean onResourceReady(PictureDrawable resource, Object model,
Target<PictureDrawable> target, DataSource dataSource, boolean isFirstResource) {
ImageView view = ((ImageViewTarget<?>) target).getView();
view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null);
return false;
}
}

View file

@ -23,9 +23,6 @@ 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;
@ -35,6 +32,9 @@ import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Provider;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import fr.free.nrw.commons.License;
import fr.free.nrw.commons.LicenseList;
import fr.free.nrw.commons.Media;
@ -56,16 +56,16 @@ import static android.widget.Toast.LENGTH_SHORT;
public class MediaDetailFragment extends CommonsDaggerSupportFragment {
private boolean editable;
private boolean isFeaturedMedia;
private boolean isCategoryImage;
private MediaDetailPagerFragment.MediaDetailProvider detailProvider;
private int index;
public static MediaDetailFragment forMedia(int index, boolean editable, boolean isFeaturedMedia) {
public static MediaDetailFragment forMedia(int index, boolean editable, boolean isCategoryImage) {
MediaDetailFragment mf = new MediaDetailFragment();
Bundle state = new Bundle();
state.putBoolean("editable", editable);
state.putBoolean("isFeaturedMedia", isFeaturedMedia);
state.putBoolean("isCategoryImage", isCategoryImage);
state.putInt("index", index);
state.putInt("listIndex", 0);
state.putInt("listTop", 0);
@ -128,7 +128,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
super.onSaveInstanceState(outState);
outState.putInt("index", index);
outState.putBoolean("editable", editable);
outState.putBoolean("isFeaturedMedia", isFeaturedMedia);
outState.putBoolean("isCategoryImage", isCategoryImage);
getScrollPosition();
outState.putInt("listTop", initialListTop);
@ -144,12 +144,12 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
if (savedInstanceState != null) {
editable = savedInstanceState.getBoolean("editable");
isFeaturedMedia = savedInstanceState.getBoolean("isFeaturedMedia");
isCategoryImage = savedInstanceState.getBoolean("isCategoryImage");
index = savedInstanceState.getInt("index");
initialListTop = savedInstanceState.getInt("listTop");
} else {
editable = getArguments().getBoolean("editable");
isFeaturedMedia = getArguments().getBoolean("isFeaturedMedia");
isCategoryImage = getArguments().getBoolean("isCategoryImage");
index = getArguments().getInt("index");
initialListTop = 0;
}
@ -161,7 +161,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
ButterKnife.bind(this,view);
if (isFeaturedMedia){
if (isCategoryImage){
authorLayout.setVisibility(VISIBLE);
} else {
authorLayout.setVisibility(GONE);
@ -328,7 +328,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
if (!TextUtils.isEmpty(licenseLink(media))) {
openWebBrowser(licenseLink(media));
} else {
if(isFeaturedMedia) {
if(isCategoryImage) {
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);
@ -503,8 +503,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
if (media.getRequestedDeletion()){
delete.setVisibility(GONE);
nominatedForDeletion.setVisibility(VISIBLE);
}
else{
} else if (!isCategoryImage) {
delete.setVisibility(VISIBLE);
nominatedForDeletion.setVisibility(GONE);
}

View file

@ -444,8 +444,8 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
.param("notprop", "list")
.param("format", "xml")
.param("meta", "notifications")
// .param("meta", "notifications")
.param("notformat", "model")
.param("notwikis", "wikidatawiki|commonswiki|enwiki")
.get()
.getNode("/api/query/notifications/list");
} catch (IOException e) {

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.notification;
import android.util.Log;
import android.graphics.drawable.PictureDrawable;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -8,17 +9,23 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.borjabravo.readmoretextview.ReadMoreTextView;
import com.bumptech.glide.RequestBuilder;
import com.pedrogomez.renderers.Renderer;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.glide.SvgSoftwareLayerSetter;
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
/**
* Created by root on 19.12.2017.
*/
public class NotificationRenderer extends Renderer<Notification> {
private RequestBuilder<PictureDrawable> requestBuilder;
@BindView(R.id.title) ReadMoreTextView title;
@BindView(R.id.time) TextView time;
@BindView(R.id.icon) ImageView icon;
@ -41,23 +48,32 @@ public class NotificationRenderer extends Renderer<Notification> {
protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) {
View inflatedView = layoutInflater.inflate(R.layout.item_notification, viewGroup, false);
ButterKnife.bind(this, inflatedView);
requestBuilder = GlideApp.with(inflatedView.getContext())
.as(PictureDrawable.class)
.error(R.drawable.round_icon_unknown)
.transition(withCrossFade())
.listener(new SvgSoftwareLayerSetter());
return inflatedView;
}
@Override
public void render() {
Notification notification = getContent();
String str = notification.notificationText.trim();
str = str.concat(" ");
title.setText(str);
setTitle(notification.notificationText);
time.setText(notification.date);
switch (notification.notificationType) {
case THANK_YOU_EDIT:
icon.setImageResource(R.drawable.ic_edit_black_24dp);
break;
default:
icon.setImageResource(R.drawable.round_icon_unknown);
}
requestBuilder.load(notification.iconUrl).into(icon);
}
/**
* Cleans up the notification text and sets it as the title
* Clean up is required to fix escaped HTML string and extra white spaces at the beginning of the notification
* @param notificationText
*/
private void setTitle(String notificationText) {
notificationText = notificationText.trim().replaceAll("(^\\h*)|(\\h*$)", "");
notificationText = Html.fromHtml(notificationText).toString();
notificationText = notificationText.concat(" ");
title.setText(notificationText);
}
public interface NotificationClicked{

View file

@ -16,12 +16,13 @@ import javax.annotation.Nullable;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.R;
import static fr.free.nrw.commons.notification.NotificationType.THANK_YOU_EDIT;
import static fr.free.nrw.commons.notification.NotificationType.UNKNOWN;
public class NotificationUtils {
private static final String COMMONS_WIKI = "commonswiki";
private static final String WIKIDATA_WIKI = "wikidatawiki";
private static final String WIKIPEDIA_WIKI = "enwiki";
public static boolean isCommonsNotification(Node document) {
if (document == null || !document.hasAttributes()) {
@ -31,6 +32,32 @@ public class NotificationUtils {
return COMMONS_WIKI.equals(element.getAttribute("wiki"));
}
/**
* Returns true if the wiki attribute corresponds to wikidatawiki
* @param document
* @return
*/
public static boolean isWikidataNotification(Node document) {
if (document == null || !document.hasAttributes()) {
return false;
}
Element element = (Element) document;
return WIKIDATA_WIKI.equals(element.getAttribute("wiki"));
}
/**
* Returns true if the wiki attribute corresponds to enwiki
* @param document
* @return
*/
public static boolean isWikipediaNotification(Node document) {
if (document == null || !document.hasAttributes()) {
return false;
}
Element element = (Element) document;
return WIKIPEDIA_WIKI.equals(element.getAttribute("wiki"));
}
public static NotificationType getNotificationType(Node document) {
Element element = (Element) document;
String type = element.getAttribute("type");
@ -68,10 +95,17 @@ public class NotificationUtils {
return notifications;
}
/**
* Currently the app is interested in showing notifications just from the following three wikis: commons, wikidata, wikipedia
* This function returns true only if the notification belongs to any of the above wikis and is of a known notification type
* @param node
* @return
*/
private static boolean isUsefulNotification(Node node) {
return isCommonsNotification(node)
&& !getNotificationType(node).equals(UNKNOWN)
&& !getNotificationType(node).equals(THANK_YOU_EDIT);
return (isCommonsNotification(node)
|| isWikidataNotification(node)
|| isWikipediaNotification(node))
&& !getNotificationType(node).equals(UNKNOWN);
}
public static boolean isBundledNotification(Node document) {
@ -97,7 +131,7 @@ public class NotificationUtils {
switch (type) {
case THANK_YOU_EDIT:
notificationText = context.getString(R.string.notifications_thank_you_edit);
notificationText = getThankYouEditDescription(document);
break;
case EDIT_USER_TALK:
notificationText = getNotificationText(document);
@ -146,6 +180,16 @@ public class NotificationUtils {
return body != null ? body.getTextContent() : "";
}
/**
* Gets the header node returned in the XML document to form the description for thank you edits
* @param document
* @return
*/
private static String getThankYouEditDescription(Node document) {
Node body = getNode(getModel(document), "header");
return body != null ? body.getTextContent() : "";
}
private static String getNotificationIconUrl(Node document) {
String format = "%s%s";
Node iconUrl = getNode(getModel(document), "iconUrl");

View file

@ -0,0 +1,35 @@
package fr.free.nrw.commons.notification;
import android.content.Context;
import android.graphics.drawable.PictureDrawable;
import android.support.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
import com.caverock.androidsvg.SVG;
import java.io.InputStream;
import fr.free.nrw.commons.glide.SvgDecoder;
import fr.free.nrw.commons.glide.SvgDrawableTranscoder;
/**
* Module for the SVG sample app.
*/
@GlideModule
public class SvgModule extends AppGlideModule {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
registry.register(SVG.class, PictureDrawable.class, new SvgDrawableTranscoder())
.append(InputStream.class, SVG.class, new SvgDecoder());
}
// Disable manifest parsing to avoid adding similar modules twice.
@Override
public boolean isManifestParsingEnabled() {
return false;
}
}

View file

@ -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());

View file

@ -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.
* Requests Storage permission, if needed.
@ -264,7 +275,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(),
@ -337,6 +347,7 @@ public class ShareActivity
if (mediaUri != null) {
backgroundImageView.setImageURI(mediaUri);
}
<<<<<<< HEAD
}
/**
@ -388,18 +399,94 @@ public class ShareActivity
});
}
/**
=======
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 (!needsToRequestStoragePermission()) {
storagePermitted = true;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
}
}
// 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);
}
}
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();
mapsFragment.setVisibility(View.VISIBLE);
if( imageObj == null || imageObj.imageCoordsExists != true){
mapsFragment.setVisibility(View.INVISIBLE);
}
}
/*
>>>>>>> refs/remotes/commons-app/master
* Function to display the zoom and map FAB
*/
private void showFABMenu() {
isFABOpen=true;
<<<<<<< HEAD
if( imageObj != null && imageObj.imageCoordsExists)
maps_fragment.setVisibility(View.VISIBLE);
=======
if( imageObj != null && imageObj.imageCoordsExists == true)
mapsFragment.setVisibility(View.VISIBLE);
>>>>>>> refs/remotes/commons-app/master
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));
}
@ -409,7 +496,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) {
@ -418,7 +505,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);
}
}
@ -671,8 +758,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");
@ -838,26 +926,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);
@ -928,53 +1009,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);
}
}
}

View file

@ -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<RequestListener> 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();
}
}