From 17c4c0ca4cd61cc5a837a943dc9ccba2f96f3410 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 4 Feb 2021 19:14:51 +0300 Subject: [PATCH 01/13] Update AB test and add custom tab implementation --- app/build.gradle | 1 + .../CoursePurchaseWebviewSplitTest.kt | 11 +- .../view/base/web/CustomTabsHelper.java | 122 ++++++++++++++++++ .../view/course/ui/activity/CourseActivity.kt | 53 ++++++-- .../ui/dialog/MagicLinkDialogFragment.kt | 14 +- dependencies.gradle | 2 + 6 files changed, 185 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java diff --git a/app/build.gradle b/app/build.gradle index e5d2a7a449..31ddbdea52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -170,6 +170,7 @@ dependencies { implementation libraries.fragmentKtx implementation libraries.room kapt libraries.roomCompiler + implementation libraries.browser implementation libraries.archCompiler implementation libraries.archViewModel diff --git a/app/src/main/java/org/stepic/droid/analytic/experiments/CoursePurchaseWebviewSplitTest.kt b/app/src/main/java/org/stepic/droid/analytic/experiments/CoursePurchaseWebviewSplitTest.kt index 5d5fd06e4c..3e6575847b 100644 --- a/app/src/main/java/org/stepic/droid/analytic/experiments/CoursePurchaseWebviewSplitTest.kt +++ b/app/src/main/java/org/stepic/droid/analytic/experiments/CoursePurchaseWebviewSplitTest.kt @@ -13,13 +13,12 @@ constructor( analytic, sharedPreferenceHelper, - name = "course_purchase_webview", + name = "course_purchase_webview_2", groups = Group.values() ) { - enum class Group( - val isInAppWebViewUsed: Boolean - ) : SplitTest.Group { - Control(isInAppWebViewUsed = false), - InAppWebview(isInAppWebViewUsed = true) + enum class Group : SplitTest.Group { + Control, + InAppWebview, + ChromeTab } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java b/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java new file mode 100644 index 0000000000..b603ad13b5 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java @@ -0,0 +1,122 @@ +package org.stepik.android.view.base.web; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class for Custom Tabs. + */ +public class CustomTabsHelper { + private static final String TAG = "CustomTabsHelper"; + static final String STABLE_PACKAGE = "com.android.chrome"; + static final String BETA_PACKAGE = "com.chrome.beta"; + static final String DEV_PACKAGE = "com.chrome.dev"; + static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; + private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE = + "android.support.customtabs.extra.KEEP_ALIVE"; + private static final String ACTION_CUSTOM_TABS_CONNECTION = + "android.support.customtabs.action.CustomTabsService"; + + private static String sPackageNameToUse; + + private CustomTabsHelper() {} + + /** + * Goes through all apps that handle VIEW intents and have a warmup service. Picks + * the one chosen by the user if there is one, otherwise makes a best effort to return a + * valid package name. + * + * This is not threadsafe. + * + * @param context {@link Context} to use for accessing {@link PackageManager}. + * @return The package name recommended to use for connecting to custom tabs related components. + */ + public static String getPackageNameToUse(Context context) { + if (sPackageNameToUse != null) return sPackageNameToUse; + + PackageManager pm = context.getPackageManager(); + // Get default VIEW intent handler. + Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); + ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0); + String defaultViewHandlerPackageName = null; + if (defaultViewHandlerInfo != null) { + defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName; + } + + // Get all apps that can handle VIEW intents. + List resolvedActivityList = pm.queryIntentActivities(activityIntent, 0); + List packagesSupportingCustomTabs = new ArrayList<>(); + for (ResolveInfo info : resolvedActivityList) { + Intent serviceIntent = new Intent(); + serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION); + serviceIntent.setPackage(info.activityInfo.packageName); + if (pm.resolveService(serviceIntent, 0) != null) { + packagesSupportingCustomTabs.add(info.activityInfo.packageName); + } + } + + // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents + // and service calls. + if (packagesSupportingCustomTabs.isEmpty()) { + sPackageNameToUse = null; + } else if (packagesSupportingCustomTabs.size() == 1) { + sPackageNameToUse = packagesSupportingCustomTabs.get(0); + } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) + && !hasSpecializedHandlerIntents(context, activityIntent) + && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) { + sPackageNameToUse = defaultViewHandlerPackageName; + } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) { + sPackageNameToUse = STABLE_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) { + sPackageNameToUse = BETA_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) { + sPackageNameToUse = DEV_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) { + sPackageNameToUse = LOCAL_PACKAGE; + } + return sPackageNameToUse; + } + + /** + * Used to check whether there is a specialized handler for a given intent. + * @param intent The intent to check with. + * @return Whether there is a specialized handler for the given intent. + */ + private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) { + try { + PackageManager pm = context.getPackageManager(); + List handlers = pm.queryIntentActivities( + intent, + PackageManager.GET_RESOLVED_FILTER); + if (handlers.size() == 0) { + return false; + } + for (ResolveInfo resolveInfo : handlers) { + IntentFilter filter = resolveInfo.filter; + if (filter == null) continue; + if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue; + if (resolveInfo.activityInfo == null) continue; + return true; + } + } catch (RuntimeException e) { + Log.e(TAG, "Runtime exception while getting specialized handlers"); + } + return false; + } + + /** + * @return All possible chrome package names that provide custom tabs feature. + */ + public static String[] getPackages() { + return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE}; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt index 50dcab4751..c5e6482a5b 100644 --- a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt +++ b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt @@ -2,11 +2,13 @@ package org.stepik.android.view.course.ui.activity import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatDelegate +import androidx.browser.customtabs.CustomTabsIntent import androidx.fragment.app.DialogFragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders @@ -34,6 +36,7 @@ import org.stepic.droid.ui.dialogs.LoadingProgressDialogFragment import org.stepic.droid.ui.dialogs.UnauthorizedDialogFragment import org.stepic.droid.ui.util.snackbar import org.stepic.droid.util.ProgressHelper +import org.stepic.droid.util.resolveColorAttribute import org.stepik.android.domain.course.analytic.CourseViewSource import org.stepik.android.domain.last_step.model.LastStep import org.stepik.android.domain.purchase_notification.analytic.PurchaseNotificationClicked @@ -42,6 +45,7 @@ import org.stepik.android.presentation.course.CoursePresenter import org.stepik.android.presentation.course.CourseView import org.stepik.android.presentation.course.model.EnrollmentError import org.stepik.android.presentation.user_courses.model.UserCourseAction +import org.stepik.android.view.base.web.CustomTabsHelper import org.stepik.android.view.course.routing.CourseDeepLinkBuilder import org.stepik.android.view.course.routing.CourseScreenTab import org.stepik.android.view.course.routing.getCourseIdFromDeepLink @@ -58,7 +62,7 @@ import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.view.base.ui.extension.showIfNotExists import javax.inject.Inject -class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFragment.Callback { +class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFragment.Callback, MagicLinkDialogFragment.Callback { companion object { private const val EXTRA_COURSE = "course" private const val EXTRA_COURSE_ID = "course_id" @@ -70,6 +74,8 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra private const val UNAUTHORIZED_DIALOG_TAG = "unauthorized_dialog" + private const val CUSTOM_TAB_REQUEST_CODE = 9231 + fun createIntent(context: Context, course: Course, source: CourseViewSource, autoEnroll: Boolean = false, tab: CourseScreenTab = CourseScreenTab.INFO): Intent = Intent(context, CourseActivity::class.java) .putExtra(EXTRA_COURSE, course) @@ -239,7 +245,7 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra override fun onResume() { super.onResume() - if (!coursePurchaseWebviewSplitTest.currentGroup.isInAppWebViewUsed) { + if (coursePurchaseWebviewSplitTest.currentGroup != CoursePurchaseWebviewSplitTest.Group.InAppWebview) { coursePresenter.handleCoursePurchasePressed() } coursePager.addOnPageChangeListener(analyticsOnPageChangeListener) @@ -450,14 +456,22 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra override fun openCoursePurchaseInWeb(courseId: Long, queryParams: Map>?) { val url = courseDeeplinkBuilder.createCourseLink(courseId, CourseScreenTab.PAY, queryParams) - if (coursePurchaseWebviewSplitTest.currentGroup.isInAppWebViewUsed) { - InAppWebViewDialogFragment - .newInstance(getString(R.string.course_purchase), url, isProvideAuth = true) - .showIfNotExists(supportFragmentManager, InAppWebViewDialogFragment.TAG) - } else { - MagicLinkDialogFragment - .newInstance(url) - .showIfNotExists(supportFragmentManager, MagicLinkDialogFragment.TAG) + when (coursePurchaseWebviewSplitTest.currentGroup) { + CoursePurchaseWebviewSplitTest.Group.Control -> { + MagicLinkDialogFragment + .newInstance(url) + .showIfNotExists(supportFragmentManager, MagicLinkDialogFragment.TAG) + } + CoursePurchaseWebviewSplitTest.Group.InAppWebview -> { + InAppWebViewDialogFragment + .newInstance(getString(R.string.course_purchase), url, isProvideAuth = true) + .showIfNotExists(supportFragmentManager, InAppWebViewDialogFragment.TAG) + } + CoursePurchaseWebviewSplitTest.Group.ChromeTab -> { + MagicLinkDialogFragment + .newInstance(url, handleUrlInParent = true) + .showIfNotExists(supportFragmentManager, MagicLinkDialogFragment.TAG) + } } } @@ -466,6 +480,9 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if (requestCode == CUSTOM_TAB_REQUEST_CODE) { +// coursePresenter.handleCoursePurchasePressed() + } if (!uiCheckout.onActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data) } @@ -499,4 +516,20 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra override fun onDismissed() { coursePresenter.handleCoursePurchasePressed() } + + override fun handleUrl(url: String) { + val builder = CustomTabsIntent.Builder() + builder.setShowTitle(true) + builder.setToolbarColor(resolveColorAttribute(R.attr.colorSurface)) + val customTabsIntent = builder.build() + val packageName = CustomTabsHelper.getPackageNameToUse(this) + if (packageName == null) { + InAppWebViewDialogFragment + .newInstance(getString(R.string.course_purchase), url, isProvideAuth = false) + .showIfNotExists(supportFragmentManager, InAppWebViewDialogFragment.TAG) + } else { + customTabsIntent.intent.`package` = packageName + customTabsIntent.launchUrl(this, Uri.parse(url)) + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/magic_links/ui/dialog/MagicLinkDialogFragment.kt b/app/src/main/java/org/stepik/android/view/magic_links/ui/dialog/MagicLinkDialogFragment.kt index c54234686e..0fda11a4b7 100644 --- a/app/src/main/java/org/stepik/android/view/magic_links/ui/dialog/MagicLinkDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/magic_links/ui/dialog/MagicLinkDialogFragment.kt @@ -17,10 +17,11 @@ import javax.inject.Inject class MagicLinkDialogFragment : DialogFragment(), MagicLinkView { companion object { - fun newInstance(url: String): DialogFragment = + fun newInstance(url: String, handleUrlInParent: Boolean = false): DialogFragment = MagicLinkDialogFragment() .apply { this.url = url + this.returnUrlToParent = handleUrlInParent } const val TAG = "MagicLinkDialogFragment" @@ -32,6 +33,7 @@ class MagicLinkDialogFragment : DialogFragment(), MagicLinkView { private val magicLinkPresenter: MagicLinkPresenter by viewModels { viewModelFactory } private var url: String by argument() + private var returnUrlToParent: Boolean by argument() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { isCancelable = false @@ -63,7 +65,11 @@ class MagicLinkDialogFragment : DialogFragment(), MagicLinkView { override fun setState(state: MagicLinkView.State) { if (state is MagicLinkView.State.Success) { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(state.url))) + if (returnUrlToParent) { + (activity as Callback).handleUrl(state.url) + } else { + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(state.url))) + } dismiss() } } @@ -72,4 +78,8 @@ class MagicLinkDialogFragment : DialogFragment(), MagicLinkView { magicLinkPresenter.detachView(this) super.onStop() } + + interface Callback { + fun handleUrl(url: String) + } } \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index 442dcbf64c..4809159572 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -32,6 +32,7 @@ ext.versions = [ material : '1.1.0', fragment : '1.2.5', room : '2.2.5', + browser : '1.3.0', archComponents : '2.2.0', media : '1.1.0', @@ -149,6 +150,7 @@ ext.libraries = [ fragmentKtx : "androidx.fragment:fragment-ktx:$versions.fragment", room : "androidx.room:room-runtime:$versions.room", roomCompiler : "androidx.room:room-compiler:$versions.room", + browser : "androidx.browser:browser:$versions.browser", archCompiler : "androidx.lifecycle:lifecycle-common-java8:$versions.archComponents", archViewModel : "androidx.lifecycle:lifecycle-viewmodel-ktx:$versions.archComponents", From d95b279d39ea60c3edef15c9c01f4c5318b904d8 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 11:45:21 +0300 Subject: [PATCH 02/13] Fix item visibility --- .../view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt index 63aac4dfa4..729e6b41de 100644 --- a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt @@ -12,6 +12,7 @@ import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.stories.model.Story import ru.nobird.android.ui.adapterdelegates.AdapterDelegate import ru.nobird.android.ui.adapterdelegates.DelegateViewHolder +import timber.log.Timber class StoriesAdapterDelegate( private val onStoryClicked: (Story, Int) -> Unit @@ -49,6 +50,7 @@ class StoriesAdapterDelegate( viewStateDelegate.switchState(state) if (state is StoriesFeature.State.Success) { storiesAdapter.setData(state.stories, state.viewedStoriesIds) + storiesAdapter.selected = -1 } } } From bf4d48a91c4d658a792871a26bd70de1113cd23b Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 13:10:33 +0300 Subject: [PATCH 03/13] Add achievement analytics --- .../stepic/droid/analytic/AmplitudeAnalytic.kt | 17 +++++++++++++++++ .../stepic/droid/core/ScreenManagerImpl.java | 5 +++++ .../ui/dialog/AchievementDetailsDialog.kt | 17 ++++++++++++++++- .../ui/fragment/AchievementsListFragment.kt | 15 ++++++++++++++- .../ui/fragment/ProfileAchievementsFragment.kt | 15 ++++++++++++++- 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt index ad55f8a01f..18ea8b1bac 100644 --- a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt +++ b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt @@ -191,9 +191,26 @@ interface AmplitudeAnalytic { object Achievements { const val NOTIFICATION_RECEIVED = "Achievement notification received" + const val SCREEN_OPENED = "Achievements screen opened" + const val POPUP_OPENED = "Achievement popup opened" + const val SHARE_PRESSED = "Achievement share pressed" + object Params { const val KIND = "achievement_kind" const val LEVEL = "achievement_level" + + const val IS_PERSONAL = "is_personal" + + const val SOURCE = "source" + } + + object Values { + /*** + * Source + */ + const val PROFILE = "profile" + const val ACHIEVEMENT_LIST = "achievement-list" + const val NOTIFICATION = "notification" } } diff --git a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java index 0890710bf4..f13289e577 100644 --- a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java +++ b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java @@ -91,7 +91,9 @@ import java.io.File; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import javax.inject.Inject; @@ -596,6 +598,9 @@ public void openRemindPassword(AppCompatActivity context) { @Override public void showAchievementsList(Context context, long userId, boolean isMyProfile) { Intent intent = AchievementsListActivity.Companion.createIntent(context, userId, isMyProfile); + Map params = new HashMap<>(); + params.put(AmplitudeAnalytic.Achievements.Params.IS_PERSONAL, isMyProfile); + analytic.reportAmplitudeEvent(AmplitudeAnalytic.Achievements.SCREEN_OPENED, params); context.startActivity(intent); } diff --git a/app/src/main/java/org/stepik/android/view/achievement/ui/dialog/AchievementDetailsDialog.kt b/app/src/main/java/org/stepik/android/view/achievement/ui/dialog/AchievementDetailsDialog.kt index b0ebea39f8..11dcc13ce0 100644 --- a/app/src/main/java/org/stepik/android/view/achievement/ui/dialog/AchievementDetailsDialog.kt +++ b/app/src/main/java/org/stepik/android/view/achievement/ui/dialog/AchievementDetailsDialog.kt @@ -10,6 +10,8 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.android.synthetic.main.dialog_achievement_details.view.* import org.stepic.droid.R +import org.stepic.droid.analytic.AmplitudeAnalytic +import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App import org.stepik.android.view.glide.ui.extension.wrapWithGlide import org.stepik.android.domain.achievement.model.AchievementItem @@ -21,19 +23,24 @@ class AchievementDetailsDialog : DialogFragment() { companion object { const val TAG = "achievement_details_dialog" - fun newInstance(achievementItem: AchievementItem, canShareAchievement: Boolean): AchievementDetailsDialog = + fun newInstance(achievementItem: AchievementItem, canShareAchievement: Boolean, source: String): AchievementDetailsDialog = AchievementDetailsDialog() .apply { this.achievementItem = achievementItem this.canShare = canShareAchievement + this.source = source } } + @Inject + lateinit var analytic: Analytic + @Inject lateinit var achievementResourceResolver: AchievementResourceResolver private var achievementItem: AchievementItem by argument() private var canShare: Boolean by argument() + private var source: String by argument() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -95,6 +102,14 @@ class AchievementDetailsDialog : DialogFragment() { } private fun shareAchievement() { + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.Achievements.SHARE_PRESSED, + mapOf( + AmplitudeAnalytic.Achievements.Params.SOURCE to source, + AmplitudeAnalytic.Achievements.Params.KIND to achievementItem.kind, + AmplitudeAnalytic.Achievements.Params.LEVEL to achievementItem.currentLevel + ) + ) val intent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, getString(R.string.achievement_share, achievementResourceResolver.resolveTitleForKind(achievementItem.kind))) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) diff --git a/app/src/main/java/org/stepik/android/view/achievement/ui/fragment/AchievementsListFragment.kt b/app/src/main/java/org/stepik/android/view/achievement/ui/fragment/AchievementsListFragment.kt index 87350411c5..b0c85fbc76 100644 --- a/app/src/main/java/org/stepik/android/view/achievement/ui/fragment/AchievementsListFragment.kt +++ b/app/src/main/java/org/stepik/android/view/achievement/ui/fragment/AchievementsListFragment.kt @@ -13,6 +13,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.synthetic.main.error_no_connection_with_button.* import kotlinx.android.synthetic.main.fragment_achievements_list.* import org.stepic.droid.R +import org.stepic.droid.analytic.AmplitudeAnalytic +import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App import org.stepic.droid.ui.util.initCenteredToolbar import org.stepik.android.domain.achievement.model.AchievementItem @@ -36,6 +38,9 @@ class AchievementsListFragment : Fragment(), AchievementsView { } } + @Inject + internal lateinit var analytic: Analytic + @Inject internal lateinit var viewModelFactory: ViewModelProvider.Factory @@ -106,8 +111,16 @@ class AchievementsListFragment : Fragment(), AchievementsView { } private fun onAchievementClicked(item: AchievementItem) { + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.Achievements.POPUP_OPENED, + mapOf( + AmplitudeAnalytic.Achievements.Params.SOURCE to AmplitudeAnalytic.Achievements.Values.ACHIEVEMENT_LIST, + AmplitudeAnalytic.Achievements.Params.KIND to item.kind, + AmplitudeAnalytic.Achievements.Params.LEVEL to item.currentLevel + ) + ) AchievementDetailsDialog - .newInstance(item, isMyProfile) + .newInstance(item, isMyProfile, AmplitudeAnalytic.Achievements.Values.ACHIEVEMENT_LIST) .showIfNotExists(childFragmentManager, AchievementDetailsDialog.TAG) } diff --git a/app/src/main/java/org/stepik/android/view/profile_achievements/ui/fragment/ProfileAchievementsFragment.kt b/app/src/main/java/org/stepik/android/view/profile_achievements/ui/fragment/ProfileAchievementsFragment.kt index e758d778e4..e6f0cbc4e9 100644 --- a/app/src/main/java/org/stepik/android/view/profile_achievements/ui/fragment/ProfileAchievementsFragment.kt +++ b/app/src/main/java/org/stepik/android/view/profile_achievements/ui/fragment/ProfileAchievementsFragment.kt @@ -10,6 +10,8 @@ import androidx.recyclerview.widget.GridLayoutManager import kotlinx.android.synthetic.main.error_no_connection_with_button_small.* import kotlinx.android.synthetic.main.fragment_profile_achievements.* import org.stepic.droid.R +import org.stepic.droid.analytic.AmplitudeAnalytic +import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App import org.stepic.droid.core.ScreenManager import org.stepik.android.domain.achievement.model.AchievementItem @@ -35,6 +37,9 @@ class ProfileAchievementsFragment : Fragment(R.layout.fragment_profile_achieveme } } + @Inject + internal lateinit var analytic: Analytic + @Inject internal lateinit var viewModelFactory: ViewModelProvider.Factory @@ -120,8 +125,16 @@ class ProfileAchievementsFragment : Fragment(R.layout.fragment_profile_achieveme } private fun onAchievementClicked(item: AchievementItem) { + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.Achievements.POPUP_OPENED, + mapOf( + AmplitudeAnalytic.Achievements.Params.SOURCE to AmplitudeAnalytic.Achievements.Values.PROFILE, + AmplitudeAnalytic.Achievements.Params.KIND to item.kind, + AmplitudeAnalytic.Achievements.Params.LEVEL to item.currentLevel + ) + ) AchievementDetailsDialog - .newInstance(item, canShareAchievement = isMyProfile) + .newInstance(item, canShareAchievement = isMyProfile, AmplitudeAnalytic.Achievements.Values.PROFILE) .showIfNotExists(childFragmentManager, AchievementDetailsDialog.TAG) } From 8cb6b49c3a52b4a20e6fefbab5047f7ea966a500 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 14:07:24 +0300 Subject: [PATCH 04/13] Add remaining events --- .../droid/analytic/AmplitudeAnalytic.kt | 34 +++++++++++++++++++ .../stepic/droid/core/ScreenManagerImpl.java | 2 ++ .../view/course/ui/activity/CourseActivity.kt | 21 ++++++++---- .../view/lesson/ui/activity/LessonActivity.kt | 5 +++ .../view/step/ui/fragment/StepFragment.kt | 4 +++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt index 18ea8b1bac..28361bd546 100644 --- a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt +++ b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt @@ -324,4 +324,38 @@ interface AmplitudeAnalytic { const val REVIEW_START_REVIEW = "Review Start Review" const val REVIEW_VIEW_REVIEW = "Review View Review" } + + object Settings { + const val SCREEN_OPENED = "Settings screen opened" + } + + object Sections { + const val SCREEN_OPENED = "Sections screen opened" + + object Params { + const val COURSE = "course" + const val TITLE = "title" + } + } + + object Discussions { + const val SCREEN_OPENED = "Discussions screen opened" + + object Params { + const val SOURCE = "source" + } + + object Values { + /*** + * Source + */ + const val DISCUSSION = "discussion" + const val REPLY = "reply" + const val DEFAULT = "default" + } + } + + object Certificates { + const val SCREEN_OPENED = "Certificates screen opened" + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java index f13289e577..26e6cdd276 100644 --- a/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java +++ b/app/src/main/java/org/stepic/droid/core/ScreenManagerImpl.java @@ -276,6 +276,7 @@ public void showCertificates(Context context) { @Override public void showCertificates(Context context, long userId) { analytic.reportEvent(Analytic.Screens.USER_OPEN_CERTIFICATES, userId + ""); + analytic.reportAmplitudeEvent(AmplitudeAnalytic.Certificates.SCREEN_OPENED); Intent intent = CertificatesActivity.Companion.createIntent(context, userId); context.startActivity(intent); } @@ -361,6 +362,7 @@ public void showVideo(@NotNull Fragment sourceFragment, @NotNull VideoPlayerMedi @Override public void showSettings(Activity sourceActivity) { analytic.reportEvent(Analytic.Screens.SHOW_SETTINGS); + analytic.reportAmplitudeEvent(AmplitudeAnalytic.Settings.SCREEN_OPENED); Intent intent = new Intent(sourceActivity, SettingsActivity.class); sourceActivity.startActivity(intent); sourceActivity.overridePendingTransition(org.stepic.droid.R.anim.push_up, org.stepic.droid.R.anim.no_transition); diff --git a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt index 50dcab4751..fcb30d39e8 100644 --- a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt +++ b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt @@ -50,6 +50,7 @@ import org.stepik.android.view.course.routing.getPromoCodeFromDeepLink import org.stepik.android.view.course.ui.adapter.CoursePagerAdapter import org.stepik.android.view.course.ui.delegates.CourseHeaderDelegate import org.stepik.android.view.course_content.ui.fragment.CourseContentFragment +import org.stepik.android.view.course_reviews.ui.fragment.CourseReviewsFragment import org.stepik.android.view.fragment_pager.FragmentDelegateScrollStateChangeListener import org.stepik.android.view.in_app_web_view.ui.dialog.InAppWebViewDialogFragment import org.stepik.android.view.magic_links.ui.dialog.MagicLinkDialogFragment @@ -91,12 +92,20 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra private var courseId: Long = NO_ID private val analyticsOnPageChangeListener = object : ViewPager.SimpleOnPageChangeListener() { override fun onPageSelected(page: Int) { - if (coursePagerAdapter.getItem(page) is CourseContentFragment) { - analytic - .reportAmplitudeEvent( - AmplitudeAnalytic.CourseReview.SCREEN_OPENED, - mapOf(AmplitudeAnalytic.CourseReview.Params.COURSE to courseId.toString()) - ) + when (coursePagerAdapter.getItem(page)) { + is CourseReviewsFragment -> + analytic + .reportAmplitudeEvent( + AmplitudeAnalytic.CourseReview.SCREEN_OPENED, + mapOf(AmplitudeAnalytic.CourseReview.Params.COURSE to courseId.toString()) + ) + + is CourseContentFragment -> + analytic + .reportAmplitudeEvent( + AmplitudeAnalytic.Sections.SCREEN_OPENED, + mapOf(AmplitudeAnalytic.Sections.Params.COURSE to courseId.toString()) + ) } } } diff --git a/app/src/main/java/org/stepik/android/view/lesson/ui/activity/LessonActivity.kt b/app/src/main/java/org/stepik/android/view/lesson/ui/activity/LessonActivity.kt index 47b3ece40b..fa247fc66b 100644 --- a/app/src/main/java/org/stepik/android/view/lesson/ui/activity/LessonActivity.kt +++ b/app/src/main/java/org/stepik/android/view/lesson/ui/activity/LessonActivity.kt @@ -26,6 +26,7 @@ import kotlinx.android.synthetic.main.error_no_connection_with_button.* import kotlinx.android.synthetic.main.layout_step_tab_icon.view.* import kotlinx.android.synthetic.main.view_subtitled_toolbar.* import org.stepic.droid.R +import org.stepic.droid.analytic.AmplitudeAnalytic import org.stepic.droid.analytic.Analytic import org.stepic.droid.base.App import org.stepic.droid.base.FragmentActivityBase @@ -403,6 +404,10 @@ class LessonActivity : FragmentActivityBase(), LessonView, override fun showComments(step: Step, discussionId: Long, discussionThread: DiscussionThread?) { if (discussionThread != null) { + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.Discussions.SCREEN_OPENED, + mapOf(AmplitudeAnalytic.Discussions.Params.SOURCE to AmplitudeAnalytic.Discussions.Values.DISCUSSION) + ) screenManager.openComments(this, discussionThread, step, discussionId, false) } else { analytic.reportEvent(Analytic.Screens.OPEN_COMMENT_NOT_AVAILABLE) diff --git a/app/src/main/java/org/stepik/android/view/step/ui/fragment/StepFragment.kt b/app/src/main/java/org/stepik/android/view/step/ui/fragment/StepFragment.kt index 307f040c3c..402e45be9e 100644 --- a/app/src/main/java/org/stepik/android/view/step/ui/fragment/StepFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step/ui/fragment/StepFragment.kt @@ -122,6 +122,10 @@ class StepFragment : Fragment(R.layout.fragment_step), StepView, stepNavigationDelegate = StepNavigationDelegate(stepNavigation) { stepPresenter.onStepDirectionClicked(it) } stepDiscussionsDelegate = StepDiscussionsDelegate(view) { discussionThread -> + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.Discussions.SCREEN_OPENED, + mapOf(AmplitudeAnalytic.Discussions.Params.SOURCE to AmplitudeAnalytic.Discussions.Values.DEFAULT) + ) screenManager .openComments( activity, From d8817607166f2de8679977a198cf368c814b8dca Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 17:33:50 +0300 Subject: [PATCH 05/13] Add view all card --- .../course_list/model/CourseListItem.kt | 2 ++ .../mapper/CourseListUserStateMapper.kt | 3 ++ .../delegate/CourseListAdapterDelegate.kt | 15 +++++++- .../CourseListViewAllAdapterDelegate.kt | 36 +++++++++++++++++++ .../main/res/layout/item_course_view_all.xml | 24 +++++++++++++ app/src/main/res/values-be/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- 7 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt create mode 100644 app/src/main/res/layout/item_course_view_all.xml diff --git a/app/src/main/java/org/stepik/android/domain/course_list/model/CourseListItem.kt b/app/src/main/java/org/stepik/android/domain/course_list/model/CourseListItem.kt index 0a237f7997..8e4a84b11c 100644 --- a/app/src/main/java/org/stepik/android/domain/course_list/model/CourseListItem.kt +++ b/app/src/main/java/org/stepik/android/domain/course_list/model/CourseListItem.kt @@ -17,4 +17,6 @@ sealed class CourseListItem { } class PlaceHolder(val courseId: Long = -1) : CourseListItem() + + object ViewAll : CourseListItem() } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt b/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt index 9e9fac0779..0ed3f86346 100644 --- a/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt +++ b/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt @@ -74,6 +74,9 @@ constructor( is CourseListItem.PlaceHolder -> it.courseId + + else -> + null } } ?.let { lastCourseId -> diff --git a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/CourseListAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/CourseListAdapterDelegate.kt index 6a61442628..8ebeae525c 100644 --- a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/CourseListAdapterDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/CourseListAdapterDelegate.kt @@ -22,6 +22,7 @@ import org.stepik.android.view.catalog.model.CatalogItem import org.stepik.android.view.catalog.ui.delegate.CatalogBlockHeaderDelegate import org.stepik.android.view.course_list.ui.adapter.delegate.CourseListItemAdapterDelegate import org.stepik.android.view.course_list.ui.adapter.delegate.CourseListPlaceHolderAdapterDelegate +import org.stepik.android.view.course_list.ui.adapter.delegate.CourseListViewAllAdapterDelegate import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.core.model.safeCast import ru.nobird.android.ui.adapterdelegates.AdapterDelegate @@ -48,6 +49,7 @@ class CourseListAdapterDelegate( private inner class CourseCollectionViewHolder(root: View) : DelegateViewHolder(root) { private var catalogBlock: CatalogBlock? = null + private var courseCount: Int? = null private val courseListCoursesRecycler = root.courseListCoursesRecycler private val courseListTitleContainer = root.catalogBlockContainer @@ -79,6 +81,10 @@ class CourseListAdapterDelegate( }, isHandleInAppPurchase = isHandleInAppPurchase ) + courseItemAdapter += CourseListViewAllAdapterDelegate { + val block = (catalogBlock?.content as? CatalogBlockContent.FullCourseList) ?: return@CourseListViewAllAdapterDelegate + onTitleClick(block.courseList.id) + } with(courseListCoursesRecycler) { adapter = courseItemAdapter @@ -106,6 +112,7 @@ class CourseListAdapterDelegate( ?.let { val countString = courseCountMapper.mapCourseCountToString(context, it.courseList.coursesCount) catalogBlockTitleDelegate.setCount(countString) + courseCount = it.courseList.coursesCount } render(catalogBlockCourseListItem.state) } @@ -122,7 +129,13 @@ class CourseListAdapterDelegate( } is CourseListFeature.State.Content -> { - courseItemAdapter.items = state.courseListItems + courseItemAdapter.items = courseCount?.let { + if (it > state.courseListItems.size) { + state.courseListItems + CourseListItem.ViewAll + } else { + state.courseListItems + } + } ?: state.courseListItems } else -> diff --git a/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt new file mode 100644 index 0000000000..dde3440143 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt @@ -0,0 +1,36 @@ +package org.stepik.android.view.course_list.ui.adapter.delegate + +import android.content.res.ColorStateList +import android.view.View +import android.view.ViewGroup +import androidx.core.widget.TextViewCompat +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.item_course_view_all.* +import org.stepic.droid.R +import org.stepic.droid.util.resolveColorAttribute +import org.stepik.android.domain.course_list.model.CourseListItem +import ru.nobird.android.ui.adapterdelegates.AdapterDelegate +import ru.nobird.android.ui.adapterdelegates.DelegateViewHolder + +class CourseListViewAllAdapterDelegate( + private val onViewClick: () -> Unit +) : AdapterDelegate>() { + override fun isForViewType(position: Int, data: CourseListItem): Boolean = + data is CourseListItem.ViewAll + + override fun onCreateViewHolder(parent: ViewGroup): DelegateViewHolder = + ViewHolder(createView(parent, R.layout.item_course_view_all)) + + private inner class ViewHolder( + override val containerView: View + ) : DelegateViewHolder(containerView), LayoutContainer { + + init { + containerView.setOnClickListener { onViewClick() } + } + + override fun onBind(data: CourseListItem) { + TextViewCompat.setCompoundDrawableTintList(viewAllText, ColorStateList.valueOf(viewAllText.context.resolveColorAttribute(R.attr.colorPrimary))) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_course_view_all.xml b/app/src/main/res/layout/item_course_view_all.xml new file mode 100644 index 0000000000..6deded1ecb --- /dev/null +++ b/app/src/main/res/layout/item_course_view_all.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index cd66eabbda..8a98dc0ec0 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -371,7 +371,7 @@ Выява апошняга кроку Мае курсы Папулярныя - Усе + Паглядзець усе " праз сацыяльныя сеткі" Уваход праз сацсеткі Яшчэ diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7f722fe4b6..5ff003ceeb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -392,7 +392,7 @@ Изображение последнего шага Мои курсы Популярные - Все + Посмотреть все " через социальные сети" Вход через соцсети From 0555e3e4ab403c79c11f7a20b3003b3e0fa704bf Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 17:52:56 +0300 Subject: [PATCH 06/13] Remove logs --- .../view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt index 729e6b41de..db209d812f 100644 --- a/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/catalog/ui/adapter/delegate/StoriesAdapterDelegate.kt @@ -12,7 +12,6 @@ import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.stories.model.Story import ru.nobird.android.ui.adapterdelegates.AdapterDelegate import ru.nobird.android.ui.adapterdelegates.DelegateViewHolder -import timber.log.Timber class StoriesAdapterDelegate( private val onStoryClicked: (Story, Int) -> Unit From f0a0cad8db1e26f676047b0e58d7f3c86812252e Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 18:44:58 +0300 Subject: [PATCH 07/13] Remove unused code --- .../stepik/android/view/course/ui/activity/CourseActivity.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt index c5e6482a5b..ced3ceb563 100644 --- a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt +++ b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt @@ -74,8 +74,6 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra private const val UNAUTHORIZED_DIALOG_TAG = "unauthorized_dialog" - private const val CUSTOM_TAB_REQUEST_CODE = 9231 - fun createIntent(context: Context, course: Course, source: CourseViewSource, autoEnroll: Boolean = false, tab: CourseScreenTab = CourseScreenTab.INFO): Intent = Intent(context, CourseActivity::class.java) .putExtra(EXTRA_COURSE, course) @@ -480,9 +478,6 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == CUSTOM_TAB_REQUEST_CODE) { -// coursePresenter.handleCoursePurchasePressed() - } if (!uiCheckout.onActivityResult(requestCode, resultCode, data)) { super.onActivityResult(requestCode, resultCode, data) } From 53ce91dbeca5ca996916a238f722298b829fc6ff Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 20:30:46 +0300 Subject: [PATCH 08/13] Outline button --- .../CourseListViewAllAdapterDelegate.kt | 2 +- .../main/res/layout/item_course_view_all.xml | 30 ++++++++----------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt index dde3440143..e0bd21b84a 100644 --- a/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt @@ -30,7 +30,7 @@ class CourseListViewAllAdapterDelegate( } override fun onBind(data: CourseListItem) { - TextViewCompat.setCompoundDrawableTintList(viewAllText, ColorStateList.valueOf(viewAllText.context.resolveColorAttribute(R.attr.colorPrimary))) + TextViewCompat.setCompoundDrawableTintList(viewAllButton, ColorStateList.valueOf(viewAllButton.context.resolveColorAttribute(R.attr.colorPrimary))) } } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_course_view_all.xml b/app/src/main/res/layout/item_course_view_all.xml index 6deded1ecb..a9879a4d2e 100644 --- a/app/src/main/res/layout/item_course_view_all.xml +++ b/app/src/main/res/layout/item_course_view_all.xml @@ -1,24 +1,18 @@ - - - - - \ No newline at end of file + android:gravity="center" + android:text="@string/view_all_courses" + android:textAppearance="?textAppearanceBody1" + android:theme="@style/ThemeOverlay.Violet" + app:cornerRadius="@dimen/course_item_radius" + app:icon="@drawable/ic_arrow_forward" + app:iconGravity="textEnd" + app:iconPadding="8dp" + tools:text="@string/view_all_courses" /> \ No newline at end of file From 4358d788eb2b2d9b3e277ac770504fc94f79a809 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 8 Feb 2021 20:32:45 +0300 Subject: [PATCH 09/13] Add fallback analytics --- .../main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt | 4 ++++ .../stepik/android/view/course/ui/activity/CourseActivity.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt index ad55f8a01f..e7ace9f9f5 100644 --- a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt +++ b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt @@ -307,4 +307,8 @@ interface AmplitudeAnalytic { const val REVIEW_START_REVIEW = "Review Start Review" const val REVIEW_VIEW_REVIEW = "Review View Review" } + + object ChromeTab { + const val FALLBACK_USED = "Chrome Tab Fallback Used" + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt index ced3ceb563..393de8896d 100644 --- a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt +++ b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt @@ -519,6 +519,7 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra val customTabsIntent = builder.build() val packageName = CustomTabsHelper.getPackageNameToUse(this) if (packageName == null) { + analytic.reportAmplitudeEvent(AmplitudeAnalytic.ChromeTab.FALLBACK_USED) InAppWebViewDialogFragment .newInstance(getString(R.string.course_purchase), url, isProvideAuth = false) .showIfNotExists(supportFragmentManager, InAppWebViewDialogFragment.TAG) From 208e1f8d36b2b71451e97c5634fda9f5c1886cfc Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 9 Feb 2021 14:20:10 +0300 Subject: [PATCH 10/13] PR fixes --- .../course_list/mapper/CourseListUserStateMapper.kt | 2 +- .../adapter/delegate/CourseListViewAllAdapterDelegate.kt | 9 --------- app/src/main/res/layout/item_course_view_all.xml | 1 + 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt b/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt index 0ed3f86346..aa6852598b 100644 --- a/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt +++ b/app/src/main/java/org/stepik/android/presentation/course_list/mapper/CourseListUserStateMapper.kt @@ -75,7 +75,7 @@ constructor( is CourseListItem.PlaceHolder -> it.courseId - else -> + is CourseListItem.ViewAll -> null } } diff --git a/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt index e0bd21b84a..d2cba5af22 100644 --- a/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/course_list/ui/adapter/delegate/CourseListViewAllAdapterDelegate.kt @@ -1,13 +1,9 @@ package org.stepik.android.view.course_list.ui.adapter.delegate -import android.content.res.ColorStateList import android.view.View import android.view.ViewGroup -import androidx.core.widget.TextViewCompat import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.item_course_view_all.* import org.stepic.droid.R -import org.stepic.droid.util.resolveColorAttribute import org.stepik.android.domain.course_list.model.CourseListItem import ru.nobird.android.ui.adapterdelegates.AdapterDelegate import ru.nobird.android.ui.adapterdelegates.DelegateViewHolder @@ -24,13 +20,8 @@ class CourseListViewAllAdapterDelegate( private inner class ViewHolder( override val containerView: View ) : DelegateViewHolder(containerView), LayoutContainer { - init { containerView.setOnClickListener { onViewClick() } } - - override fun onBind(data: CourseListItem) { - TextViewCompat.setCompoundDrawableTintList(viewAllButton, ColorStateList.valueOf(viewAllButton.context.resolveColorAttribute(R.attr.colorPrimary))) - } } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_course_view_all.xml b/app/src/main/res/layout/item_course_view_all.xml index a9879a4d2e..8c128fd600 100644 --- a/app/src/main/res/layout/item_course_view_all.xml +++ b/app/src/main/res/layout/item_course_view_all.xml @@ -15,4 +15,5 @@ app:icon="@drawable/ic_arrow_forward" app:iconGravity="textEnd" app:iconPadding="8dp" + app:iconTint="?colorPrimary" tools:text="@string/view_all_courses" /> \ No newline at end of file From b0639803baf5fbe9215f7b76e27aaa2543b7fd79 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 9 Feb 2021 19:37:05 +0300 Subject: [PATCH 11/13] Fix pmd --- .../stepik/android/view/base/web/CustomTabsHelper.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java b/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java index b603ad13b5..1b5e83aaab 100644 --- a/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java +++ b/app/src/main/java/org/stepik/android/view/base/web/CustomTabsHelper.java @@ -15,7 +15,7 @@ /** * Helper class for Custom Tabs. */ -public class CustomTabsHelper { +public final class CustomTabsHelper { private static final String TAG = "CustomTabsHelper"; static final String STABLE_PACKAGE = "com.android.chrome"; static final String BETA_PACKAGE = "com.chrome.beta"; @@ -112,11 +112,4 @@ private static boolean hasSpecializedHandlerIntents(Context context, Intent inte } return false; } - - /** - * @return All possible chrome package names that provide custom tabs feature. - */ - public static String[] getPackages() { - return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE}; - } } \ No newline at end of file From 9e6d1285c6a48cee73e4163a96e1bc57c75c440f Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 9 Feb 2021 20:11:09 +0300 Subject: [PATCH 12/13] Update analytic and remove deprecated function --- .../org/stepic/droid/analytic/AmplitudeAnalytic.kt | 6 +++++- .../view/course/ui/activity/CourseActivity.kt | 13 +++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt index e7ace9f9f5..35a63de5b0 100644 --- a/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt +++ b/app/src/main/java/org/stepic/droid/analytic/AmplitudeAnalytic.kt @@ -309,6 +309,10 @@ interface AmplitudeAnalytic { } object ChromeTab { - const val FALLBACK_USED = "Chrome Tab Fallback Used" + const val CHROME_TAB_OPENED = "Chrome tab opened" + + object Params { + const val FALLBACK = "fallback" + } } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt index 393de8896d..24d68b49a9 100644 --- a/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt +++ b/app/src/main/java/org/stepik/android/view/course/ui/activity/CourseActivity.kt @@ -8,6 +8,7 @@ import android.view.Menu import android.view.MenuItem import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatDelegate +import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent import androidx.fragment.app.DialogFragment import androidx.lifecycle.ViewModelProvider @@ -515,11 +516,19 @@ class CourseActivity : FragmentActivityBase(), CourseView, InAppWebViewDialogFra override fun handleUrl(url: String) { val builder = CustomTabsIntent.Builder() builder.setShowTitle(true) - builder.setToolbarColor(resolveColorAttribute(R.attr.colorSurface)) + builder.setDefaultColorSchemeParams( + CustomTabColorSchemeParams.Builder() + .setToolbarColor(resolveColorAttribute(R.attr.colorSurface)) + .setSecondaryToolbarColor(resolveColorAttribute(R.attr.colorSurface)) + .build() + ) val customTabsIntent = builder.build() val packageName = CustomTabsHelper.getPackageNameToUse(this) + analytic.reportAmplitudeEvent( + AmplitudeAnalytic.ChromeTab.CHROME_TAB_OPENED, + mapOf(AmplitudeAnalytic.ChromeTab.Params.FALLBACK to (packageName == null)) + ) if (packageName == null) { - analytic.reportAmplitudeEvent(AmplitudeAnalytic.ChromeTab.FALLBACK_USED) InAppWebViewDialogFragment .newInstance(getString(R.string.course_purchase), url, isProvideAuth = false) .showIfNotExists(supportFragmentManager, InAppWebViewDialogFragment.TAG) From 2f1419ada55d12a3975a53454f6d41e38a6f7063 Mon Sep 17 00:00:00 2001 From: Stepik Bot Date: Wed, 10 Feb 2021 03:01:18 +0000 Subject: [PATCH 13/13] "inc version to 2192" --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 4809159572..184453829c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,6 +1,6 @@ ext.versions = [ - code : 2191, - name : '1.159', + code : 2192, + name : '1.160', minSdk : 16, targetSdk : 29,