diff options
author | Dmitry Yunitsky <yunik@mapswithme.com> | 2016-05-25 15:26:54 +0300 |
---|---|---|
committer | Vladimir Byko-Ianko <v.bykoianko@corp.mail.ru> | 2016-06-24 13:31:45 +0300 |
commit | ba4767d7853d45f6dfbee12037d7d0842dc8ecb9 (patch) | |
tree | 2819956540760f9ae262aa4cb901146049cef0d9 /android | |
parent | ea8b9b849e51d969a394f57884ce32ec469cf49e (diff) |
[android] UserStats integration.
Diffstat (limited to 'android')
9 files changed, 301 insertions, 63 deletions
diff --git a/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp b/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp index 11b1d96be6..ebebf7255d 100644 --- a/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp +++ b/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp @@ -1,11 +1,15 @@ #include <jni.h> #include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" #include "base/logging.hpp" +#include "base/string_utils.hpp" +#include "base/timer.hpp" #include "editor/osm_auth.hpp" #include "editor/server_api.hpp" +#include "editor/user_stats.hpp" namespace { @@ -115,4 +119,31 @@ Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetOsmUsername(JNIEnv * env, jcla return nullptr; } } + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_OsmOAuth_nativeUpdateOsmUserStats(JNIEnv * env, jclass clazz, jstring jUsername) +{ + static jclass const statsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/UserStats"); + static jmethodID const statsCtor = jni::GetConstructorID(env, statsClazz, "(IILjava/lang/String;J)V"); + static jclass const osmAuthClazz = static_cast<jclass>(env->NewGlobalRef(clazz)); + // void onUserStatsUpdated(UserStats stats) + static jmethodID const listenerId = env->GetStaticMethodID(osmAuthClazz, "onUserStatsUpdated", "(Lcom/mapswithme/maps/editor/data/UserStats;)V"); + ASSERT(listenerId, ("Can't get methodID for onUserStatsUpdated", DescribeException())); + auto const username = jni::ToNativeString(env, jUsername); + g_framework->NativeFramework()->UpdateUserStats(username, [username]() + { + editor::UserStats const & userStats = g_framework->NativeFramework()->GetUserStats(username); + if (!userStats.IsValid()) + return; + int32_t count, rank; + string levelUp; + userStats.GetChangesCount(count); + userStats.GetRank(rank); + userStats.GetLevelUpRequiredFeat(levelUp); + JNIEnv * env = jni::GetEnv(); + env->CallStaticVoidMethod(osmAuthClazz, listenerId, + env->NewObject(statsClazz, statsCtor, count, rank, jni::ToJavaString(env, levelUp), + my::TimeTToSecondsSinceEpoch(userStats.GetLastUpdate()))); + }); +} } // extern "C" diff --git a/android/res/layout/fragment_auth_editor.xml b/android/res/layout/fragment_auth_editor.xml index ebcbcfd8c7..31a7b17be4 100644 --- a/android/res/layout/fragment_auth_editor.xml +++ b/android/res/layout/fragment_auth_editor.xml @@ -31,49 +31,85 @@ <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?colorPrimary" android:fillViewport="true" tools:ignore="DuplicateIds"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:padding="@dimen/margin_half_plus" - android:clipToPadding="false" android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical" tools:ignore="ScrollViewSize"> <LinearLayout android:id="@+id/block_edits" android:layout_width="match_parent" android:layout_height="wrap_content" + android:animateLayoutChanges="true" + android:background="?colorPrimary" android:orientation="vertical" + android:padding="@dimen/margin_base" android:visibility="visible"> - <include - android:id="@+id/local_edits" - layout="@layout/item_osm_edits" + <LinearLayout + android:id="@+id/sent_edits" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/margin_half"/> + android:paddingBottom="@dimen/margin_base" + android:orientation="vertical"> + + <TextView + android:id="@+id/edits_count" + android:layout_width="match_parent" + android:layout_height="112dp" + android:gravity="center" + android:textColor="@color/text_light" + android:textSize="96sp" + android:textStyle="bold" + tools:text="244"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/editor_rating_verified_changes" + android:textAppearance="@style/MwmTextAppearance.Body1.Light" + android:textStyle="bold"/> + + <TextView + android:id="@+id/date_sent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center" + android:textAppearance="@style/MwmTextAppearance.Body3.Light" + tools:text="Last sent: 12.01.2015"/> + + </LinearLayout> <include - android:id="@+id/sent_edits" + android:id="@+id/local_edits" layout="@layout/item_osm_edits" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/margin_half"/> + android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:id="@+id/block_auth" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" + android:layout_height="0dp" + android:layout_weight="1" + android:background="?colorPrimary" + android:clipChildren="false" android:clipToPadding="false" - android:clipChildren="false"> + android:orientation="vertical" + android:paddingEnd="@dimen/margin_base" + android:paddingLeft="@dimen/margin_base" + android:paddingRight="@dimen/margin_base" + android:paddingStart="@dimen/margin_base" + tools:visibility="gone"> <TextView android:id="@+id/first_osm_edit" @@ -87,9 +123,9 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - android:clipToPadding="false" android:clipChildren="false" + android:clipToPadding="false" + android:orientation="horizontal" tools:ignore="ButtonStyle"> <Button @@ -159,7 +195,8 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/margin_half" android:background="?clickableBackground" - android:padding="@dimen/margin_half" + android:paddingBottom="@dimen/margin_half" + android:paddingTop="@dimen/margin_half" android:text="@string/register_at_openstreetmap" android:textAllCaps="true" android:textAppearance="@style/MwmTextAppearance.Body1.Light" @@ -167,6 +204,90 @@ </LinearLayout> + <RelativeLayout + android:id="@+id/block_rating" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:padding="@dimen/margin_base"> + + <android.support.v7.widget.CardView + style="@style/MwmWidget.Editor.CardView" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + android:paddingBottom="@dimen/margin_base" + android:paddingEnd="@dimen/margin_half" + android:paddingLeft="@dimen/margin_half" + android:paddingRight="@dimen/margin_half" + android:paddingStart="@dimen/margin_half" + android:paddingTop="@dimen/margin_base"> + + <ImageView + android:id="@+id/image" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/margin_half" + android:layout_marginStart="@dimen/margin_half" + android:scaleType="center" + android:src="@drawable/ic_device" + android:tint="?iconTint"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/margin_base" + android:layout_marginStart="@dimen/margin_base" + android:layout_weight="1" + android:orientation="vertical" + tools:ignore="NestedWeights"> + + <TextView + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center_vertical" + android:text="@string/editor_rating_your_place" + android:textAppearance="@style/MwmTextAppearance.Body3"/> + + <TextView + android:id="@+id/rating" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:fontFamily="@string/robotoMedium" + android:gravity="center_vertical" + android:textAppearance="@style/MwmTextAppearance.Headline" + tools:ignore="UnusedAttribute" + tools:text="-42"/> + + </LinearLayout> + + </LinearLayout> + + </android.support.v7.widget.CardView> + + <TextView + android:id="@+id/about_osm" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:background="?clickableBackground" + android:gravity="center" + android:paddingBottom="@dimen/margin_half" + android:paddingTop="@dimen/margin_half" + android:text="@string/editor_more_about_osm" + android:textAppearance="@style/MwmTextAppearance.Body4" + android:textColor="?colorAccent" + android:textSize="@dimen/text_size_body_4"/> + + </RelativeLayout> + </LinearLayout> </ScrollView> diff --git a/android/res/layout/item_osm_edits.xml b/android/res/layout/item_osm_edits.xml index d9b189f2b2..8769c5b1fe 100644 --- a/android/res/layout/item_osm_edits.xml +++ b/android/res/layout/item_osm_edits.xml @@ -46,16 +46,7 @@ android:gravity="center_vertical" android:textAppearance="@style/MwmTextAppearance.Body1" tools:ignore="UnusedAttribute" - tools:text="Edits : 4"/> - - <TextView - android:id="@+id/subtitle" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:gravity="center_vertical" - android:textAppearance="@style/MwmTextAppearance.Body3" - tools:text="Last sent 12.01.2015"/> + tools:text="Not sent : 4"/> </LinearLayout> diff --git a/android/src/com/mapswithme/maps/editor/EditorFragment.java b/android/src/com/mapswithme/maps/editor/EditorFragment.java index ab58113ef5..f9bc9e3702 100644 --- a/android/src/com/mapswithme/maps/editor/EditorFragment.java +++ b/android/src/com/mapswithme/maps/editor/EditorFragment.java @@ -230,18 +230,21 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe private boolean validateFields() { - if (!Editor.nativeIsHouseValid(mHouseNumber.getText().toString())) + if (Editor.nativeIsAddressEditable()) { - mHouseNumber.requestFocus(); - InputUtils.showKeyboard(mHouseNumber); - return false; - } + if (!Editor.nativeIsHouseValid(mHouseNumber.getText().toString())) + { + mHouseNumber.requestFocus(); + InputUtils.showKeyboard(mHouseNumber); + return false; + } - if (!Editor.nativeIsLevelValid(mBuildingLevels.getText().toString())) - { - mBuildingLevels.requestFocus(); - InputUtils.showKeyboard(mBuildingLevels); - return false; + if (!Editor.nativeIsLevelValid(mBuildingLevels.getText().toString())) + { + mBuildingLevels.requestFocus(); + InputUtils.showKeyboard(mBuildingLevels); + return false; + } } if (!Editor.nativeIsZipcodeValid(mZipcode.getText().toString())) diff --git a/android/src/com/mapswithme/maps/editor/OsmAuthFragment.java b/android/src/com/mapswithme/maps/editor/OsmAuthFragment.java index 906edea210..0a64aa329d 100644 --- a/android/src/com/mapswithme/maps/editor/OsmAuthFragment.java +++ b/android/src/com/mapswithme/maps/editor/OsmAuthFragment.java @@ -25,6 +25,7 @@ import com.mapswithme.util.ThemeUtils; import com.mapswithme.util.UiUtils; import com.mapswithme.util.concurrency.ThreadPool; import com.mapswithme.util.concurrency.UiThread; +import com.mapswithme.util.statistics.Statistics; public class OsmAuthFragment extends BaseMwmToolbarFragment implements View.OnClickListener { @@ -143,6 +144,7 @@ public class OsmAuthFragment extends BaseMwmToolbarFragment implements View.OnCl private void recoverPassword() { + Statistics.INSTANCE.trackEvent(Statistics.EventName.EDITOR_LOST_PASSWORD); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.Url.OSM_RECOVER_PASSWORD))); } } diff --git a/android/src/com/mapswithme/maps/editor/OsmAuthFragmentDelegate.java b/android/src/com/mapswithme/maps/editor/OsmAuthFragmentDelegate.java index 200bb0137a..8023e0ae8b 100644 --- a/android/src/com/mapswithme/maps/editor/OsmAuthFragmentDelegate.java +++ b/android/src/com/mapswithme/maps/editor/OsmAuthFragmentDelegate.java @@ -61,10 +61,6 @@ public abstract class OsmAuthFragmentDelegate implements View.OnClickListener Statistics.INSTANCE.trackAuthRequest(OsmOAuth.AuthType.GOOGLE); loginWebview(OsmOAuth.AuthType.GOOGLE); break; - case R.id.lost_password: - Statistics.INSTANCE.trackEvent(Statistics.EventName.EDITOR_LOST_PASSWORD); - recoverPassword(); - break; case R.id.register: Statistics.INSTANCE.trackEvent(Statistics.EventName.EDITOR_REG_REQUEST); register(); @@ -183,11 +179,6 @@ public abstract class OsmAuthFragmentDelegate implements View.OnClickListener }); } - protected void recoverPassword() - { - mFragment.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.Url.OSM_RECOVER_PASSWORD))); - } - protected void register() { mFragment.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.Url.OSM_REGISTER))); diff --git a/android/src/com/mapswithme/maps/editor/OsmOAuth.java b/android/src/com/mapswithme/maps/editor/OsmOAuth.java index c942a2f7ec..34a4dada43 100644 --- a/android/src/com/mapswithme/maps/editor/OsmOAuth.java +++ b/android/src/com/mapswithme/maps/editor/OsmOAuth.java @@ -7,7 +7,10 @@ import android.support.annotation.Size; import android.support.annotation.WorkerThread; import android.text.TextUtils; +import java.lang.ref.WeakReference; + import com.mapswithme.maps.MwmApplication; +import com.mapswithme.maps.editor.data.UserStats; public final class OsmOAuth { @@ -44,6 +47,28 @@ public final class OsmOAuth private static final String PREF_OSM_SECRET = "OsmSecret"; private static final String PREF_OSM_USERNAME = "OsmUsername"; + public interface OnUserStatsChanged + { + void onStatsChange(UserStats stats); + } + + private static WeakReference<OnUserStatsChanged> sListener; + + public static void setUserStatsListener(OnUserStatsChanged listener) + { + sListener = new WeakReference<>(listener); + } + + // Called from native OsmOAuth.cpp. + @SuppressWarnings("unused") + public static void onUserStatsUpdated(UserStats stats) + { + if (sListener == null || sListener.get() == null) + return; + + sListener.get().onStatsChange(stats); + } + public static final String URL_PARAM_VERIFIER = "oauth_verifier"; public static boolean isAuthorized() @@ -127,4 +152,6 @@ public final class OsmOAuth @WorkerThread @Nullable public static native String nativeGetOsmUsername(String token, String secret); + + public static native void nativeUpdateOsmUserStats(String username); } diff --git a/android/src/com/mapswithme/maps/editor/ProfileFragment.java b/android/src/com/mapswithme/maps/editor/ProfileFragment.java index 85d2dc7b31..2abdbd0391 100644 --- a/android/src/com/mapswithme/maps/editor/ProfileFragment.java +++ b/android/src/com/mapswithme/maps/editor/ProfileFragment.java @@ -1,5 +1,7 @@ package com.mapswithme.maps.editor; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.format.DateUtils; @@ -10,15 +12,22 @@ import android.widget.TextView; import java.util.Locale; import com.mapswithme.maps.R; +import com.mapswithme.maps.editor.data.UserStats; +import com.mapswithme.util.Constants; import com.mapswithme.util.UiUtils; -public class ProfileFragment extends AuthFragment implements View.OnClickListener +public class ProfileFragment extends AuthFragment implements View.OnClickListener, OsmOAuth.OnUserStatsChanged { + private View mLocalBlock; private TextView mEditsLocal; + private View mSentBlock; private TextView mEditsSent; private TextView mEditsSentDate; private View mLogout; private View mAuthBlock; + private View mRatingBlock; + private TextView mEditorRank; + private TextView mEditorLevelUp; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) @@ -27,6 +36,8 @@ public class ProfileFragment extends AuthFragment implements View.OnClickListene mToolbarController.setTitle(R.string.profile); initViews(view); refreshViews(); + OsmOAuth.setUserStatsListener(this); + OsmOAuth.nativeUpdateOsmUserStats(OsmOAuth.getUsername()); } private void initViews(View view) @@ -35,37 +46,66 @@ public class ProfileFragment extends AuthFragment implements View.OnClickListene mLogout.setOnClickListener(this); View editsBlock = view.findViewById(R.id.block_edits); UiUtils.show(editsBlock); - final View localEdits = editsBlock.findViewById(R.id.local_edits); - ((ImageView) localEdits.findViewById(R.id.image)).setImageResource(R.drawable.ic_device); - mEditsLocal = (TextView) localEdits.findViewById(R.id.title); - UiUtils.hide(localEdits.findViewById(R.id.subtitle)); - final View sentEdits = editsBlock.findViewById(R.id.sent_edits); - ((ImageView) sentEdits.findViewById(R.id.image)).setImageResource(R.drawable.ic_upload); - mEditsSent = (TextView) sentEdits.findViewById(R.id.title); - mEditsSentDate = (TextView) sentEdits.findViewById(R.id.subtitle); + mLocalBlock = editsBlock.findViewById(R.id.local_edits); + ((ImageView) mLocalBlock.findViewById(R.id.image)).setImageResource(R.drawable.ic_device); + mEditsLocal = (TextView) mLocalBlock.findViewById(R.id.title); + mSentBlock = editsBlock.findViewById(R.id.sent_edits); + mEditsSent = (TextView) mSentBlock.findViewById(R.id.edits_count); + mEditsSentDate = (TextView) mSentBlock.findViewById(R.id.date_sent); mAuthBlock = view.findViewById(R.id.block_auth); - ((TextView) mAuthBlock.findViewById(R.id.first_osm_edit)).setText(R.string.login_and_edit_map_motivation_message); + mRatingBlock = view.findViewById(R.id.block_rating); + mEditorRank = (TextView) mRatingBlock.findViewById(R.id.rating); + // FIXME show when it will be implemented on server +// mEditorLevelUp = mRatingBlock.findViewById(R.id.level_up_feat); + view.findViewById(R.id.about_osm).setOnClickListener(this); } private void refreshViews() { if (OsmOAuth.isAuthorized()) { - UiUtils.show(mLogout); + UiUtils.show(mLogout, mRatingBlock, mSentBlock); UiUtils.hide(mAuthBlock); } else { UiUtils.show(mAuthBlock); - UiUtils.hide(mLogout); + UiUtils.hide(mLogout, mRatingBlock, mSentBlock); } + final long[] stats = Editor.nativeGetStats(); - mEditsLocal.setText(String.format(Locale.US, "%s %d", getString(R.string.editor_profile_unsent_changes), stats[0] - stats[1])); - mEditsSent.setText(String.format(Locale.US, "%s %d", getString(R.string.editor_profile_changes), + stats[1])); - if (stats[1] == 0) - UiUtils.hide(mEditsSentDate); + final long localCount = stats[0] - stats[1]; + if (localCount == 0) + { + UiUtils.hide(mLocalBlock); + } + else + { + UiUtils.show(mLocalBlock); + mEditsLocal.setText(String.format(Locale.US, "%s %d", getString(R.string.editor_profile_unsent_changes), localCount)); + } + + refreshRatings(0, 0, 0, ""); + } + + private void refreshRatings(long uploadedCount, long uploadMillis, long rank, String levelFeat) + { + String edits, editsDate; + + if (uploadedCount == 0) + { + edits = editsDate = "---"; + } else - UiUtils.setTextAndShow(mEditsSentDate, "Upload date : " + DateUtils.formatDateTime(getActivity(), stats[2] * 1000, 0)); + { + edits = String.valueOf(uploadedCount); + editsDate = DateUtils.formatDateTime(getActivity(), uploadMillis, 0); + } + mEditsSent.setText(edits); + mEditsSentDate.setText(String.format(Locale.US, "%s %s", getString(R.string.last_upload), editsDate)); + mEditorRank.setText(String.valueOf(rank)); + // FIXME show when it will be implemented on server +// mEditorLevelUp.setText(levelFeat); } @Override @@ -77,6 +117,21 @@ public class ProfileFragment extends AuthFragment implements View.OnClickListene OsmOAuth.clearAuthorization(); refreshViews(); break; + case R.id.about_osm: + startActivity(new Intent((Intent.ACTION_VIEW), Uri.parse(Constants.Url.OSM_ABOUT))); + break; } } + + @Override + public void onStatsChange(final UserStats stats) + { + if (!isAdded()) + return; + + if (stats == null) + refreshRatings(0, 0, 0, ""); + else + refreshRatings(stats.editsCount, stats.uploadTimestampSeconds, stats.editorRank, stats.levelUp); + } } diff --git a/android/src/com/mapswithme/maps/editor/data/UserStats.java b/android/src/com/mapswithme/maps/editor/data/UserStats.java new file mode 100644 index 0000000000..f91b92cf36 --- /dev/null +++ b/android/src/com/mapswithme/maps/editor/data/UserStats.java @@ -0,0 +1,17 @@ +package com.mapswithme.maps.editor.data; + +public class UserStats +{ + public final int editsCount; + public final int editorRank; + public final String levelUp; + public final long uploadTimestampSeconds; + + public UserStats(int editsCount, int editorRank, String levelUp, long seconds) + { + this.editsCount = editsCount; + this.editorRank = editorRank; + this.levelUp = levelUp; + this.uploadTimestampSeconds = seconds; + } +} |