/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.plaidapp.ui;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.SharedElementCallback;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.transition.ArcMotion;
import android.transition.TransitionManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List;
import io.plaidapp.BuildConfig;
import io.plaidapp.R;
import io.plaidapp.data.api.AuthInterceptor;
import io.plaidapp.data.api.dribbble.DribbbleAuthService;
import io.plaidapp.data.api.dribbble.DribbbleService;
import io.plaidapp.data.api.dribbble.model.AccessToken;
import io.plaidapp.data.api.dribbble.model.User;
import io.plaidapp.data.prefs.DribbblePrefs;
import io.plaidapp.ui.transitions.FabDialogMorphSetup;
import io.plaidapp.ui.transitions.MorphDialogToFab;
import io.plaidapp.ui.transitions.MorphFabToDialog;
import io.plaidapp.util.ScrimUtil;
import io.plaidapp.util.glide.CircleTransform;
import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;
import retrofit.converter.GsonConverter;
public class DribbbleLogin extends Activity {
boolean isDismissing = false;
private ViewGroup container;
private TextView message;
private Button login;
private ProgressBar loading;
private DribbblePrefs dribbblePrefs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dribbble_login);
FabDialogMorphSetup.setupSharedEelementTransitions(this, container,
getResources().getDimensionPixelSize(R.dimen.dialog_corners));
container = (ViewGroup) findViewById(R.id.container);
message = (TextView) findViewById(R.id.login_message);
login = (Button) findViewById(R.id.login);
loading = (ProgressBar) findViewById(R.id.loading);
loading.setVisibility(View.GONE);
dribbblePrefs = DribbblePrefs.get(this);
checkAuthCallback(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
checkAuthCallback(intent);
}
public void doLogin(View view) {
showLoading();
dribbblePrefs.login(DribbbleLogin.this);
}
public void dismiss(View view) {
isDismissing = true;
setResult(Activity.RESULT_CANCELED);
finishAfterTransition();
}
@Override
public void onBackPressed() {
dismiss(null);
}
private void showLoading() {
TransitionManager.beginDelayedTransition(container);
message.setVisibility(View.GONE);
login.setVisibility(View.GONE);
loading.setVisibility(View.VISIBLE);
}
private void showLogin() {
TransitionManager.beginDelayedTransition(container);
message.setVisibility(View.VISIBLE);
login.setVisibility(View.VISIBLE);
loading.setVisibility(View.GONE);
}
private void checkAuthCallback(Intent intent) {
if (intent != null
&& intent.getData() != null
&& !TextUtils.isEmpty(intent.getData().getAuthority())
&& DribbblePrefs.LOGIN_CALLBACK.equals(intent.getData().getAuthority())) {
showLoading();
getAccessToken(intent.getData().getQueryParameter("code"));
}
}
private void getAccessToken(String code) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(DribbbleAuthService.ENDPOINT)
.build();
DribbbleAuthService dribbbleAuthApi = restAdapter.create((DribbbleAuthService.class));
dribbbleAuthApi.getAccessToken(BuildConfig.DRIBBBLE_CLIENT_ID,
BuildConfig.DRIBBBLE_CLIENT_SECRET,
code, "", new Callback<AccessToken>() {
@Override
public void success(AccessToken accessToken, Response response) {
dribbblePrefs.setAccessToken(accessToken.access_token);
showLoggedInUser();
setResult(Activity.RESULT_OK);
finishAfterTransition();
}
@Override
public void failure(RetrofitError error) {
Log.e(getClass().getCanonicalName(), error.getMessage(), error);
// TODO snackbar?
Toast.makeText(getApplicationContext(), "Log in failed: " + error
.getResponse()
.getStatus(), Toast.LENGTH_LONG).show();
showLogin();
}
});
}
private void showLoggedInUser() {
Gson gson = new GsonBuilder()
.setDateFormat(DribbbleService.DATE_FORMAT)
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(DribbbleService.ENDPOINT)
.setConverter(new GsonConverter(gson))
.setRequestInterceptor(new AuthInterceptor(dribbblePrefs.getAccessToken()))
.build();
DribbbleService dribbbleApi = restAdapter.create((DribbbleService.class));
dribbbleApi.getAuthenticatedUser(new Callback<User>() {
@Override
public void success(User user, Response response) {
dribbblePrefs.setLoggedInUser(user);
Toast confirmLogin = new Toast(getApplicationContext());
View v = LayoutInflater.from(DribbbleLogin.this).inflate(R.layout
.toast_logged_in_confirmation, null, false);
((TextView) v.findViewById(R.id.name)).setText(user.name);
// need to use app context here as the activity will be destroyed shortly
Glide.with(getApplicationContext())
.load(user.avatar_url)
.placeholder(R.drawable.ic_player)
.transform(new CircleTransform(getApplicationContext()))
.into((ImageView) v.findViewById(R.id.avatar));
v.findViewById(R.id.scrim).setBackground(ScrimUtil.makeCubicGradientScrimDrawable
(ContextCompat.getColor(DribbbleLogin.this, R.color.scrim),
5, Gravity.BOTTOM));
confirmLogin.setView(v);
confirmLogin.setGravity(Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0);
confirmLogin.setDuration(Toast.LENGTH_LONG);
confirmLogin.show();
}
@Override
public void failure(RetrofitError error) {
}
});
}
private void forceSharedElementLayout() {
int widthSpec = View.MeasureSpec.makeMeasureSpec(container.getWidth(),
View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(container.getHeight(),
View.MeasureSpec.EXACTLY);
container.measure(widthSpec, heightSpec);
container.layout(container.getLeft(), container.getTop(), container.getRight(), container
.getBottom());
}
private SharedElementCallback sharedElementEnterCallback = new SharedElementCallback() {
@Override
public View onCreateSnapshotView(Context context, Parcelable snapshot) {
// grab the saved fab snapshot and pass it to the below via a View
View view = new View(context);
final Bitmap snapshotBitmap = getSnapshot(snapshot);
if (snapshotBitmap != null) {
view.setBackground(new BitmapDrawable(context.getResources(), snapshotBitmap));
}
return view;
}
@Override
public void onSharedElementStart(List<String> sharedElementNames,
List<View> sharedElements,
List<View> sharedElementSnapshots) {
// grab the fab snapshot and fade it out/in (depending on if we are entering or exiting)
for (int i = 0; i < sharedElements.size(); i++) {
if (sharedElements.get(i) == container) {
View snapshot = sharedElementSnapshots.get(i);
BitmapDrawable fabSnapshot = (BitmapDrawable) snapshot.getBackground();
fabSnapshot.setBounds(0, 0, snapshot.getWidth(), snapshot.getHeight());
container.getOverlay().clear();
container.getOverlay().add(fabSnapshot);
if (!isDismissing) {
// fab -> login: fade out the fab snapshot
ObjectAnimator.ofInt(fabSnapshot, "alpha", 0).setDuration(100).start();
} else {
// login -> fab: fade in the fab snapshot toward the end of the transition
fabSnapshot.setAlpha(0);
ObjectAnimator fadeIn = ObjectAnimator.ofInt(fabSnapshot, "alpha", 255)
.setDuration(150);
fadeIn.setStartDelay(150);
fadeIn.start();
}
forceSharedElementLayout();
break;
}
}
}
private Bitmap getSnapshot(Parcelable parcel) {
if (parcel instanceof Bitmap) {
return (Bitmap) parcel;
} else if (parcel instanceof Bundle) {
Bundle bundle = (Bundle) parcel;
// see SharedElementCallback#onCaptureSharedElementSnapshot
return (Bitmap) bundle.getParcelable("sharedElement:snapshot:bitmap");
}
return null;
}
};
}