Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions app/src/main/java/org/openedx/app/AppViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.openedx.core.BaseViewModel
import org.openedx.core.SingleEventLiveData
import org.openedx.core.config.Config
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.utils.FileUtil

class AppViewModel(
private val config: Config,
Expand All @@ -21,6 +22,7 @@ class AppViewModel(
private val preferencesManager: CorePreferences,
private val dispatcher: CoroutineDispatcher,
private val analytics: AppAnalytics,
private val fileUtil: FileUtil,
) : BaseViewModel() {

private val _logoutUser = SingleEventLiveData<Unit>()
Expand All @@ -32,10 +34,14 @@ class AppViewModel(
private var logoutHandledAt: Long = 0

val isBranchEnabled get() = config.getBranchConfig().enabled
private val canResetAppDirectory get() = preferencesManager.canResetAppDirectory

override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
setUserId()
if (canResetAppDirectory) {
resetAppDirectory()
}
viewModelScope.launch {
notifier.notifier.collect { event ->
if (event is LogoutEvent && System.currentTimeMillis() - logoutHandledAt > 5000) {
Expand All @@ -60,6 +66,11 @@ class AppViewModel(
)
}

private fun resetAppDirectory() {
fileUtil.deleteOldAppDirectory()
preferencesManager.canResetAppDirectory = false
}

private fun setUserId() {
preferencesManager.user?.let {
analytics.setUserIdForSession(it.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences
}
get() = getBoolean(APP_WAS_POSITIVE_RATED)

override var canResetAppDirectory: Boolean
set(value) {
saveBoolean(RESET_APP_DIRECTORY, value)
}
get() = getBoolean(RESET_APP_DIRECTORY, true)

override fun setCalendarSyncEventsDialogShown(courseName: String) {
saveBoolean(courseName.replaceSpace("_"), true)
}
Expand All @@ -172,5 +178,6 @@ class PreferencesManager(context: Context) : CorePreferences, ProfilePreferences
private const val VIDEO_SETTINGS_STREAMING_QUALITY = "video_settings_streaming_quality"
private const val VIDEO_SETTINGS_DOWNLOAD_QUALITY = "video_settings_download_quality"
private const val APP_CONFIG = "app_config"
private const val RESET_APP_DIRECTORY = "reset_app_directory"
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel

val screenModule = module {

viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get()) }
viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get(), get()) }
viewModel { MainViewModel(get(), get(), get()) }

factory { AuthRepository(get(), get(), get()) }
Expand Down
35 changes: 32 additions & 3 deletions app/src/test/java/org/openedx/AppViewModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.openedx.app.system.notifier.AppNotifier
import org.openedx.app.system.notifier.LogoutEvent
import org.openedx.core.config.Config
import org.openedx.core.data.model.User
import org.openedx.core.utils.FileUtil

@ExperimentalCoroutinesApi
class AppViewModelTest {
Expand All @@ -42,6 +43,7 @@ class AppViewModelTest {
private val room = mockk<AppDatabase>()
private val preferencesManager = mockk<PreferencesManager>()
private val analytics = mockk<AppAnalytics>()
private val fileUtil = mockk<FileUtil>()

private val user = User(0, "", "", "")

Expand All @@ -60,8 +62,17 @@ class AppViewModelTest {
every { analytics.setUserIdForSession(any()) } returns Unit
every { preferencesManager.user } returns user
every { notifier.notifier } returns flow { }
every { preferencesManager.canResetAppDirectory } returns false
val viewModel =
AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics)
AppViewModel(
config,
notifier,
room,
preferencesManager,
dispatcher,
analytics,
fileUtil
)

val mockLifeCycleOwner: LifecycleOwner = mockk()
val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
Expand All @@ -82,8 +93,17 @@ class AppViewModelTest {
every { preferencesManager.user } returns user
every { room.clearAllTables() } returns Unit
every { analytics.logoutEvent(true) } returns Unit
every { preferencesManager.canResetAppDirectory } returns false
val viewModel =
AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics)
AppViewModel(
config,
notifier,
room,
preferencesManager,
dispatcher,
analytics,
fileUtil
)

val mockLifeCycleOwner: LifecycleOwner = mockk()
val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
Expand All @@ -106,8 +126,17 @@ class AppViewModelTest {
every { preferencesManager.user } returns user
every { room.clearAllTables() } returns Unit
every { analytics.logoutEvent(true) } returns Unit
every { preferencesManager.canResetAppDirectory } returns false
val viewModel =
AppViewModel(config, notifier, room, preferencesManager, dispatcher, analytics)
AppViewModel(
config,
notifier,
room,
preferencesManager,
dispatcher,
analytics,
fileUtil
)

val mockLifeCycleOwner: LifecycleOwner = mockk()
val lifecycleRegistry = LifecycleRegistry(mockLifeCycleOwner)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface CorePreferences {
var user: User?
var videoSettings: VideoSettings
var appConfig: AppConfig
var canResetAppDirectory: Boolean

fun clear()
}
43 changes: 42 additions & 1 deletion core/src/main/java/org/openedx/core/utils/FileUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import java.io.File
import java.util.Collections

class FileUtil(val context: Context) {

Expand All @@ -15,7 +16,10 @@ class FileUtil(val context: Context) {
return file
}

inline fun <reified T> saveObjectToFile(obj: T, fileName: String = "${T::class.java.simpleName}.json") {
inline fun <reified T> saveObjectToFile(
obj: T,
fileName: String = "${T::class.java.simpleName}.json",
) {
val gson: Gson = GsonBuilder().setPrettyPrinting().create()
val jsonString = gson.toJson(obj)
File(getExternalAppDir().path + fileName).writeText(jsonString)
Expand All @@ -31,6 +35,43 @@ class FileUtil(val context: Context) {
null
}
}

/**
* Deletes all the files and directories in the app's external storage directory.
*/
fun deleteOldAppDirectory() {
val externalFilesDir = context.getExternalFilesDir(null)
val externalAppDir = File(externalFilesDir?.parentFile, Directories.VIDEOS.name)
if (externalAppDir.isDirectory) {
deleteRecursive(externalAppDir, Collections.emptyList())
}
}

/**
* Deletes a file or directory and all its content recursively.
*
* @param fileOrDirectory The file or directory that needs to be deleted.
* @param exceptions Names of the files or directories that need to be skipped while deletion.
*/
private fun deleteRecursive(
fileOrDirectory: File,
exceptions: List<String>,
) {
if (exceptions.contains(fileOrDirectory.name)) return

if (fileOrDirectory.isDirectory) {
val filesList = fileOrDirectory.listFiles()
if (filesList != null) {
for (child in filesList) {
deleteRecursive(child, exceptions)
}
}
}

// Don't break the recursion upon encountering an error
// noinspection ResultOfMethodCallIgnored
fileOrDirectory.delete()
}
}

enum class Directories {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ private fun CourseItem(
apiHostUrl: String,
enrolledCourse: EnrolledCourse,
windowSize: WindowSize,
onClick: (EnrolledCourse) -> Unit
onClick: (EnrolledCourse) -> Unit,
) {
val imageWidth by remember(key1 = windowSize) {
mutableStateOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DashboardListViewModel(
private val resourceManager: ResourceManager,
private val discoveryNotifier: DiscoveryNotifier,
private val analytics: DashboardAnalytics,
private val appUpgradeNotifier: AppUpgradeNotifier
private val appUpgradeNotifier: AppUpgradeNotifier,
) : BaseViewModel() {

private val coursesList = mutableListOf<EnrolledCourse>()
Expand Down