Skip to content

Commit

Permalink
Fix oppia#3302 and oppia#3307: Implement View Event Logs Feature (opp…
Browse files Browse the repository at this point in the history
…ia#3376)

* Implement Developer Options Starter

* Fix lint issues

* Implement Developer Options Menu Item in Nav Drawer

* Fix lint issues

* Added Kdoc. abstract class -> interface

* Added tests for Developer Options menu item

* Fixed lint issues

* Introduced ApplicationComponentForDevMode

* Added KDocs and fixed lint issues

* Added test to check unavailibility of Dev Options menu item when not in dev mode

* Added initial test for DeveloperOptionsActivity. Added KDocs. Fixed lint issues

* Introduced DebugApplicationComponent

* Implement developer options menu ui

* Modified way of passing data to recycler view

* removed unnecessary isMultipane boolean

* added view models to app/BUILD.bazel

* Added tests for DeveloperOptionsActivityTest

* Fixed lint issues

* Corrected key mismatch error. Changed isDevMode to isDebugMode. Nit fixes

* Fixed Robolectric test for NavigationDrawerActivityTest

* Updated developer_options_fragment layout

* Added test for hints switch

* Added eof. Changed dev mode to debug mode

* Removed unnecessary lastLoadedFragment flag

* Corrected imports

* Removed unnecessary code from DeveloperOptionsActivityTest

* Modified approach for Application Components

* nit fix

* nit fix

* Added tests and Kdocs + nit fixes

* Code reformating

* Separated dev and prod tests for NavigationDrawerActivityTest

* nit fix

* Implemented View Event Logs feature

* Added deps to app/BUILD.bazel

* Renamed NavigationDrawerActivityDevTest to NavigationDrawerActivityDebugTest

* Created DebugLoggerModule

* Added deps for debug logging module

* Fixed event logs list

* Moved starter to devoptions

* Moved starter to devoptions

* nit fix

* Added tests for ViewEventLogsActivity

* Added TODOs

* Removed unnecessary code. Nit fixes

* Nit fixes in ViewEventLogsActivityTest

* Added accessiblity test rule. Modified UI for the same

* Nit fix

* Nit fixes

* Fixed bazel lint error

* Added TODO

* Added Kdoc to DeveloperOptionsViewModel

* Removed DebugExceptionLogger

* Added KDocs

* Code refactoring + added KDocs + nit fixes

* Nit changes in strings.xml

* KDocs added and updated

* fixed bazel build error

* Added test to check for intent

* Nit fixes

* Added TODOs and updated Kdocs

* Moved debug_module to firebase package

* Nit fix

* Added configChange Test

* Nit fixes

* Fixed ViewEventLogsActivityTest

* Nit fixes

* Nit + added configChange tests

* Fixed ViewEventLogsActivityTest

* Test name
  • Loading branch information
yashraj-01 committed Jul 9, 2021
1 parent 9abd017 commit ef83fde
Show file tree
Hide file tree
Showing 27 changed files with 1,233 additions and 16 deletions.
4 changes: 4 additions & 0 deletions app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ LISTENERS = [
"src/main/java/org/oppia/android/app/administratorcontrols/RouteToProfileListListener.kt",
"src/main/java/org/oppia/android/app/administratorcontrols/ShowLogoutDialogListener.kt",
"src/main/java/org/oppia/android/app/devoptions/ForceCrashButtonClickListener.kt",
"src/main/java/org/oppia/android/app/devoptions/RouteToViewEventLogsListener.kt",
"src/main/java/org/oppia/android/app/drawer/RouteToProfileProgressListener.kt",
"src/main/java/org/oppia/android/app/help/RouteToFAQListListener.kt",
"src/main/java/org/oppia/android/app/help/faq/RouteToFAQSingleListener.kt",
Expand Down Expand Up @@ -173,6 +174,8 @@ VIEW_MODELS = [
"src/main/java/org/oppia/android/app/devoptions/devoptionsitemviewmodel/DeveloperOptionsOverrideAppBehaviorsViewModel.kt",
"src/main/java/org/oppia/android/app/devoptions/devoptionsitemviewmodel/DeveloperOptionsViewLogsViewModel.kt",
"src/main/java/org/oppia/android/app/devoptions/DeveloperOptionsViewModel.kt",
"src/main/java/org/oppia/android/app/devoptions/vieweventlogs/EventLogItemViewModel.kt",
"src/main/java/org/oppia/android/app/devoptions/vieweventlogs/ViewEventLogsViewModel.kt",
"src/main/java/org/oppia/android/app/drawer/NavigationDrawerFooterViewModel.kt",
"src/main/java/org/oppia/android/app/drawer/NavigationDrawerHeaderViewModel.kt",
"src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQContentViewModel.kt",
Expand Down Expand Up @@ -580,6 +583,7 @@ kt_android_library(
"//third_party:androidx_databinding_databinding-runtime",
"//utility",
"//utility/src/main/java/org/oppia/android/util/extensions:context_extensions",
"//utility/src/main/java/org/oppia/android/util/logging/firebase:debug_module",
],
)

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@
android:name=".app.devoptions.DeveloperOptionsActivity"
android:label="@string/developer_options_activity_title"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.devoptions.vieweventlogs.ViewEventLogsActivity"
android:label="@string/view_event_logs_activity_title"
android:theme="@style/OppiaThemeWithoutActionBar" />

<provider
android:name="androidx.work.impl.WorkManagerInitializer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.oppia.android.app.administratorcontrols.AdministratorControlsActivity
import org.oppia.android.app.administratorcontrols.appversion.AppVersionActivity
import org.oppia.android.app.completedstorylist.CompletedStoryListActivity
import org.oppia.android.app.devoptions.DeveloperOptionsActivity
import org.oppia.android.app.devoptions.vieweventlogs.ViewEventLogsActivity
import org.oppia.android.app.fragment.FragmentComponent
import org.oppia.android.app.help.HelpActivity
import org.oppia.android.app.help.faq.FAQListActivity
Expand Down Expand Up @@ -121,5 +122,6 @@ interface ActivityComponent {
fun inject(topicRevisionTestActivity: TopicRevisionTestActivity)
fun inject(topicTestActivity: TopicTestActivity)
fun inject(topicTestActivityForStory: TopicTestActivityForStory)
fun inject(viewEventLogsActivity: ViewEventLogsActivity)
fun inject(walkthroughActivity: WalkthroughActivity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ import org.oppia.android.util.accessibility.AccessibilityProdModule
import org.oppia.android.util.caching.CachingModule
import org.oppia.android.util.gcsresource.GcsResourceModule
import org.oppia.android.util.logging.LoggerModule
import org.oppia.android.util.logging.firebase.DebugLogReportingModule
import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule
import org.oppia.android.util.logging.firebase.LogReportingModule
import org.oppia.android.util.parser.html.HtmlParserEntityTypeModule
import org.oppia.android.util.parser.image.GlideImageLoaderModule
import org.oppia.android.util.parser.image.ImageParsingModule
Expand All @@ -50,6 +50,10 @@ import javax.inject.Singleton
/**
* Root Dagger component for the application. All application-scoped modules should be included in
* this component.
*
* At the time of building the app in prod mode -
* Remove: [DeveloperOptionsStarterModule], [DebugLogReportingModule]
* Add: [LogReportingModule]
*/
@Singleton
@Component(
Expand All @@ -63,7 +67,7 @@ import javax.inject.Singleton
InteractionsModule::class, GcsResourceModule::class,
GlideImageLoaderModule::class, ImageParsingModule::class,
HtmlParserEntityTypeModule::class, CachingModule::class,
QuestionModule::class, LogReportingModule::class,
QuestionModule::class, DebugLogReportingModule::class,
AccessibilityProdModule::class, ImageClickInputModule::class,
LogStorageModule::class, IntentFactoryShimModule::class,
ViewBindingShimModule::class, PrimeTopicAssetsControllerModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import android.content.Intent
import android.os.Bundle
import org.oppia.android.R
import org.oppia.android.app.activity.InjectableAppCompatActivity
import org.oppia.android.app.devoptions.vieweventlogs.ViewEventLogsActivity
import org.oppia.android.app.drawer.NAVIGATION_PROFILE_ID_ARGUMENT_KEY
import javax.inject.Inject

/** Activity for Developer Options. */
class DeveloperOptionsActivity : InjectableAppCompatActivity(), ForceCrashButtonClickListener {
class DeveloperOptionsActivity :
InjectableAppCompatActivity(),
ForceCrashButtonClickListener,
RouteToViewEventLogsListener {
@Inject
lateinit var developerOptionsActivityPresenter: DeveloperOptionsActivityPresenter

Expand All @@ -20,6 +24,10 @@ class DeveloperOptionsActivity : InjectableAppCompatActivity(), ForceCrashButton
title = getString(R.string.developer_options_activity_title)
}

override fun routeToViewEventLogs() {
startActivity(ViewEventLogsActivity.createViewEventLogsActivityIntent(this))
}

companion object {
/** Function to create intent for DeveloperOptionsActivity */
fun createDeveloperOptionsActivityIntent(context: Context, internalProfileId: Int): Intent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import javax.inject.Inject
*/
@FragmentScope
class DeveloperOptionsViewModel @Inject constructor(activity: AppCompatActivity) {

private val forceCrashButtonClickListener = activity as ForceCrashButtonClickListener
private val routeToViewEventLogsListener = activity as RouteToViewEventLogsListener

/**
* List of [DeveloperOptionsItemViewModel] used to populate recyclerview of
Expand All @@ -29,7 +29,7 @@ class DeveloperOptionsViewModel @Inject constructor(activity: AppCompatActivity)
private fun processDeveloperOptionsList(): List<DeveloperOptionsItemViewModel> {
return listOf(
DeveloperOptionsModifyLessonProgressViewModel(),
DeveloperOptionsViewLogsViewModel(),
DeveloperOptionsViewLogsViewModel(routeToViewEventLogsListener),
DeveloperOptionsOverrideAppBehaviorsViewModel(forceCrashButtonClickListener)
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.oppia.android.app.devoptions

/** Listener for when the user wants to view event logs. */
interface RouteToViewEventLogsListener {
/** Called when the user indicates that they want to view event logs. */
fun routeToViewEventLogs()
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
package org.oppia.android.app.devoptions.devoptionsitemviewmodel

import org.oppia.android.app.devoptions.RouteToViewEventLogsListener

/** [DeveloperOptionsItemViewModel] to provide features to view logs such as analytic event logs. */
class DeveloperOptionsViewLogsViewModel : DeveloperOptionsItemViewModel()
class DeveloperOptionsViewLogsViewModel(
private val routeToViewEventLogsListener: RouteToViewEventLogsListener
) : DeveloperOptionsItemViewModel() {
/** Routes the user to [ViewEventLogsActivity] for displaying the event logs. */
fun onEventLogsClicked() {
routeToViewEventLogsListener.routeToViewEventLogs()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.oppia.android.app.devoptions.vieweventlogs

import org.oppia.android.app.model.EventLog
import org.oppia.android.app.viewmodel.ObservableViewModel
import org.oppia.android.util.system.OppiaDateTimeFormatter
import javax.inject.Inject

/** [ViewModel] for displaying a event log. */
class EventLogItemViewModel @Inject constructor(
val eventLog: EventLog,
private val oppiaDateTimeFormatter: OppiaDateTimeFormatter
) : ObservableViewModel() {

/** Returns the event log timestamp in a human readable format. */
fun processDateAndTime(): String {
return oppiaDateTimeFormatter.formatDateFromDateString(
OppiaDateTimeFormatter.DD_MMM_hh_mm_aa,
eventLog.timestamp
)
}

/** Returns the event log priority in a human readable format. */
fun formatPriorityString(): String? = eventLog.priority.name.toLowerCase().capitalize()

/** Returns the event log context in a human readable format. */
fun formatContextString(): String? =
eventLog.context.activityContextCase.name.capitalizeWords().substringBeforeLast(" ")

/** Returns the event log action name in a human readable format. */
fun formatActionNameString(): String = eventLog.actionName.name.capitalizeWords()

private fun String.capitalizeWords(): String =
toLowerCase().split("_").joinToString(" ") { it.capitalize() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.oppia.android.app.devoptions.vieweventlogs

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

/** Activity for View Event Logs. */
class ViewEventLogsActivity : InjectableAppCompatActivity() {
@Inject
lateinit var viewEventLogsActivityPresenter: ViewEventLogsActivityPresenter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityComponent.inject(this)
viewEventLogsActivityPresenter.handleOnCreate()
title = getString(R.string.view_event_logs_activity_title)
}

companion object {
fun createViewEventLogsActivityIntent(context: Context): Intent {
return Intent(context, ViewEventLogsActivity::class.java)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.oppia.android.app.devoptions.vieweventlogs

import androidx.appcompat.app.AppCompatActivity
import org.oppia.android.R
import org.oppia.android.app.activity.ActivityScope
import javax.inject.Inject

/** The presenter for [ViewEventLogsActivity]. */
@ActivityScope
class ViewEventLogsActivityPresenter @Inject constructor(
private val activity: AppCompatActivity
) {

fun handleOnCreate() {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white_24dp)
activity.setContentView(R.layout.view_event_logs_activity)

if (getViewEventLogsFragment() == null) {
val viewEventLogsFragment = ViewEventLogsFragment
.newInstance()
activity.supportFragmentManager.beginTransaction().add(
R.id.view_event_logs_container,
viewEventLogsFragment
).commitNow()
}
}

private fun getViewEventLogsFragment(): ViewEventLogsFragment? {
return activity.supportFragmentManager
.findFragmentById(R.id.view_event_logs_container) as ViewEventLogsFragment?
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.oppia.android.app.devoptions.vieweventlogs

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.oppia.android.app.fragment.InjectableFragment
import javax.inject.Inject

/** Fragment to display all event logs. */
class ViewEventLogsFragment : InjectableFragment() {
@Inject
lateinit var viewEventLogsFragmentPresenter: ViewEventLogsFragmentPresenter

companion object {
fun newInstance(): ViewEventLogsFragment {
return ViewEventLogsFragment()
}
}

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

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return viewEventLogsFragmentPresenter.handleCreateView(inflater, container)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.oppia.android.app.devoptions.vieweventlogs

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.ViewEventLogsEventLogItemViewBinding
import org.oppia.android.databinding.ViewEventLogsFragmentBinding
import javax.inject.Inject

/** The presenter for [ViewEventLogsFragment]. */
@FragmentScope
class ViewEventLogsFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<ViewEventLogsViewModel>
) {

private lateinit var binding: ViewEventLogsFragmentBinding
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var bindingAdapter: BindableAdapter<EventLogItemViewModel>

fun handleCreateView(
inflater: LayoutInflater,
container: ViewGroup?
): View? {
binding = ViewEventLogsFragmentBinding.inflate(
inflater,
container,
/* attachToRoot= */ false
)

binding.viewEventLogsToolbar.setNavigationOnClickListener {
(activity as ViewEventLogsActivity).finish()
}

binding.apply {
this.lifecycleOwner = fragment
this.viewModel = getViewEventLogsViewModel()
}

linearLayoutManager = LinearLayoutManager(activity.applicationContext)

bindingAdapter = createRecyclerViewAdapter()
binding.viewEventLogsRecyclerView.apply {
layoutManager = linearLayoutManager
adapter = bindingAdapter
}

return binding.root
}

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

private fun getViewEventLogsViewModel(): ViewEventLogsViewModel {
return viewModelProvider.getForFragment(fragment, ViewEventLogsViewModel::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.oppia.android.app.devoptions.vieweventlogs

import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.viewmodel.ObservableViewModel
import org.oppia.android.util.logging.firebase.DebugEventLogger
import org.oppia.android.util.system.OppiaDateTimeFormatter
import javax.inject.Inject

/**
* [ViewModel] for [ViewEventLogsFragment]. It populates the recyclerview with a list of
* [EventLogItemViewModel] which in turn display the event log.
*/
@FragmentScope
class ViewEventLogsViewModel @Inject constructor(
debugEventLogger: DebugEventLogger,
private val oppiaDateTimeFormatter: OppiaDateTimeFormatter
) : ObservableViewModel() {

private val eventList = debugEventLogger.getEventList()

/**
* List of [EventLogItemViewModel] used to populate recyclerview of [ViewEventLogsFragment]
* to display event logs.
*/
val eventLogsList: List<EventLogItemViewModel> by lazy {
processEventLogsList()
}

private fun processEventLogsList(): List<EventLogItemViewModel> {
return eventList.map {
EventLogItemViewModel(it, oppiaDateTimeFormatter)
}.reversed()
}
}
Loading

0 comments on commit ef83fde

Please sign in to comment.