Skip to content

Commit

Permalink
Fixes part of #16: Implement ProfileListActivity in settings [Blocked #…
Browse files Browse the repository at this point in the history
…22, #48] (#542)

* implemented get and delete

* Finished test cases

* added observing cachestore

* Fixed test cases

* Finished first draft of implementation

* Added additional checks to setCurrentProfileId

* Added more test cases

* Finished test stubs

* Finished test cases

* Added query string to gravatar

* primed cache on init

* Fixed typo

* Fixed addProfile test case

* added create method to PersistentCacheStore

* added setTimestamp and setAdmin

* changed isAdmin to default to false

* Added update last logged in

* Started working on chooser

* debugging

* Added UI for chooser

* added click functionality

* Minor fixes

* Started basic admin auth and add profile

* Updated to use deferred value from persistentCacheStore

* Updated to use login

* Ensured result is error to post error value

* name can only be letters and unique check now case insensitive

* Added profile sorting by last accessed

* Fixed margins and added gradient

* allow names to have spaces

* Switched fragments to activities

* Finished admin auth styling

* Styled inputs for add profile

* Fixed name only letters toast

* Added support for upload image

* Started custom view

* added upload image and fixed input styling

* Added image rotation and compression

* Added red color

* fixed api requires for exifinterface

* Changed gradle dependency

* Added error handling ui support

* Added new asset and changed colors

* hide keyboard on create

* changed selectedImage to private

* Moved bindingadapter to companion object

* Started activity

* removed fragment checks

* Finished basic flow of pin password

* Added show password button

* Added input to dialog

* Sorted alphabetically

* added local default to tolowercase

* updated comment

* Renamed keys

* Updated key

* Changed to getProfile from database

* Added change pin dialogs

* Added pin input animation and go to play store

* added info icon

* started profile test helper

* Removed broken test, couldn't get mockito to work

* Added ProfileTestHelperTest

* added test case for profilechooserfragment

* Added test for AdminAuthActivity

* using string.xml values in tests

* Started AddProfileActivityTest

* Finished test cases

* Finished test cases and adjusted sizes

* Minor fixes and added default profile avatar

* minor fixes

* added endline

* Minor fixes

* removed resources

* Minor fixes

* Minor fixes.

* Started updating to DataProviders

* Fixed recyclerview

* Fixed loginToProfile

* Minor fixes

* Added comments and new test.

* minor fixes

* Fixed bug

* Added vector version of avatar

* Minor fixes.

* Converted livedata to dataproviders

* Minor fixes

* Removed coroutines from test.

* Added helper methods

* Removed ExperimentalCoroutinesApi

* Removed import

* Removed ExperimentalCouroutinesApi

* Addressed comments

* Fixed Project.xml

* Addressed all comments.

* Fixed failing test cases

* Updated xml to multiples of 4

* Fixed dp values

* Minor fixes

* Fixed dp

* Fixed ProfileTestHelper

* Added avatar color support.

* Added Ben's createTimer

* Addressed comments in previous PRs that didn't get pushed before.

* Removed lines

* Added admin pin creation flow

* Fixed tests

* Merge branch 'profile-avatar-colors' into profile-admin-flow

* Added back button dialog to home activity

* Initial changes, fragments to activities

* Added basic recyclerview

* Added recyclerview databinding

* added new line

* Updated log statement

* Updated domain test case

* Added AdminPinTests

* Removed unused imports

* Finished test cases

* Cleaner profile avatar design

* Updated profile:src

* Removed textUtils

* Reverted splash activity

* Removed unused imports

* Updated to now store colorHex and other fixes.

* Updated comment.

* Updated to colorRgb

* Added fixes

* Updated to force admin.

* Updated comments.

* Nit fixes.
  • Loading branch information
jamesxu0 authored Dec 14, 2019
1 parent 9087f07 commit e87347a
Show file tree
Hide file tree
Showing 20 changed files with 440 additions and 118 deletions.
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
android:name=".profile.ProfileActivity"
android:theme="@style/OppiaThemeWithoutActionBar"
android:screenOrientation="portrait" />
<activity
android:name=".settings.profile.ProfileEditActivity"
android:screenOrientation="portrait" />
<activity
android:name=".settings.profile.ProfileListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".settings.profile.ProfileRenameActivity"
android:screenOrientation="portrait" />
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/org/oppia/app/activity/ActivityComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import org.oppia.app.profile.AdminAuthActivity
import org.oppia.app.profile.AdminPinActivity
import org.oppia.app.profile.PinPasswordActivity
import org.oppia.app.profile.ProfileActivity
import org.oppia.app.settings.profile.ProfileEditActivity
import org.oppia.app.settings.profile.ProfileListActivity
import org.oppia.app.settings.profile.ProfileRenameActivity
import org.oppia.app.settings.profile.ProfileResetPinActivity
import org.oppia.app.story.StoryActivity
Expand Down Expand Up @@ -61,6 +63,8 @@ interface ActivityComponent {
fun inject(pinPasswordActivity: PinPasswordActivity)
fun inject(profileActivity: ProfileActivity)
fun inject(questionPlayerActivity: QuestionPlayerActivity)
fun inject(profileEditActivity: ProfileEditActivity)
fun inject(profileListActivity: ProfileListActivity)
fun inject(profileRenameActivity: ProfileRenameActivity)
fun inject(profileResetPinActivity: ProfileResetPinActivity)
fun inject(storyActivity: StoryActivity)
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import org.oppia.app.player.audio.AudioFragment
import org.oppia.app.player.exploration.ExplorationFragment
import org.oppia.app.player.state.StateFragment
import org.oppia.app.profile.AdminSettingsDialogFragment
import org.oppia.app.settings.profile.ProfileEditFragment
import org.oppia.app.settings.profile.ProfileListFragment
import org.oppia.app.player.state.itemviewmodel.InteractionViewModelModule
import org.oppia.app.profile.ProfileChooserFragment
import org.oppia.app.profile.ResetPinDialogFragment
Expand Down Expand Up @@ -48,8 +46,6 @@ interface FragmentComponent {
fun inject(explorationFragment: ExplorationFragment)
fun inject(homeFragment: HomeFragment)
fun inject(profileChooserFragment: ProfileChooserFragment)
fun inject(profileEditFragment: ProfileEditFragment)
fun inject(profileListFragment: ProfileListFragment)
fun inject(questionPlayerFragment: QuestionPlayerFragment)
fun inject(resetPinDialogFragment: ResetPinDialogFragment)
fun inject(stateFragment: StateFragment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import javax.inject.Inject
/** The ViewModel for [ProfileChooserFragment]. */
@FragmentScope
class ProfileChooserViewModel @Inject constructor(
private val profileManagementController: ProfileManagementController, private val logger: Logger
private val logger: Logger,
private val profileManagementController: ProfileManagementController
) : ObservableViewModel() {
val profiles: LiveData<List<ProfileChooserUiModel>> by lazy {
Transformations.map(profileManagementController.getProfiles(), ::processGetProfilesResult)
Expand All @@ -33,7 +34,7 @@ class ProfileChooserViewModel @Inject constructor(
if (profilesResult.isFailure()) {
logger.e(
"ProfileChooserViewModel",
"Failed to retrieve the list of profiles: ",
"Failed to retrieve the list of profiles",
profilesResult.getErrorOrNull()!!
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.oppia.app.settings.profile

import android.content.Context
import android.content.Intent
import android.os.Bundle
import org.oppia.app.activity.InjectableAppCompatActivity
import javax.inject.Inject

const val KEY_PROFILE_EDIT_PROFILE_ID = "KEY_PROFILE_EDIT_PROFILE_ID"

/** Activity that allows user to select a profile to edit from settings. */
class ProfileEditActivity : InjectableAppCompatActivity() {
@Inject lateinit var profileEditActivityPresenter: ProfileEditActivityPresenter

companion object {
fun createProfileEditActivity(context: Context, profileId: Int): Intent {
val intent = Intent(context, ProfileEditActivity::class.java)
intent.putExtra(KEY_PROFILE_EDIT_PROFILE_ID, profileId)
return intent
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityComponent.inject(this)
profileEditActivityPresenter.handleOnCreate()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.oppia.app.settings.profile

import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import org.oppia.app.R
import org.oppia.app.activity.ActivityScope
import org.oppia.app.databinding.ProfileEditActivityBinding
import org.oppia.app.viewmodel.ViewModelProvider
import javax.inject.Inject

/** The presenter for [ProfileEditActivity]. */
@ActivityScope
class ProfileEditActivityPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val viewModelProvider: ViewModelProvider<ProfileEditViewModel>
) {
fun handleOnCreate() {
val binding = DataBindingUtil.setContentView<ProfileEditActivityBinding>(activity, R.layout.profile_edit_activity)
}

private fun getProfileEditViewModel(): ProfileEditViewModel {
return viewModelProvider.getForActivity(activity, ProfileEditViewModel::class.java)
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.oppia.app.settings.profile

import org.oppia.app.fragment.FragmentScope
import org.oppia.app.activity.ActivityScope
import org.oppia.app.viewmodel.ObservableViewModel
import javax.inject.Inject

/** The ViewModel for [ProfileEditFragment]. */
@FragmentScope
/** The ViewModel for [ProfileEditActivity]. */
@ActivityScope
class ProfileEditViewModel @Inject constructor() : ObservableViewModel() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.oppia.app.settings.profile

import android.os.Bundle
import org.oppia.app.activity.InjectableAppCompatActivity
import javax.inject.Inject

/** Activity that allows users to select a profile to edit from settings. */
class ProfileListActivity : InjectableAppCompatActivity() {
@Inject lateinit var profileListActivityPresenter: ProfileListActivityPresenter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityComponent.inject(this)
profileListActivityPresenter.handleOnCreate()
}

override fun onSupportNavigateUp(): Boolean {
finish()
return false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.oppia.app.settings.profile

import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import org.oppia.app.R
import org.oppia.app.activity.ActivityScope
import org.oppia.app.databinding.ProfileListActivityBinding
import org.oppia.app.databinding.ProfileListProfileViewBinding
import org.oppia.app.model.Profile
import org.oppia.app.recyclerview.BindableAdapter
import org.oppia.app.viewmodel.ViewModelProvider
import javax.inject.Inject

/** The presenter for [ProfileListActivity]. */
@ActivityScope
class ProfileListActivityPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val viewModelProvider: ViewModelProvider<ProfileListViewModel>
) {
fun handleOnCreate() {
activity.title = activity.getString(R.string.profile_list_activity_title)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp)

val binding = DataBindingUtil.setContentView<ProfileListActivityBinding>(activity, R.layout.profile_list_activity)
binding.apply {
viewModel = getProfileListViewModel()
lifecycleOwner = activity
}

binding.profileListRecyclerView.apply {
adapter = createRecyclerViewAdapter()
}
}

private fun createRecyclerViewAdapter(): BindableAdapter<Profile> {
return BindableAdapter.SingleTypeBuilder
.newBuilder<Profile>()
.registerViewDataBinderWithSameModelType(
inflateDataBinding = ProfileListProfileViewBinding::inflate,
setViewModel = ::bindProfileView
)
.build()
}

private fun bindProfileView(
binding: ProfileListProfileViewBinding,
profile: Profile
) {
binding.profile = profile
binding.root.setOnClickListener {
activity.startActivity(ProfileEditActivity.createProfileEditActivity(activity, profile.id.internalId))
}
}

private fun getProfileListViewModel(): ProfileListViewModel {
return viewModelProvider.getForActivity(activity, ProfileListViewModel::class.java)
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,47 @@
package org.oppia.app.settings.profile

import org.oppia.app.fragment.FragmentScope
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import org.oppia.app.activity.ActivityScope
import org.oppia.app.model.Profile
import org.oppia.app.viewmodel.ObservableViewModel
import org.oppia.domain.profile.ProfileManagementController
import org.oppia.util.data.AsyncResult
import org.oppia.util.logging.Logger
import java.util.*
import javax.inject.Inject

/** The ViewModel for [ProfileListFragment]. */
@FragmentScope
class ProfileListViewModel @Inject constructor(): ObservableViewModel() {
/** The ViewModel for [ProfileListActivity]. */
@ActivityScope
class ProfileListViewModel @Inject constructor(
private val logger: Logger,
private val profileManagementController: ProfileManagementController
) : ObservableViewModel() {
val profiles: LiveData<List<Profile>> by lazy {
Transformations.map(profileManagementController.getProfiles(), ::processGetProfilesResult)
}

private fun processGetProfilesResult(profilesResult: AsyncResult<List<Profile>>): List<Profile> {
if (profilesResult.isFailure()) {
logger.e(
"ProfileListViewModel",
"Failed to retrieve the list of profiles",
profilesResult.getErrorOrNull()!!
)
}
val profileList = profilesResult.getOrDefault(emptyList())

val sortedProfileList = profileList.sortedBy {
it.name.toLowerCase(Locale.getDefault())
}.toMutableList()

val adminProfile = sortedProfileList.find { it.isAdmin }

adminProfile?.let {
sortedProfileList.remove(adminProfile)
sortedProfileList.add(0, it)
}

return sortedProfileList
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_arrow_back_white_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>
Loading

0 comments on commit e87347a

Please sign in to comment.