Skip to content

Commit

Permalink
Fix part of #5025: App and OS Deprecation Milestone 3 - Add New Depre…
Browse files Browse the repository at this point in the history
…cation Dialog Fragments (#5096)

<!-- READ ME FIRST: Please fill in the explanation section below and
check off every point from the Essential Checklist! -->
## Explanation
<!--
- Explain what your PR does. If this PR fixes an existing bug, please
include
- "Fixes #bugnum:" in the explanation so that GitHub can auto-close the
issue
  - when this PR is merged.
  -->
Fix part of #5025 
When this PR is merged, it will;
- Add fragments and fragment presenters for the Forced, Optional, and OS
deprecation dialogs.
- Add strings for the new deprecation dialogs.

## Screenshots of the introduced dialog fragments

Forced Deprecation Dialog | Optional Deprecation Dialog | OS Deprecation
Dialog

:-------------------------:|:-------------------------:|:-------------------------:
![A screenshot of the forced deprecation
dialog](https://github.com/oppia/oppia-android/assets/18438114/33808235-7867-458b-aa99-bb1166511121)
| ![A screenshot of the optional deprecation
dialog](https://github.com/oppia/oppia-android/assets/18438114/84e0ffc1-f1ea-49e0-a997-1871aed0134f)
| ![A screenshot of the OS deprecation
dialog](https://github.com/oppia/oppia-android/assets/18438114/fe4fd5dc-5461-4d12-99d7-8eb3c9160aaf)


## Videos of the dialogs in action
### Forced Deprecation Dialog

https://github.com/oppia/oppia-android/assets/18438114/45e8319b-89dd-479a-a41d-5c458707ea50

### Optional Deprecation Dialog

https://github.com/oppia/oppia-android/assets/18438114/32343ff1-34be-4c53-bb64-a4624a15ea86

### OS Deprecation Dialog

https://github.com/oppia/oppia-android/assets/18438114/7d289d25-b7ba-4362-8c4f-a2f8a27f8e63


## Essential Checklist
<!-- Please tick the relevant boxes by putting an "x" in them. -->
- [x] The PR title and explanation each start with "Fix #bugnum: " (If
this PR fixes part of an issue, prefix the title with "Fix part of
#bugnum: ...".)
- [x] Any changes to
[scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets)
files have their rationale included in the PR explanation.
- [x] The PR follows the [style
guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide).
- [x] The PR does not contain any unnecessary code changes from Android
Studio
([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)).
- [x] The PR is made from a branch that's **not** called "develop" and
is up-to-date with "develop".
- [x] The PR is **assigned** to the appropriate reviewers
([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)).

## For UI-specific PRs only
<!-- Delete these section if this PR does not include UI-related
changes. -->
If your PR includes UI-related changes, then:
- Add screenshots for portrait/landscape for both a tablet & phone of
the before & after UI changes
- For the screenshots above, include both English and pseudo-localized
(RTL) screenshots (see [RTL
guide](https://github.com/oppia/oppia-android/wiki/RTL-Guidelines))
- Add a video showing the full UX flow with a screen reader enabled (see
[accessibility
guide](https://github.com/oppia/oppia-android/wiki/Accessibility-A11y-Guide))
- Add a screenshot demonstrating that you ran affected Espresso tests
locally & that they're passing

---------

Co-authored-by: Kenneth Murerwa <kkmurerwa@Kenneths-MacBook-Air.local>
Co-authored-by: Ben Henning <ben@oppia.org>
  • Loading branch information
3 people committed Oct 24, 2023
1 parent e151bbd commit d471d79
Show file tree
Hide file tree
Showing 21 changed files with 1,381 additions and 7 deletions.
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -92,6 +92,18 @@
android:name=".app.notice.testing.GeneralAvailabilityUpgradeNoticeDialogFragmentTestActivity"
android:label="@string/test_activity_label"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.notice.testing.ForcedAppDeprecationNoticeDialogFragmentTestActivity"
android:label="@string/test_activity_label"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.notice.testing.OptionalAppDeprecationNoticeDialogFragmentTestActivity"
android:label="@string/test_activity_label"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.notice.testing.OsDeprecationNoticeDialogFragmentTestActivity"
android:label="@string/test_activity_label"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.onboarding.OnboardingActivity"
android:label="@string/onboarding_activity_title"
Expand Down
Expand Up @@ -31,7 +31,10 @@ import org.oppia.android.app.mydownloads.MyDownloadsFragment
import org.oppia.android.app.mydownloads.UpdatesTabFragment
import org.oppia.android.app.notice.AutomaticAppDeprecationNoticeDialogFragment
import org.oppia.android.app.notice.BetaNoticeDialogFragment
import org.oppia.android.app.notice.ForcedAppDeprecationNoticeDialogFragment
import org.oppia.android.app.notice.GeneralAvailabilityUpgradeNoticeDialogFragment
import org.oppia.android.app.notice.OptionalAppDeprecationNoticeDialogFragment
import org.oppia.android.app.notice.OsDeprecationNoticeDialogFragment
import org.oppia.android.app.onboarding.OnboardingFragment
import org.oppia.android.app.ongoingtopiclist.OngoingTopicListFragment
import org.oppia.android.app.options.AppLanguageFragment
Expand Down Expand Up @@ -113,7 +116,10 @@ interface FragmentComponentImpl : FragmentComponent, ViewComponentBuilderInjecto
fun inject(appVersionFragment: AppVersionFragment)
fun inject(audioFragment: AudioFragment)
fun inject(audioLanguageFragment: AudioLanguageFragment)
fun inject(autoAppDeprecationNoticeDialogFragment: AutomaticAppDeprecationNoticeDialogFragment)
fun inject(
automaticAppDeprecationNoticeDialogFragment:
AutomaticAppDeprecationNoticeDialogFragment
)
fun inject(betaNoticeDialogFragment: BetaNoticeDialogFragment)
fun inject(cellularAudioDialogFragment: CellularAudioDialogFragment)
fun inject(completedStoryListFragment: CompletedStoryListFragment)
Expand All @@ -127,6 +133,7 @@ interface FragmentComponentImpl : FragmentComponent, ViewComponentBuilderInjecto
fun inject(explorationTestActivityTestFragment: ExplorationTestActivityPresenter.TestFragment)
fun inject(faqListFragment: FAQListFragment)
fun inject(forceNetworkTypeFragment: ForceNetworkTypeFragment)
fun inject(forcedAppDeprecationNoticeDialogFragment: ForcedAppDeprecationNoticeDialogFragment)
fun inject(fragment: GeneralAvailabilityUpgradeNoticeDialogFragment)
fun inject(helpFragment: HelpFragment)
fun inject(hintsAndSolutionDialogFragment: HintsAndSolutionDialogFragment)
Expand All @@ -146,7 +153,9 @@ interface FragmentComponentImpl : FragmentComponent, ViewComponentBuilderInjecto
fun inject(navigationDrawerFragment: NavigationDrawerFragment)
fun inject(onboardingFragment: OnboardingFragment)
fun inject(ongoingTopicListFragment: OngoingTopicListFragment)
fun inject(optionalAppDeprecationNoticeDialogFragment: OptionalAppDeprecationNoticeDialogFragment)
fun inject(optionFragment: OptionsFragment)
fun inject(osDeprecationNoticeDialogFragment: OsDeprecationNoticeDialogFragment)
fun inject(policiesFragment: PoliciesFragment)
fun inject(profileAndDeviceIdFragment: ProfileAndDeviceIdFragment)
fun inject(profileChooserFragment: ProfileChooserFragment)
Expand Down
@@ -0,0 +1,9 @@
package org.oppia.android.app.notice

import org.oppia.android.app.splash.DeprecationNoticeActionType

/** Listener for when an option on any deprecation dialog is clicked. */
interface DeprecationNoticeActionListener {
/** Called when a dialog button is clicked. */
fun onActionButtonClicked(noticeType: DeprecationNoticeActionType)
}
@@ -0,0 +1,29 @@
package org.oppia.android.app.notice

import android.app.Dialog
import android.content.Context
import android.os.Bundle
import org.oppia.android.app.fragment.FragmentComponentImpl
import org.oppia.android.app.fragment.InjectableDialogFragment
import javax.inject.Inject

/** Dialog fragment that informs the user of an app deprecation. */
class ForcedAppDeprecationNoticeDialogFragment : InjectableDialogFragment() {
companion object {
/** Returns a new instance of [ForcedAppDeprecationNoticeDialogFragment]. */
fun newInstance(): ForcedAppDeprecationNoticeDialogFragment {
return ForcedAppDeprecationNoticeDialogFragment()
}
}

@Inject lateinit var presenter: ForcedAppDeprecationNoticeDialogFragmentPresenter

override fun onAttach(context: Context) {
super.onAttach(context)
(fragmentComponent as FragmentComponentImpl).inject(this)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return presenter.handleOnCreateDialog()
}
}
@@ -0,0 +1,47 @@
package org.oppia.android.app.notice

import android.app.Dialog
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.oppia.android.R
import org.oppia.android.app.splash.DeprecationNoticeActionType
import org.oppia.android.app.translation.AppLanguageResourceHandler
import javax.inject.Inject

/** Presenter class responsible for showing an app deprecation dialog to the user. */
class ForcedAppDeprecationNoticeDialogFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val resourceHandler: AppLanguageResourceHandler
) {
private val deprecationNoticeActionListener by lazy {
activity as DeprecationNoticeActionListener
}

/** Handles dialog creation for the forced app deprecation notice. */
fun handleOnCreateDialog(): Dialog {
val appName = resourceHandler.getStringInLocale(R.string.app_name)

val dialog = AlertDialog.Builder(activity, R.style.DeprecationAlertDialogTheme)
.setTitle(R.string.forced_app_update_dialog_title)
.setMessage(
resourceHandler.getStringInLocaleWithWrapping(
R.string.forced_app_update_dialog_message,
appName
)
)
.setPositiveButton(R.string.forced_app_update_dialog_update_button_text) { _, _ ->
deprecationNoticeActionListener.onActionButtonClicked(
DeprecationNoticeActionType.UPDATE
)
}
.setNegativeButton(R.string.forced_app_update_dialog_close_button_text) { _, _ ->
deprecationNoticeActionListener.onActionButtonClicked(
DeprecationNoticeActionType.CLOSE
)
}
.setCancelable(false)
.create()
dialog.setCanceledOnTouchOutside(false)
return dialog
}
}
@@ -0,0 +1,30 @@
package org.oppia.android.app.notice

import android.app.Dialog
import android.content.Context
import android.os.Bundle
import org.oppia.android.app.fragment.FragmentComponentImpl
import org.oppia.android.app.fragment.InjectableDialogFragment
import javax.inject.Inject

/** Dialog fragment that informs the user that a new app version is available for download. */
class OptionalAppDeprecationNoticeDialogFragment : InjectableDialogFragment() {
companion object {
/** Returns a new instance of [OptionalAppDeprecationNoticeDialogFragment]. */
fun newInstance(): OptionalAppDeprecationNoticeDialogFragment {
return OptionalAppDeprecationNoticeDialogFragment()
}
}

@Inject lateinit var optionalAppDeprecationNoticeDialogFragmentPresenter:
OptionalAppDeprecationNoticeDialogFragmentPresenter

override fun onAttach(context: Context) {
super.onAttach(context)
(fragmentComponent as FragmentComponentImpl).inject(this)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return optionalAppDeprecationNoticeDialogFragmentPresenter.handleOnCreateDialog()
}
}
@@ -0,0 +1,47 @@
package org.oppia.android.app.notice

import android.app.Dialog
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.oppia.android.R
import org.oppia.android.app.splash.DeprecationNoticeActionType
import org.oppia.android.app.translation.AppLanguageResourceHandler
import javax.inject.Inject

/** Presenter class responsible for showing an optional update dialog to the user. */
class OptionalAppDeprecationNoticeDialogFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val resourceHandler: AppLanguageResourceHandler
) {
private val deprecationNoticeActionListener by lazy {
activity as DeprecationNoticeActionListener
}

/** Handles dialog creation for the optional app deprecation notice. */
fun handleOnCreateDialog(): Dialog {
val appName = resourceHandler.getStringInLocale(R.string.app_name)

val dialog = AlertDialog.Builder(activity, R.style.DeprecationAlertDialogTheme)
.setTitle(R.string.optional_app_update_dialog_title)
.setMessage(
resourceHandler.getStringInLocaleWithWrapping(
R.string.optional_app_update_dialog_message,
appName
)
)
.setPositiveButton(R.string.optional_app_update_dialog_update_button_text) { _, _ ->
deprecationNoticeActionListener.onActionButtonClicked(
DeprecationNoticeActionType.UPDATE
)
}
.setNegativeButton(R.string.optional_app_update_dialog_dismiss_button_text) { _, _ ->
deprecationNoticeActionListener.onActionButtonClicked(
DeprecationNoticeActionType.DISMISS
)
}
.setCancelable(false)
.create()
dialog.setCanceledOnTouchOutside(false)
return dialog
}
}
@@ -0,0 +1,33 @@
package org.oppia.android.app.notice

import android.app.Dialog
import android.content.Context
import android.os.Bundle
import org.oppia.android.app.fragment.FragmentComponentImpl
import org.oppia.android.app.fragment.InjectableDialogFragment
import javax.inject.Inject

/**
* Dialog fragment that informs the user that their phone OS is no longer supported by Oppia and
* they will no longer be able to update their app to the latest version.
*/
class OsDeprecationNoticeDialogFragment : InjectableDialogFragment() {
companion object {
/** Returns a new instance of [OsDeprecationNoticeDialogFragment]. */
fun newInstance(): OsDeprecationNoticeDialogFragment {
return OsDeprecationNoticeDialogFragment()
}
}

@Inject lateinit var osDeprecationNoticeDialogFragmentPresenter:
OsDeprecationNoticeDialogFragmentPresenter

override fun onAttach(context: Context) {
super.onAttach(context)
(fragmentComponent as FragmentComponentImpl).inject(this)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return osDeprecationNoticeDialogFragmentPresenter.handleOnCreateDialog()
}
}
@@ -0,0 +1,42 @@
package org.oppia.android.app.notice

import android.app.Dialog
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.oppia.android.R
import org.oppia.android.app.splash.DeprecationNoticeActionType
import org.oppia.android.app.translation.AppLanguageResourceHandler
import javax.inject.Inject

/** Presenter class responsible for showing an OS deprecation dialog to the user. */
class OsDeprecationNoticeDialogFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val resourceHandler: AppLanguageResourceHandler
) {
private val deprecationNoticeActionListener by lazy {
activity as DeprecationNoticeActionListener
}

/** Handles dialog creation for the OS deprecation notice. */
fun handleOnCreateDialog(): Dialog {
val appName = resourceHandler.getStringInLocale(R.string.app_name)

val dialog = AlertDialog.Builder(activity, R.style.DeprecationAlertDialogTheme)
.setTitle(R.string.os_deprecation_dialog_title)
.setMessage(
resourceHandler.getStringInLocaleWithWrapping(
R.string.os_deprecation_dialog_message,
appName
)
)
.setNegativeButton(R.string.os_deprecation_dialog_dismiss_button_text) { _, _ ->
deprecationNoticeActionListener.onActionButtonClicked(
DeprecationNoticeActionType.DISMISS
)
}
.setCancelable(false)
.create()
dialog.setCanceledOnTouchOutside(false)
return dialog
}
}
39 changes: 39 additions & 0 deletions app/src/main/java/org/oppia/android/app/notice/testing/BUILD.bazel
Expand Up @@ -18,6 +18,19 @@ kt_android_library(
],
)

kt_android_library(
name = "forced_app_deprecation_notice_dialog_fragment_test_activity",
testonly = True,
srcs = [
"ForcedAppDeprecationNoticeDialogFragmentTestActivity.kt",
],
visibility = ["//app:app_testing_visibility"],
deps = [
"//app",
"//app/src/main/java/org/oppia/android/app/testing/activity:test_activity",
],
)

kt_android_library(
name = "general_availability_upgrade_notice_dialog_fragment_test_activity",
testonly = True,
Expand All @@ -31,4 +44,30 @@ kt_android_library(
],
)

kt_android_library(
name = "optional_app_deprecation_notice_dialog_fragment_test_activity",
testonly = True,
srcs = [
"OptionalAppDeprecationNoticeDialogFragmentTestActivity.kt",
],
visibility = ["//app:app_testing_visibility"],
deps = [
"//app",
"//app/src/main/java/org/oppia/android/app/testing/activity:test_activity",
],
)

kt_android_library(
name = "os_deprecation_notice_dialog_fragment_test_activity",
testonly = True,
srcs = [
"OsDeprecationNoticeDialogFragmentTestActivity.kt",
],
visibility = ["//app:app_testing_visibility"],
deps = [
"//app",
"//app/src/main/java/org/oppia/android/app/testing/activity:test_activity",
],
)

dagger_rules()
@@ -0,0 +1,30 @@
package org.oppia.android.app.notice.testing

import android.os.Bundle
import org.oppia.android.app.notice.DeprecationNoticeActionListener
import org.oppia.android.app.notice.ForcedAppDeprecationNoticeDialogFragment
import org.oppia.android.app.splash.DeprecationNoticeActionType
import org.oppia.android.app.testing.activity.TestActivity

/** [TestActivity] for setting up a test environment for testing the beta notice dialog. */
class ForcedAppDeprecationNoticeDialogFragmentTestActivity :
TestActivity(),
DeprecationNoticeActionListener {
/**
* [DeprecationNoticeActionListener] that must be initialized by the test, and is presumed to be a
* Mockito mock (though this is not, strictly speaking, required).
*
* This listener will be used as the callback for the dialog in response to UI operations.
*/
lateinit var mockCallbackListener: DeprecationNoticeActionListener

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ForcedAppDeprecationNoticeDialogFragment.newInstance()
.showNow(supportFragmentManager, "forced_app_deprecation_dialog")
}

override fun onActionButtonClicked(noticeType: DeprecationNoticeActionType) {
mockCallbackListener.onActionButtonClicked(noticeType)
}
}

0 comments on commit d471d79

Please sign in to comment.