mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-1451 Space | Enhancement | Move 'Space debug' button to the 'Space' screen + Refact (#197)
This commit is contained in:
parent
073d92e44a
commit
0b1936a78f
16 changed files with 201 additions and 25 deletions
|
@ -2,21 +2,32 @@ package com.anytypeio.anytype.di.feature.settings
|
|||
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.device.share.debug.DebugSpaceDeviceFileContentSaver
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.debugging.DebugSpaceContentSaver
|
||||
import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader
|
||||
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
|
||||
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel
|
||||
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.anytypeio.anytype.providers.DefaultUriFileProvider
|
||||
import com.anytypeio.anytype.ui.settings.MainSettingFragment
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
||||
@Subcomponent(modules = [MainSettingsModule::class])
|
||||
@Subcomponent(
|
||||
modules = [
|
||||
MainSettingsModule::class,
|
||||
MainSettingsModule.Bindings::class
|
||||
]
|
||||
)
|
||||
@PerScreen
|
||||
interface MainSettingsSubComponent {
|
||||
|
||||
|
@ -70,13 +81,30 @@ object MainSettingsModule {
|
|||
configStorage: ConfigStorage,
|
||||
urlBuilder: UrlBuilder,
|
||||
setObjectDetails: SetObjectDetails,
|
||||
spaceGradientProvider: SpaceGradientProvider
|
||||
spaceGradientProvider: SpaceGradientProvider,
|
||||
debugSpaceShareDownloader: DebugSpaceShareDownloader
|
||||
): MainSettingsViewModel.Factory = MainSettingsViewModel.Factory(
|
||||
analytics,
|
||||
storelessSubscriptionContainer,
|
||||
configStorage,
|
||||
urlBuilder,
|
||||
setObjectDetails,
|
||||
spaceGradientProvider
|
||||
analytics = analytics,
|
||||
storelessSubscriptionContainer = storelessSubscriptionContainer,
|
||||
configStorage = configStorage,
|
||||
urlBuilder = urlBuilder,
|
||||
setObjectDetails = setObjectDetails,
|
||||
spaceGradientProvider = spaceGradientProvider,
|
||||
debugSpaceShareDownloader = debugSpaceShareDownloader
|
||||
)
|
||||
|
||||
@Module
|
||||
interface Bindings {
|
||||
@PerScreen
|
||||
@Binds
|
||||
fun bindUriFileProvider(
|
||||
defaultProvider: DefaultUriFileProvider
|
||||
): UriFileProvider
|
||||
|
||||
@PerScreen
|
||||
@Binds
|
||||
fun bindSpaceDebugDeviceSharer(
|
||||
saver: DebugSpaceDeviceFileContentSaver
|
||||
): DebugSpaceContentSaver
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_ui.common.ComposeDialogView
|
||||
import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
|
||||
import com.anytypeio.anytype.core_utils.ext.shareFile
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
|
@ -23,12 +24,15 @@ import com.anytypeio.anytype.di.common.componentManager
|
|||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel.Command
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel.Event
|
||||
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
|
||||
import com.anytypeio.anytype.ui.editor.modals.IconPickerFragmentBase.Companion.ARG_CONTEXT_ID_KEY
|
||||
import com.anytypeio.anytype.ui.sets.ARG_SHOW_REMOVE_BUTTON
|
||||
import com.anytypeio.anytype.ui.settings.system.SettingsActivity
|
||||
import com.anytypeio.anytype.ui_settings.main.MainSettingScreen
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class MainSettingFragment : BaseBottomSheetComposeFragment() {
|
||||
|
||||
|
@ -38,6 +42,9 @@ class MainSettingFragment : BaseBottomSheetComposeFragment() {
|
|||
@Inject
|
||||
lateinit var featureToggles: FeatureToggles
|
||||
|
||||
@Inject
|
||||
lateinit var uriFileProvider: UriFileProvider
|
||||
|
||||
private val vm by viewModels<MainSettingsViewModel> { factory }
|
||||
|
||||
private val onProfileClicked = {
|
||||
|
@ -135,13 +142,23 @@ class MainSettingFragment : BaseBottomSheetComposeFragment() {
|
|||
)
|
||||
)
|
||||
}
|
||||
Command.OpenFilesStorageScreen -> {
|
||||
is Command.OpenFilesStorageScreen -> {
|
||||
safeNavigate(R.id.actionOpenFilesStorageScreen)
|
||||
}
|
||||
|
||||
is Command.Toast -> {
|
||||
toast(msg = command.msg)
|
||||
}
|
||||
is Command.ShareSpaceDebug -> {
|
||||
try {
|
||||
shareFile(
|
||||
uriFileProvider.getUriForFile(File(command.path))
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error while sharing space debug").also {
|
||||
toast("Error while sharing space debug. Please try again later.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ class ProfileFragment : BaseBottomSheetComposeFragment() {
|
|||
onSpaceDebugClicked = { throttle { vm.onSpaceDebugClicked() } },
|
||||
isLogoutInProgress = vm.isLoggingOut.collectAsState().value,
|
||||
isDebugSpaceReportInProgress = vm.isDebugSpaceReportInProgress.collectAsState().value,
|
||||
isShowDebug = true,
|
||||
isShowDebug = false,
|
||||
onNameChange = { vm.onNameChange(it) },
|
||||
onProfileIconClick = { proceedWithIconClick() },
|
||||
account = vm.profileData.collectAsStateWithLifecycle().value,
|
||||
|
|
|
@ -6,6 +6,7 @@ typealias Url = String
|
|||
typealias Hash = String
|
||||
typealias Struct = Map<Id, Any?>
|
||||
typealias Name = String
|
||||
typealias Filepath = String
|
||||
|
||||
typealias Document = List<Block>
|
||||
|
||||
|
|
|
@ -48,9 +48,9 @@ import com.anytypeio.anytype.core_utils.const.FileConstants.REQUEST_MEDIA_CODE
|
|||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import timber.log.Timber
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import timber.log.Timber
|
||||
|
||||
fun Context.dimen(res: Int): Float {
|
||||
return resources
|
||||
|
|
|
@ -3,8 +3,7 @@ package com.anytypeio.anytype.presentation.util.downloader
|
|||
import android.net.Uri
|
||||
import java.io.File
|
||||
|
||||
// TODO move to device module
|
||||
interface UriFileProvider {
|
||||
|
||||
fun getUriForFile(file: File): Uri
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.anytypeio.anytype.data.auth.other
|
||||
|
||||
import com.anytypeio.anytype.domain.debugging.DebugSpaceContentSaver
|
||||
|
||||
interface DebugSpaceDeviceContentSaver : DebugSpaceContentSaver
|
|
@ -6,6 +6,7 @@ plugins {
|
|||
dependencies {
|
||||
|
||||
implementation project(':data')
|
||||
implementation project(':domain')
|
||||
|
||||
implementation libs.kotlin
|
||||
implementation libs.coroutinesAndroid
|
||||
|
@ -17,4 +18,6 @@ dependencies {
|
|||
testImplementation libs.kotlinTest
|
||||
testImplementation libs.androidXTestCore
|
||||
testImplementation libs.robolectric
|
||||
|
||||
compileOnly libs.javaxInject
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.anytypeio.anytype.device.share.debug
|
||||
|
||||
import android.content.Context
|
||||
import com.anytypeio.anytype.data.auth.other.DebugSpaceDeviceContentSaver
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugSpaceDeviceFileContentSaver @Inject constructor(
|
||||
private val context: Context
|
||||
) : DebugSpaceDeviceContentSaver {
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun save(content: String): File {
|
||||
val cacheDir = context.cacheDir
|
||||
|
||||
require(cacheDir != null) { "Impossible to cache files!" }
|
||||
|
||||
val filename = getFileName()
|
||||
|
||||
// Creating folder
|
||||
|
||||
val downloadFolder = File("${cacheDir.path}/$FOLDER_NAME/").apply {
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
val resultFilePath = "${cacheDir.path}/$FOLDER_NAME/${filename}"
|
||||
val resultFile = File(resultFilePath)
|
||||
|
||||
// Writing content
|
||||
|
||||
val tempFileFolderPath = "${downloadFolder.absolutePath}/$TEMP_FOLDER_NAME"
|
||||
val tempDir = File(tempFileFolderPath)
|
||||
if (tempDir.exists()) tempDir.deleteRecursively()
|
||||
tempDir.mkdirs()
|
||||
|
||||
val tempResult = File(tempFileFolderPath, filename)
|
||||
|
||||
FileOutputStream(tempResult).use { stream ->
|
||||
stream.write(content.toByteArray())
|
||||
}
|
||||
|
||||
tempResult.renameTo(resultFile)
|
||||
|
||||
// Clearing
|
||||
|
||||
tempDir.deleteRecursively()
|
||||
|
||||
// Sending file
|
||||
|
||||
return resultFile
|
||||
}
|
||||
|
||||
private fun getFileName(): String {
|
||||
val date = Calendar.getInstance().time
|
||||
val dateFormat = SimpleDateFormat(DATE_FORMAT, Locale.getDefault())
|
||||
val formattedDate = dateFormat.format(date)
|
||||
return "DebugSpace$formattedDate.txt"
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FOLDER_NAME = "debug_space"
|
||||
const val TEMP_FOLDER_NAME = "tmp"
|
||||
const val DATE_FORMAT = "dd-MM-yyyy-HH:mm:ss"
|
||||
}
|
||||
}
|
|
@ -3,8 +3,9 @@ package com.anytypeio.anytype.domain.debugging
|
|||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugSpace(
|
||||
class DebugSpace @Inject constructor(
|
||||
private val repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
) : ResultInteractor<Unit, String>(dispatchers.io) {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package com.anytypeio.anytype.domain.debugging
|
||||
|
||||
import java.io.File
|
||||
|
||||
interface DebugSpaceContentSaver {
|
||||
fun save(content: String) : File
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.anytypeio.anytype.domain.debugging
|
||||
|
||||
import com.anytypeio.anytype.core_models.Filepath
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import javax.inject.Inject
|
||||
|
||||
class DebugSpaceShareDownloader @Inject constructor(
|
||||
private val debugSpace: DebugSpace,
|
||||
private val debugSpaceContentSaver: DebugSpaceContentSaver,
|
||||
dispatchers: AppCoroutineDispatchers,
|
||||
) : ResultInteractor<Unit, Filepath>(dispatchers.io) {
|
||||
override suspend fun doWork(params: Unit): Filepath {
|
||||
val content = debugSpace.run(Unit)
|
||||
val file = debugSpaceContentSaver.save(content = content)
|
||||
return file.path
|
||||
}
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
package com.anytypeio.anytype.presentation.settings
|
||||
|
||||
import android.os.Build
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.analytics.base.EventsDictionary
|
||||
import com.anytypeio.anytype.analytics.base.sendEvent
|
||||
import com.anytypeio.anytype.core_models.Filepath
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_utils.ext.throttleFirst
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.debugging.DebugSpaceShareDownloader
|
||||
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
|
||||
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
|
||||
import com.anytypeio.anytype.presentation.BuildConfig
|
||||
import com.anytypeio.anytype.presentation.profile.ProfileIconView
|
||||
import com.anytypeio.anytype.presentation.profile.profileIcon
|
||||
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
|
||||
|
@ -37,7 +37,8 @@ class MainSettingsViewModel(
|
|||
private val configStorage: ConfigStorage,
|
||||
private val urlBuilder: UrlBuilder,
|
||||
private val setObjectDetails: SetObjectDetails,
|
||||
private val spaceGradientProvider: SpaceGradientProvider
|
||||
private val spaceGradientProvider: SpaceGradientProvider,
|
||||
private val debugSpaceShareDownloader: DebugSpaceShareDownloader
|
||||
) : ViewModel() {
|
||||
|
||||
val events = MutableSharedFlow<Event>(replay = 0)
|
||||
|
@ -99,7 +100,9 @@ class MainSettingsViewModel(
|
|||
Event.OnProfileClicked -> commands.emit(Command.OpenProfileScreen)
|
||||
Event.OnAppearanceClicked -> commands.emit(Command.OpenAppearanceScreen)
|
||||
Event.OnPersonalizationClicked -> commands.emit(Command.OpenPersonalizationScreen)
|
||||
Event.OnDebugClicked -> commands.emit(Command.OpenDebugScreen)
|
||||
Event.OnDebugClicked -> {
|
||||
proceedWithSpaceDebug()
|
||||
}
|
||||
Event.OnSpaceImageClicked -> commands.emit(
|
||||
Command.OpenSpaceImageSet(
|
||||
configStorage.get().workspace
|
||||
|
@ -111,6 +114,22 @@ class MainSettingsViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
private fun proceedWithSpaceDebug() {
|
||||
viewModelScope.launch {
|
||||
debugSpaceShareDownloader
|
||||
.stream(Unit)
|
||||
.collect { result ->
|
||||
result.fold(
|
||||
onSuccess = { path ->
|
||||
commands.emit(
|
||||
Command.ShareSpaceDebug(path)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchAnalyticEvent(event: Event) {
|
||||
when (event) {
|
||||
Event.OnAboutClicked -> {
|
||||
|
@ -178,7 +197,8 @@ class MainSettingsViewModel(
|
|||
private val configStorage: ConfigStorage,
|
||||
private val urlBuilder: UrlBuilder,
|
||||
private val setObjectDetails: SetObjectDetails,
|
||||
private val spaceGradientProvider: SpaceGradientProvider
|
||||
private val spaceGradientProvider: SpaceGradientProvider,
|
||||
private val debugSpaceShareDownloader: DebugSpaceShareDownloader
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(
|
||||
|
@ -189,7 +209,8 @@ class MainSettingsViewModel(
|
|||
configStorage = configStorage,
|
||||
urlBuilder = urlBuilder,
|
||||
setObjectDetails = setObjectDetails,
|
||||
spaceGradientProvider = spaceGradientProvider
|
||||
spaceGradientProvider = spaceGradientProvider,
|
||||
debugSpaceShareDownloader = debugSpaceShareDownloader
|
||||
) as T
|
||||
}
|
||||
|
||||
|
@ -212,6 +233,7 @@ class MainSettingsViewModel(
|
|||
class OpenSpaceImageSet(val id: Id) : Command()
|
||||
object OpenFilesStorageScreen : Command()
|
||||
data class Toast(val msg: String) : Command()
|
||||
data class ShareSpaceDebug(val path: Filepath): Command()
|
||||
}
|
||||
|
||||
sealed class WorkspaceAndAccount {
|
||||
|
@ -230,10 +252,7 @@ class MainSettingsViewModel(
|
|||
val name: String,
|
||||
val icon: ProfileIconView,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const val SPACE_STORAGE_SUBSCRIPTION_ID = "settings_space_storage_subscription"
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.anytypeio.anytype.domain.base.ResultInteractor
|
|||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
@Deprecated("To be deleted")
|
||||
class DebugSpaceFileContentSaver(
|
||||
private val context: Context,
|
||||
dispatchers: AppCoroutineDispatchers,
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.text.SimpleDateFormat
|
|||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
@Deprecated("To be deleted")
|
||||
class DebugSpaceShareDownloader(
|
||||
private val debugSpace: DebugSpace,
|
||||
private val fileSaver: DebugSpaceFileContentSaver,
|
||||
|
|
|
@ -114,6 +114,12 @@ private fun Settings(
|
|||
onClick = onFileStorageClick
|
||||
)
|
||||
Divider(paddingStart = 60.dp)
|
||||
Option(
|
||||
image = R.drawable.ic_debug,
|
||||
text = stringResource(R.string.space_debug),
|
||||
onClick = onDebugClicked
|
||||
)
|
||||
Divider(paddingStart = 60.dp)
|
||||
Option(
|
||||
image = R.drawable.ic_about,
|
||||
text = stringResource(R.string.about),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue