Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix part #549 : Options Navigation Drawer Domain layer part 1 #548

Merged
merged 41 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
75fd9b0
Added option screen
veena14cs Dec 13, 2019
c387ebb
Merge branch 'develop' into options-low-fi
veena14cs Dec 16, 2019
5635e10
working on bindable adapter
veena14cs Dec 16, 2019
25718ed
Update OptionsFragment.kt
veena14cs Dec 16, 2019
da1181d
adde test cases
veena14cs Dec 16, 2019
9c430ab
Done nit changes
veena14cs Dec 17, 2019
afb3671
Merge branch 'develop' into options-low-fi
veena14cs Dec 17, 2019
ed4e06e
renamed toolbar
veena14cs Dec 17, 2019
dd6f467
Update OptionsFragmentTest.kt
veena14cs Dec 17, 2019
215abda
Update OptionsFragmentTest.kt
veena14cs Dec 17, 2019
56b10ef
nit change
veena14cs Dec 18, 2019
48a84f4
fixed nit
veena14cs Dec 18, 2019
5c3245d
working on shared pref
veena14cs Dec 18, 2019
274ed07
Update OptionsFragment.kt
veena14cs Dec 18, 2019
bd91dee
Merge branch 'develop' into options-low-fi
veena14cs Dec 23, 2019
95a1c06
working on domain layer
veena14cs Dec 23, 2019
6725517
fixed livedata issue.
veena14cs Dec 30, 2019
4bd86d8
Update OptionsFragment.kt
veena14cs Dec 30, 2019
abddba2
Update AndroidManifest.xml
veena14cs Dec 30, 2019
5d68166
Update OptionsFragment.kt
veena14cs Dec 30, 2019
ef5d3d8
Fixed nit
veena14cs Dec 30, 2019
6e9de0e
added test cases
veena14cs Dec 30, 2019
62a1593
Update OptionsFragment.kt
veena14cs Dec 30, 2019
72e380f
Merge branch 'develop' into options-low-fi
veena14cs Dec 30, 2019
bee5119
Update ActivityComponent.kt
veena14cs Dec 30, 2019
7a90240
added options in navigation
veena14cs Jan 6, 2020
c93e524
added icon for options
veena14cs Jan 6, 2020
d5ec963
Merge branch 'develop' into options-low-fi
veena14cs Jan 6, 2020
764a93b
added currentprofileId
veena14cs Jan 6, 2020
64d37d6
Merge branch 'develop' into options-low-fi
veena14cs Jan 21, 2020
7abd9ed
removed app module from this pr
veena14cs Jan 21, 2020
5364cb2
removed layouts
veena14cs Jan 21, 2020
bbdcd03
Update misc.xml
veena14cs Jan 21, 2020
fe00df8
updated parameters
veena14cs Jan 21, 2020
9fe384f
Update ProfileManagementControllerTest.kt
veena14cs Jan 21, 2020
916ec9f
add spacing
veena14cs Jan 21, 2020
202c3c7
fixed spacing
veena14cs Jan 21, 2020
36dd20c
add spacing
veena14cs Jan 21, 2020
5987a2c
add default values
veena14cs Jan 21, 2020
be1f59a
Update ProfileActivityPresenter.kt
veena14cs Jan 21, 2020
c8a5850
Update ProfileManagementController.kt
veena14cs Jan 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class AddProfileActivityPresenter @Inject constructor(
private var allowDownloadAccess = false
private var inputtedPin = false
private var inputtedConfirmPin = false
private var storyTextSize = 14f
private var appLanguage = "English"
private var audioLanguage = "No Audio"

@ExperimentalCoroutinesApi
fun handleOnCreate() {
Expand Down Expand Up @@ -111,7 +114,10 @@ class AddProfileActivityPresenter @Inject constructor(
avatarImagePath = selectedImage,
allowDownloadAccess = allowDownloadAccess,
colorRgb = activity.intent.getIntExtra(KEY_ADD_PROFILE_COLOR_RGB, -10710042),
isAdmin = false
isAdmin = false,
storyTextSize = storyTextSize,
appLanguage = appLanguage,
audioLanguage = audioLanguage
)
.observe(activity, Observer {
handleAddProfileResult(it, binding)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ class ProfileActivityPresenter @Inject constructor(
avatarImagePath = null,
allowDownloadAccess = true,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
)
activity.setContentView(R.layout.profile_activity)
if (getProfileChooserFragment() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ProfileChooserFragmentTest {

@Test
fun testProfileChooserFragment_clickAdminProfileWithNoPin_checkOpensAdminPinActivity() {
profileManagementController.addProfile("Sean", "", null, true, -10710042, true)
profileManagementController.addProfile("Sean", "", null, true, -10710042, true, 16f, "English", "English")
ActivityScenario.launch(ProfileActivity::class.java).use {
onView(atPosition(R.id.profile_recycler_view, 1)).perform(click())
intended(hasComponent(AdminPinActivity::class.java.name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ class ProfileEditActivityTest {
avatarImagePath = null,
allowDownloadAccess = true,
colorRgb = -10710042,
isAdmin = false
isAdmin = false,
storyTextSize = 16f,
appLanguage = "English",
audioLanguage = "No Audio"
)
ActivityScenario.launch<ProfileEditActivity>(ProfileEditActivity.createProfileEditActivity(context, 2)).use {
onView(withId(R.id.profile_edit_allow_download_switch)).check(matches(isChecked()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ import org.oppia.util.logging.Logger
import org.oppia.util.profile.DirectoryManagementUtil
import java.io.File
import java.io.FileOutputStream
import java.lang.Exception
import java.util.Date
import java.util.Locale
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton

Expand All @@ -37,6 +35,9 @@ private const val UPDATE_DOWNLOAD_ACCESS_TRANSFORMED_PROVIDER_ID = "update_downl
private const val LOGIN_PROFILE_TRANSFORMED_PROVIDER_ID = "login_profile_transformed_id"
private const val DELETE_PROFILE_TRANSFORMED_PROVIDER_ID = "delete_profile_transformed_id"
private const val SET_PROFILE_TRANSFORMED_PROVIDER_ID = "set_profile_transformed_id"
private const val UPDATE_STORY_TEXT_SIZE_TRANSFORMED_ID = "update_story_text_size_transformed_id"
private const val UPDATE_APP_LANGUAGE_TRANSFORMED_PROVIDER_ID = "update_app_language_transformed_id"
private const val UPDATE_AUDIO_LANGUAGE_TRANSFORMED_PROVIDER_ID = "update_audio_language_transformed_id"

const val PROFILE_AVATAR_FILE_NAME = "profile_avatar.png"

Expand Down Expand Up @@ -132,8 +133,12 @@ class ProfileManagementController @Inject constructor(
avatarImagePath: Uri?,
allowDownloadAccess: Boolean,
colorRgb: Int,
isAdmin: Boolean
isAdmin: Boolean,
storyTextSize: Float?,
appLanguage: String?,
audioLanguage: String?
): LiveData<AsyncResult<Any?>> {

if (!onlyLetters(name)) {
return MutableLiveData(AsyncResult.failed(ProfileNameOnlyLettersException("$name does not contain only letters")))
}
Expand All @@ -151,6 +156,9 @@ class ProfileManagementController @Inject constructor(
.setAllowDownloadAccess(allowDownloadAccess)
.setId(ProfileId.newBuilder().setInternalId(nextProfileId))
.setDateCreatedTimestampMs(Date().time).setIsAdmin(isAdmin)
.setStoryTextSize(storyTextSize!!)
.setAppLanguage(appLanguage)
.setAudioLanguage(audioLanguage)

if (avatarImagePath != null) {
val imageUri =
Expand Down Expand Up @@ -250,13 +258,90 @@ class ProfileManagementController @Inject constructor(
})
}

/**
* Updates the story text size of the profile.
*
* @param profileId the ID corresponding to the profile being updated.
* @param storyTextSize New text size for the profile being updated.
* @return a [LiveData] that indicates the success/failure of this update operation.
*/
fun updateStoryTextSize(
profileId: ProfileId, storyTextSize: Float
): LiveData<AsyncResult<Any?>> {
val deferred = profileDataStore.storeDataWithCustomChannelAsync(updateInMemoryCache = true) {
val profile = it.profilesMap[profileId.internalId] ?: return@storeDataWithCustomChannelAsync Pair(
it,
ProfileActionStatus.PROFILE_NOT_FOUND
)
val updatedProfile = profile.toBuilder().setStoryTextSize(storyTextSize).build()
val profileDatabaseBuilder = it.toBuilder().putProfiles(profileId.internalId, updatedProfile)
Pair(profileDatabaseBuilder.build(), ProfileActionStatus.SUCCESS)
}
return dataProviders.convertToLiveData(
dataProviders.createInMemoryDataProviderAsync(UPDATE_STORY_TEXT_SIZE_TRANSFORMED_ID) {
return@createInMemoryDataProviderAsync getDeferredResult(profileId, null, deferred)
})
}

/**
* Updates the app language of the profile.
*
* @param profileId the ID corresponding to the profile being updated.
* @param appLanguage New app language for the profile being updated.
* @return a [LiveData] that indicates the success/failure of this update operation.
*/
fun updateAppLanguage(
profileId: ProfileId, appLanguage: String
): LiveData<AsyncResult<Any?>> {
val deferred = profileDataStore.storeDataWithCustomChannelAsync(updateInMemoryCache = true) {
val profile = it.profilesMap[profileId.internalId] ?: return@storeDataWithCustomChannelAsync Pair(
it,
ProfileActionStatus.PROFILE_NOT_FOUND
)
val updatedProfile = profile.toBuilder().setAppLanguage(appLanguage).build()
val profileDatabaseBuilder = it.toBuilder().putProfiles(profileId.internalId, updatedProfile)
Pair(profileDatabaseBuilder.build(), ProfileActionStatus.SUCCESS)
}
return dataProviders.convertToLiveData(
dataProviders.createInMemoryDataProviderAsync(UPDATE_APP_LANGUAGE_TRANSFORMED_PROVIDER_ID) {
return@createInMemoryDataProviderAsync getDeferredResult(profileId, null, deferred)
})
}

/**
* Updates the audio language of the profile.
*
* @param profileId the ID corresponding to the profile being updated.
* @param audioLanguage New audio language for the profile being updated.
* @return a [LiveData] that indicates the success/failure of this update operation.
*/
fun updateAudioLanguage(
profileId: ProfileId, audioLanguage: String
): LiveData<AsyncResult<Any?>> {
val deferred = profileDataStore.storeDataWithCustomChannelAsync(updateInMemoryCache = true) {
val profile = it.profilesMap[profileId.internalId] ?: return@storeDataWithCustomChannelAsync Pair(
it,
ProfileActionStatus.PROFILE_NOT_FOUND
)
val updatedProfile = profile.toBuilder().setAudioLanguage(audioLanguage).build()
val profileDatabaseBuilder = it.toBuilder().putProfiles(profileId.internalId, updatedProfile)
Pair(profileDatabaseBuilder.build(), ProfileActionStatus.SUCCESS)
}
return dataProviders.convertToLiveData(
dataProviders.createInMemoryDataProviderAsync(UPDATE_AUDIO_LANGUAGE_TRANSFORMED_PROVIDER_ID) {
return@createInMemoryDataProviderAsync getDeferredResult(profileId, null, deferred)
})
}

/**
* Log in to the user's Profile by setting the current profile Id and updating profile's last logged in time.
*
* @param profileId the ID corresponding to the profile being logged into.
* @return a [LiveData] that indicates the success/failure of this login operation.
*/
fun loginToProfile(profileId: ProfileId): LiveData<AsyncResult<Any?>> {
currentProfileId = profileId.internalId
setCurrentProfileId(profileId)
return dataProviders.convertToLiveData(
dataProviders.transformAsync(LOGIN_PROFILE_TRANSFORMED_PROVIDER_ID, setCurrentProfileId(profileId)) {
return@transformAsync getDeferredResult(profileId, null, updateLastLoggedInAsync(profileId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@ class ProfileTestHelper @Inject constructor(
avatarImagePath = null,
allowDownloadAccess = true,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 16f,
appLanguage = "English",
audioLanguage = "Hindi"
)
profileManagementController.addProfile(
name = "Ben",
pin = "123",
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = false
isAdmin = false,
storyTextSize = 16f,
appLanguage = "Hindi",
audioLanguage = "English"
)
return profileManagementController.loginToProfile(ProfileId.newBuilder().setInternalId(0).build())
}
Expand All @@ -39,7 +45,10 @@ class ProfileTestHelper @Inject constructor(
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = false
isAdmin = false,
storyTextSize = 18f,
appLanguage = "Chinese",
audioLanguage = "French"
)
}
}
Expand All @@ -51,4 +60,7 @@ class ProfileTestHelper @Inject constructor(
/** Login to user profile. */
fun loginToUser() =
profileManagementController.loginToProfile(ProfileId.newBuilder().setInternalId(1).build())
/** Login to user profile. */
fun loginToUser2() =
profileManagementController.loginToProfile(ProfileId.newBuilder().setInternalId(2).build())
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = true,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
).observeForever(mockUpdateResultObserver)
advanceUntilIdle()

Expand Down Expand Up @@ -157,7 +160,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
).observeForever(mockUpdateResultObserver)

verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture())
Expand All @@ -179,7 +185,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
).observeForever(mockUpdateResultObserver)

verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture())
Expand Down Expand Up @@ -237,7 +246,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = false
isAdmin = false,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
)
advanceUntilIdle()
profileManagementController.getProfiles().observeForever(mockProfilesObserver)
Expand Down Expand Up @@ -381,6 +393,67 @@ class ProfileManagementControllerTest {
.contains("ProfileId 6 does not match an existing Profile")
}


@Test
@ExperimentalCoroutinesApi
fun testUpdateStoryTextSize_addProfiles_updateWithFontSize18_checkUpdateIsSuccessful() =
runBlockingTest(coroutineContext) {
addTestProfiles()
advanceUntilIdle()

val profileId = ProfileId.newBuilder().setInternalId(2).build()
profileManagementController.updateStoryTextSize(profileId, 18f)
.observeForever(mockUpdateResultObserver)
advanceUntilIdle()
profileManagementController.getProfile(profileId).observeForever(mockProfileObserver)

verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture())
verify(mockProfileObserver, atLeastOnce()).onChanged(profileResultCaptor.capture())
assertThat(updateResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.getOrThrow().storyTextSize).isEqualTo(18f)
}

@Test
@ExperimentalCoroutinesApi
fun testUpdateAppLanguage_addProfiles_updateWithChineseLanguage_checkUpdateIsSuccessful() =
runBlockingTest(coroutineContext) {
addTestProfiles()
advanceUntilIdle()

val profileId = ProfileId.newBuilder().setInternalId(2).build()
profileManagementController.updateAppLanguage(profileId, "Chinese")
.observeForever(mockUpdateResultObserver)
advanceUntilIdle()
profileManagementController.getProfile(profileId).observeForever(mockProfileObserver)

verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture())
verify(mockProfileObserver, atLeastOnce()).onChanged(profileResultCaptor.capture())
assertThat(updateResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.getOrThrow().appLanguage).isEqualTo("Chinese")
}

@Test
@ExperimentalCoroutinesApi
fun testUpdateAudioLanguage_addProfiles_updateWithFrenchLanguage_checkUpdateIsSuccessful() =
runBlockingTest(coroutineContext) {
addTestProfiles()
advanceUntilIdle()

val profileId = ProfileId.newBuilder().setInternalId(2).build()
profileManagementController.updateAudioLanguage(profileId, "French")
.observeForever(mockUpdateResultObserver)
advanceUntilIdle()
profileManagementController.getProfile(profileId).observeForever(mockProfileObserver)

verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture())
verify(mockProfileObserver, atLeastOnce()).onChanged(profileResultCaptor.capture())
assertThat(updateResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.isSuccess()).isTrue()
assertThat(profileResultCaptor.value.getOrThrow().audioLanguage).isEqualTo("French")
}

@Test
@ExperimentalCoroutinesApi
fun testDeleteProfile_addProfiles_deleteProfile_checkDeletionIsSuccessful() =
Expand Down Expand Up @@ -417,7 +490,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = false,
colorRgb = -10710042,
isAdmin = true
isAdmin = true,
storyTextSize = 14f,
appLanguage = "English",
audioLanguage = "No Audio"
)
advanceUntilIdle()
profileManagementController.getProfiles().observeForever(mockProfilesObserver)
Expand Down Expand Up @@ -510,7 +586,10 @@ class ProfileManagementControllerTest {
avatarImagePath = null,
allowDownloadAccess = it.allowDownloadAccess,
colorRgb = -10710042,
isAdmin = false
isAdmin = false,
storyTextSize = it.storyTextSize,
appLanguage = it.appLanguage,
audioLanguage = it.audioLanguage
)
}
}
Expand Down
10 changes: 10 additions & 0 deletions model/src/main/proto/profile.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ message Profile {

// Represents the time the user's profile was created.
int64 date_created_timestamp_ms = 9;

// Represents user selected story-text-size.
float story_text_size = 10;

// Represents user selected audio-language.
string audio_language = 11;

// Represents user selected app-language.
string app_language = 12;
}

// Represents a profile avatar image.
Expand Down Expand Up @@ -72,3 +81,4 @@ message ProfileChooserUiModel {
bool add_profile = 2;
}
}