Display like dialogs on the main activity

This commit is contained in:
Dmitry Yunitsky 2015-01-22 20:36:53 +03:00 committed by Alex Zolotarev
parent 657918e9ea
commit 7661789be1
18 changed files with 379 additions and 19 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:drawable="@drawable/ic_rate_empty"/>
<item android:id="@android:id/secondaryProgress"
android:drawable="@drawable/ic_rate_full"/>
<item android:id="@android:id/progress"
android:drawable="@drawable/ic_rate_full"/>
</layer-list>

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv__title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_small"
android:layout_marginLeft="@dimen/margin_medium_and_half"
android:layout_marginRight="@dimen/margin_medium_and_half"
android:layout_marginTop="@dimen/margin_medium_and_half"
android:fontFamily="@string/robotoMedium"
android:text="Do you like maps.me?"
android:textColor="@color/text_black_title"
android:textSize="20sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/tv__subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_medium_and_half"
android:layout_marginLeft="@dimen/margin_medium_and_half"
android:layout_marginRight="@dimen/margin_medium_and_half"
android:fontFamily="@string/robotoRegular"
android:text="Please, tap a star to rate our app"
android:textColor="@color/text_black_subtitle"
android:textSize="14sp"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RatingBar
android:id="@+id/rb__play_rate"
style="@style/MwmRatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_vertical"
android:numStars="5"
android:stepSize="1"/>
<View
android:id="@+id/v__divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/downloader_gray"
android:visibility="gone"/>
<Button
android:id="@+id/btn__explain_bad_rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/clickableBackground"
android:drawableLeft="@drawable/ic_rate_send"
android:fontFamily="@string/robotoRegular"
android:gravity="center_vertical"
android:padding="@dimen/margin_medium"
android:text="Send feedback"
android:textColor="@color/text_black_title"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>

View file

@ -65,4 +65,8 @@
<!-- routing-->
<color name="text_turn_blue">#2291d1</color>
<!-- global black fonts -->
<color name="text_black_title">#dd000000</color>
<color name="text_black_subtitle">#89000000</color>
</resources>

View file

@ -14,6 +14,7 @@
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_small_and_half">12dp</dimen>
<dimen name="margin_medium">16dp</dimen>
<dimen name="margin_medium_and_half">24dp</dimen>
<dimen name="margin_large">32dp</dimen>
<dimen name="margin_large_and_half">48dp</dimen>

View file

@ -150,4 +150,9 @@
<item name="android:background">@drawable/ic_bg_light</item>
</style>
<style name="MwmRatingBar" parent="android:Widget.RatingBar">
<item name="android:progressDrawable">@drawable/rating_bar</item>
<item name="android:indeterminateDrawable">@drawable/rating_bar</item>
</style>
</resources>

View file

@ -158,7 +158,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
});
}
protected void confirmDownloadCancelation(final ViewHolder holder, final int position, final String name)
protected void confirmDownloadCancellation(final ViewHolder holder, final int position, final String name)
{
final Dialog dlg = new AlertDialog.Builder(mFragment.getActivity())
.setTitle(name)
@ -376,7 +376,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
@Override
public void onClick(View v)
{
confirmDownloadCancelation(holder, position, item.getName());
confirmDownloadCancellation(holder, position, item.getName());
}
});
@ -462,7 +462,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
@Override
public void onClick(View v)
{
confirmDownloadCancelation(holder, position, item.getName());
confirmDownloadCancellation(holder, position, item.getName());
}
});
holder.mInfoSlided.setVisibility(View.VISIBLE);
@ -773,7 +773,7 @@ abstract class BaseDownloadAdapter extends BaseAdapter
processNotDownloaded(name, position, status, StorageOptions.MAP_OPTION_MAP_ONLY, holder);
break;
case MENU_CANCEL:
confirmDownloadCancelation(holder, position, name);
confirmDownloadCancellation(holder, position, name);
break;
case MENU_SHOW:
showCountry(position);

View file

@ -49,6 +49,7 @@ import com.mapswithme.maps.Framework.OnBalloonListener;
import com.mapswithme.maps.Framework.RoutingListener;
import com.mapswithme.maps.MapStorage.Index;
import com.mapswithme.maps.ads.AdsManager;
import com.mapswithme.maps.ads.LikesManager;
import com.mapswithme.maps.ads.MenuAd;
import com.mapswithme.maps.api.ParsedMmwRequest;
import com.mapswithme.maps.background.WorkerService;
@ -72,7 +73,6 @@ import com.mapswithme.maps.settings.UnitLocale;
import com.mapswithme.maps.widget.MapInfoView;
import com.mapswithme.maps.widget.MapInfoView.OnVisibilityChangedListener;
import com.mapswithme.maps.widget.MapInfoView.State;
import com.mapswithme.util.ConnectionState;
import com.mapswithme.util.Constants;
import com.mapswithme.util.InputUtils;
import com.mapswithme.util.LocationUtils;
@ -159,6 +159,7 @@ public class MWMActivity extends NvEventQueueActivity
private boolean mIsFragmentContainer;
private LocationPredictor mLocationPredictor;
private LikesManager mLikesManager;
public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload)
{
@ -730,6 +731,7 @@ public class MWMActivity extends NvEventQueueActivity
LocalBroadcastManager.getInstance(this).registerReceiver(mUpdateAdsReceiver, new IntentFilter(WorkerService.ACTION_UPDATE_MENU_ADS));
mLocationPredictor = new LocationPredictor(new Handler(), this);
mLikesManager = new LikesManager(this);
}
private void initViews()
@ -1127,16 +1129,6 @@ public class MWMActivity extends NvEventQueueActivity
LocationState.INSTANCE.removeLocationStateModeListener(mLocationStateModeListenerId);
}
@Override
protected void onPause()
{
pauseLocation();
stopWatchingExternalStorage();
stopWatchingCompassStatusUpdate();
super.onPause();
mLocationPredictor.pause();
}
@Override
protected void onResume()
{
@ -1155,6 +1147,18 @@ public class MWMActivity extends NvEventQueueActivity
tryResumeRouting();
MWMApplication.get().onMwmResume(this);
mLocationPredictor.resume();
mLikesManager.showLikeDialogs();
}
@Override
protected void onPause()
{
pauseLocation();
stopWatchingExternalStorage();
stopWatchingCompassStatusUpdate();
super.onPause();
mLocationPredictor.pause();
mLikesManager.cancelLikeDialogs();
}
private void tryResumeRouting()

View file

@ -284,7 +284,10 @@ public class MWMApplication extends android.app.Application implements ActiveCou
final int sessionNum = nativeGetInt(SESSION_NUMBER_SETTING, 0);
final long lastSessionTimestamp = nativeGetLong(LAST_SESSION_TIMESTAMP_SETTING, 0);
if (!DateUtils.isToday(lastSessionTimestamp))
{
nativeSetInt(SESSION_NUMBER_SETTING, sessionNum + 1);
nativeSetLong(LAST_SESSION_TIMESTAMP_SETTING, System.currentTimeMillis());
}
}
private void trackAppActivation()

View file

@ -2,6 +2,7 @@ package com.mapswithme.maps.ads;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
@ -11,10 +12,21 @@ import android.view.View;
import com.google.android.gms.plus.PlusOneButton;
import com.mapswithme.maps.R;
import com.mapswithme.util.Constants;
import com.mapswithme.util.statistics.Statistics;
public class GooglePlusDialogFragment extends DialogFragment
{
@Override
public void onResume()
{
super.onResume();
PlusOneButton plusButton = (PlusOneButton) getDialog().findViewById(R.id.btn__gplus);
if (plusButton != null)
plusButton.initialize(Constants.Url.PLAY_MARKET_HTTPS_APP_PREFIX + Constants.Package.MWM_PRO_PACKAGE, 0);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
@ -23,10 +35,24 @@ public class GooglePlusDialogFragment extends DialogFragment
final LayoutInflater inflater = getActivity().getLayoutInflater();
final View root = inflater.inflate(R.layout.fragment_google_plus_dialog, null);
builder.setView(root);
PlusOneButton plusButton = (PlusOneButton) root.findViewById(R.id.btn__gplus);
plusButton.initialize(Constants.Url.PLAY_MARKET_HTTPS_APP_PREFIX + Constants.Package.MWM_PRO_PACKAGE, 1);
builder.
setView(root).
setNegativeButton(getString(R.string.remind_me_later), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.PLUS_DIALOG_LATER);
}
});
return builder.create();
}
@Override
public void onCancel(DialogInterface dialog)
{
super.onCancel(dialog);
Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.PLUS_DIALOG_LATER);
}
}

View file

@ -0,0 +1,102 @@
package com.mapswithme.maps.ads;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import com.mapswithme.maps.MWMApplication;
import java.lang.ref.WeakReference;
import java.util.Arrays;
public class LikesManager
{
public static final Integer[] GPLAY_NEW_USERS = new Integer[]{3, 7, 10, 15, 21};
public static final Integer[] GPLUS_NEW_USERS = new Integer[]{11, 20, 30, 40, 50};
public static final Integer[] GPLAY_OLD_USERS = new Integer[]{1, 7, 10, 15, 21};
public static final Integer[] GPLUS_OLD_USERS = new Integer[]{4, 14, 24, 34, 44};
private final boolean mIsNewUser;
private final int mSessionNum;
private Handler mHandler;
private Runnable mLikeRunnable;
private WeakReference<FragmentActivity> mActivityRef;
public static final String LAST_RATED_SESSION = "LastRatedSession";
public LikesManager(FragmentActivity activity)
{
mHandler = new Handler(activity.getMainLooper());
mActivityRef = new WeakReference<>(activity);
mIsNewUser = MWMApplication.get().getFirstInstallVersion() >= 430;
mSessionNum = MWMApplication.get().getSessionsNumber();
}
public void showLikeDialogs()
{
if (mIsNewUser)
{
if (Arrays.asList(GPLAY_NEW_USERS).contains(mSessionNum))
displayLikeDialog(RateStoreDialogFragment.class);
else if (Arrays.asList(GPLUS_NEW_USERS).contains(mSessionNum))
displayLikeDialog(GooglePlusDialogFragment.class);
}
else
{
if (Arrays.asList(GPLAY_OLD_USERS).contains(mSessionNum))
displayLikeDialog(RateStoreDialogFragment.class);
else if (Arrays.asList(GPLUS_OLD_USERS).contains(mSessionNum))
displayLikeDialog(GooglePlusDialogFragment.class);
}
}
private void displayLikeDialog(final Class<? extends DialogFragment> dialogFragmentClass)
{
if (isSessionRated())
return;
setSessionRated();
mHandler.removeCallbacks(mLikeRunnable);
mLikeRunnable = new Runnable()
{
@Override
public void run()
{
final FragmentActivity activity = mActivityRef.get();
if (activity == null)
return;
final DialogFragment fragment;
try
{
fragment = dialogFragmentClass.newInstance();
fragment.show(activity.getSupportFragmentManager(), null);
} catch (InstantiationException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
};
mHandler.postDelayed(mLikeRunnable, 1);
}
public void cancelLikeDialogs()
{
mHandler.removeCallbacks(mLikeRunnable);
}
public boolean isSessionRated()
{
return MWMApplication.get().nativeGetInt(LAST_RATED_SESSION, 0) >= mSessionNum;
}
public void setSessionRated()
{
MWMApplication.get().nativeSetInt(LAST_RATED_SESSION, mSessionNum);
}
}

View file

@ -0,0 +1,112 @@
package com.mapswithme.maps.ads;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.RatingBar;
import android.widget.TextView;
import com.mapswithme.maps.BuildConfig;
import com.mapswithme.maps.R;
import com.mapswithme.util.Constants;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.statistics.Statistics;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
public class RateStoreDialogFragment extends DialogFragment implements View.OnClickListener
{
private float mRating;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final LayoutInflater inflater = getActivity().getLayoutInflater();
final View root = inflater.inflate(R.layout.fragment_google_play_dialog, null);
builder.
setView(root).
setNegativeButton(getString(R.string.remind_me_later), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.RATE_DIALOG_LATER);
}
});
final RatingBar rateBar = (RatingBar) root.findViewById(R.id.rb__play_rate);
rateBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener()
{
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser)
{
Statistics.INSTANCE.trackRatingDialog(rating);
mRating = rating;
if (rating == 5.0f)
Utils.openAppInMarket(getActivity(), BuildConfig.REVIEW_URL);
else
{
ObjectAnimator animator = ObjectAnimator.ofFloat(rateBar, "alpha", 1.0f, 0.0f);
animator.addListener(new UiUtils.SimpleNineoldAnimationListener()
{
@Override
public void onAnimationEnd(Animator animation)
{
final Button button = (Button) root.findViewById(R.id.btn__explain_bad_rating);
button.setVisibility(View.VISIBLE);
button.setOnClickListener(RateStoreDialogFragment.this);
((TextView) root.findViewById(R.id.tv__title)).setText("Thank you!");
((TextView) root.findViewById(R.id.tv__subtitle)).setText("Would you like to share any ideas or issues, so we can improve the app for you?");
root.findViewById(R.id.v__divider).setVisibility(View.VISIBLE);
rateBar.setVisibility(View.GONE);
super.onAnimationEnd(animation);
}
});
animator.start();
}
}
});
return builder.create();
}
@Override
public void onCancel(DialogInterface dialog)
{
super.onCancel(dialog);
Statistics.INSTANCE.trackSimpleNamedEvent(Statistics.EventName.RATE_DIALOG_LATER);
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btn__explain_bad_rating:
final Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Utils.buildMailUri(Constants.Url.MAIL_MAPSME_RATING, "Rating : " + mRating,
"Android version:" + Build.VERSION.SDK_INT + "\n" + "App version: " + BuildConfig.APPLICATION_ID + " " + BuildConfig.VERSION_CODE + "\n"));
try
{
startActivity(intent);
} catch (android.content.ActivityNotFoundException ex)
{
//
}
break;
}
}
}

View file

@ -30,6 +30,7 @@ public class Constants
public static final String MAIL_MAPSME_INFO = "android@maps.me";
public static final String MAIL_MAPSME_BUGS = "android@maps.me";
public static final String MAIL_MAPSME_SUBSCRIBE = "subscribe@maps.me";
public static final String MAIL_MAPSME_RATING = "rating@maps.me";
public static final String DATA_SCHEME_FILE = "file";
public static final String FEATURES_JSON = "http://application.server/android/features.json";

View file

@ -287,7 +287,6 @@ public class Utils
}
/**
*
* @param timestamp in currentTimeMillis() format
* @return
*/
@ -304,4 +303,15 @@ public class Utils
return false;
}
public static void openAppInMarket(Activity activity, String url)
{
final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
else
marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(marketIntent);
}
}

View file

@ -66,6 +66,9 @@ public enum Statistics
public static final String STATISTICS_STATUS_CHANGED = "Statistics status changed";
public static final String NO_FREE_SPACE = "Downloader. Not enough free space.";
public static final String APP_ACTIVATED = "Application activated.";
public static final String PLUS_DIALOG_LATER = "GPlus dialog cancelled.";
public static final String RATE_DIALOG_LATER = "GPlay dialog cancelled.";
public static final String RATE_DIALOG_RATED = "GPlay dialog. Rating set";
}
public static class EventParam
@ -85,6 +88,7 @@ public enum Statistics
public static final String ENABLED = "Enabled";
public static final String IS_PREINSTALLED = "IsPreinstalled";
public static final String APP_FLAVOR = "Flavor";
public static final String RATING = "Rating";
}
private Statistics()
@ -261,6 +265,15 @@ public enum Statistics
trackIfEnabled(mEventBuilder.setName(EventName.DOWNLOAD_COUNTRY_NOTIFICATION_CLICKED).buildEvent());
}
public void trackRatingDialog(float rating)
{
final Event event = mEventBuilder.
setName(EventName.RATE_DIALOG_RATED).
addParam(EventParam.RATING, String.valueOf(rating)).
buildEvent();
trackIfEnabled(event);
}
public void trackSimpleNamedEvent(String eventName)
{
trackIfEnabled(mEventBuilder.setName(eventName).buildEvent());