[Architecture] split all feature modules to api/impl
This commit is contained in:
parent
84bfb14bd9
commit
bc9f3b69cc
214 changed files with 626 additions and 1090 deletions
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.bugreport
|
||||
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import io.element.android.libraries.architecture.FeatureEntryPoint
|
||||
|
||||
interface BugReportEntryPoint : FeatureEntryPoint {
|
||||
|
||||
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
|
||||
|
||||
interface NodeBuilder {
|
||||
fun callback(callback: Callback): NodeBuilder
|
||||
fun build(): Node
|
||||
}
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onBugReportSent()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface CrashDataStore {
|
||||
fun setCrashData(crashData: String)
|
||||
|
||||
suspend fun resetAppHasCrashed()
|
||||
fun appHasCrashed(): Flow<Boolean>
|
||||
fun crashInfo(): Flow<String>
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
sealed interface CrashDetectionEvents {
|
||||
object ResetAllCrashData : CrashDetectionEvents
|
||||
object ResetAppHasCrashed : CrashDetectionEvents
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
||||
interface CrashDetectionPresenter : Presenter<CrashDetectionState>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
data class CrashDetectionState(
|
||||
val crashDetected: Boolean,
|
||||
val eventSink: (CrashDetectionEvents) -> Unit
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
fun aCrashDetectionState() = CrashDetectionState(
|
||||
crashDetected = false,
|
||||
eventSink = {}
|
||||
)
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.crash
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
fun CrashDetectionView(
|
||||
state: CrashDetectionState,
|
||||
onOpenBugReport: () -> Unit = { },
|
||||
) {
|
||||
LogCompositions(
|
||||
tag = "Crash",
|
||||
msg = "CrashDetectionScreen"
|
||||
)
|
||||
|
||||
fun onPopupDismissed() {
|
||||
state.eventSink(CrashDetectionEvents.ResetAllCrashData)
|
||||
}
|
||||
|
||||
if (state.crashDetected) {
|
||||
CrashDetectionContent(
|
||||
onYesClicked = onOpenBugReport,
|
||||
onNoClicked = ::onPopupDismissed,
|
||||
onDismiss = ::onPopupDismissed,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CrashDetectionContent(
|
||||
onNoClicked: () -> Unit = { },
|
||||
onYesClicked: () -> Unit = { },
|
||||
onDismiss: () -> Unit = { },
|
||||
) {
|
||||
ConfirmationDialog(
|
||||
title = stringResource(id = StringR.string.send_bug_report),
|
||||
content = stringResource(id = StringR.string.send_bug_report_app_crashed),
|
||||
submitText = stringResource(id = StringR.string.yes),
|
||||
cancelText = stringResource(id = StringR.string.no),
|
||||
onCancelClicked = onNoClicked,
|
||||
onSubmitClicked = onYesClicked,
|
||||
onDismiss = onDismiss,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun CrashDetectionViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun CrashDetectionViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
CrashDetectionView(
|
||||
state = aCrashDetectionState().copy(crashDetected = true)
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.detection
|
||||
|
||||
import io.element.android.features.rageshake.api.screenshot.ImageResult
|
||||
|
||||
sealed interface RageshakeDetectionEvents {
|
||||
object Dismiss : RageshakeDetectionEvents
|
||||
object Disable : RageshakeDetectionEvents
|
||||
object StartDetection : RageshakeDetectionEvents
|
||||
object StopDetection : RageshakeDetectionEvents
|
||||
data class ProcessScreenshot(val imageResult: ImageResult) : RageshakeDetectionEvents
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.detection
|
||||
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
||||
interface RageshakeDetectionPresenter : Presenter<RageshakeDetectionState>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.detection
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import io.element.android.features.rageshake.api.preferences.RageshakePreferencesState
|
||||
|
||||
@Immutable
|
||||
data class RageshakeDetectionState(
|
||||
val takeScreenshot: Boolean,
|
||||
val showDialog: Boolean,
|
||||
val isStarted: Boolean,
|
||||
val preferenceState: RageshakePreferencesState,
|
||||
val eventSink: (RageshakeDetectionEvents) -> Unit
|
||||
)
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.detection
|
||||
|
||||
import io.element.android.features.rageshake.api.preferences.aRageshakePreferencesState
|
||||
|
||||
fun aRageshakeDetectionState() = RageshakeDetectionState(
|
||||
takeScreenshot = false,
|
||||
showDialog = false,
|
||||
isStarted = false,
|
||||
preferenceState = aRageshakePreferencesState(),
|
||||
eventSink = {}
|
||||
)
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.detection
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import io.element.android.features.rageshake.api.screenshot.ImageResult
|
||||
import io.element.android.features.rageshake.api.screenshot.screenshot
|
||||
import io.element.android.libraries.androidutils.hardware.vibrate
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
fun RageshakeDetectionView(
|
||||
state: RageshakeDetectionState,
|
||||
onOpenBugReport: () -> Unit = { },
|
||||
) {
|
||||
LogCompositions(
|
||||
tag = "Rageshake",
|
||||
msg = "RageshakeDetectionScreen"
|
||||
)
|
||||
val eventSink = state.eventSink
|
||||
val context = LocalContext.current
|
||||
OnLifecycleEvent { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_RESUME -> eventSink(RageshakeDetectionEvents.StartDetection)
|
||||
Lifecycle.Event.ON_PAUSE -> eventSink(RageshakeDetectionEvents.StopDetection)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
when {
|
||||
state.takeScreenshot -> TakeScreenshot(
|
||||
onScreenshotTaken = { eventSink(RageshakeDetectionEvents.ProcessScreenshot(it)) }
|
||||
)
|
||||
state.showDialog -> {
|
||||
LaunchedEffect(Unit) {
|
||||
context.vibrate()
|
||||
}
|
||||
RageshakeDialogContent(
|
||||
onNoClicked = { eventSink(RageshakeDetectionEvents.Dismiss) },
|
||||
onDisableClicked = { eventSink(RageshakeDetectionEvents.Disable) },
|
||||
onYesClicked = onOpenBugReport
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TakeScreenshot(
|
||||
onScreenshotTaken: (ImageResult) -> Unit = {}
|
||||
) {
|
||||
val view = LocalView.current
|
||||
LaunchedEffect(Unit) {
|
||||
view.screenshot {
|
||||
onScreenshotTaken(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RageshakeDialogContent(
|
||||
onNoClicked: () -> Unit = { },
|
||||
onDisableClicked: () -> Unit = { },
|
||||
onYesClicked: () -> Unit = { },
|
||||
) {
|
||||
ConfirmationDialog(
|
||||
title = stringResource(id = StringR.string.send_bug_report),
|
||||
content = stringResource(id = StringR.string.send_bug_report_alert_message),
|
||||
thirdButtonText = stringResource(id = StringR.string.action_disable),
|
||||
submitText = stringResource(id = StringR.string.yes),
|
||||
cancelText = stringResource(id = StringR.string.no),
|
||||
onCancelClicked = onNoClicked,
|
||||
onThirdButtonClicked = onDisableClicked,
|
||||
onSubmitClicked = onYesClicked,
|
||||
onDismiss = onNoClicked,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RageshakeDialogContentLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RageshakeDialogContentDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
RageshakeDialogContent()
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.preferences
|
||||
|
||||
sealed interface RageshakePreferencesEvents {
|
||||
data class SetSensitivity(val sensitivity: Float) : RageshakePreferencesEvents
|
||||
data class SetIsEnabled(val isEnabled: Boolean) : RageshakePreferencesEvents
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.preferences
|
||||
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
||||
interface RageshakePreferencesPresenter : Presenter<RageshakePreferencesState>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.preferences
|
||||
|
||||
data class RageshakePreferencesState(
|
||||
val isEnabled: Boolean,
|
||||
val isSupported: Boolean,
|
||||
val sensitivity: Float,
|
||||
val eventSink: (RageshakePreferencesEvents) -> Unit,
|
||||
)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.preferences
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
||||
open class RageshakePreferencesStateProvider : PreviewParameterProvider<RageshakePreferencesState> {
|
||||
override val values: Sequence<RageshakePreferencesState>
|
||||
get() = sequenceOf(
|
||||
aRageshakePreferencesState().copy(isEnabled = true, isSupported = true, sensitivity = 0.5f),
|
||||
aRageshakePreferencesState().copy(isEnabled = true, isSupported = false, sensitivity = 0.5f),
|
||||
)
|
||||
}
|
||||
|
||||
fun aRageshakePreferencesState() = RageshakePreferencesState(
|
||||
isEnabled = false,
|
||||
isSupported = true,
|
||||
sensitivity = 0.3f,
|
||||
eventSink = {}
|
||||
)
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.preferences
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSlide
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
fun RageshakePreferencesView(
|
||||
state: RageshakePreferencesState,
|
||||
modifier: Modifier = Modifier,
|
||||
onOpenRageshake: () -> Unit = {},
|
||||
) {
|
||||
fun onSensitivityChanged(sensitivity: Float) {
|
||||
state.eventSink(RageshakePreferencesEvents.SetSensitivity(sensitivity = sensitivity))
|
||||
}
|
||||
|
||||
fun onEnabledChanged(isEnabled: Boolean) {
|
||||
state.eventSink(RageshakePreferencesEvents.SetIsEnabled(isEnabled = isEnabled))
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
PreferenceCategory(title = stringResource(id = StringR.string.send_bug_report)) {
|
||||
PreferenceText(
|
||||
title = stringResource(id = StringR.string.send_bug_report),
|
||||
icon = Icons.Default.BugReport,
|
||||
onClick = onOpenRageshake
|
||||
)
|
||||
}
|
||||
PreferenceCategory(title = stringResource(id = StringR.string.settings_rageshake)) {
|
||||
if (state.isSupported) {
|
||||
PreferenceSwitch(
|
||||
title = stringResource(id = StringR.string.send_bug_report_rage_shake),
|
||||
isChecked = state.isEnabled,
|
||||
onCheckedChange = ::onEnabledChanged
|
||||
)
|
||||
PreferenceSlide(
|
||||
title = stringResource(id = StringR.string.settings_rageshake_detection_threshold),
|
||||
// summary = stringResource(id = StringR.string.settings_rageshake_detection_threshold_summary),
|
||||
value = state.sensitivity,
|
||||
enabled = state.isEnabled,
|
||||
steps = 3 /* 5 possible values - steps are in ]0, 1[ */,
|
||||
onValueChange = ::onSensitivityChanged
|
||||
)
|
||||
} else {
|
||||
PreferenceText(title = "Rageshaking is not supported by your device")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RageshakePreferencesViewLightPreview(@PreviewParameter(RageshakePreferencesStateProvider::class) state: RageshakePreferencesState) =
|
||||
ElementPreviewLight { ContentToPreview(state) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RageshakePreferencesViewDarkPreview(@PreviewParameter(RageshakePreferencesStateProvider::class) state: RageshakePreferencesState) =
|
||||
ElementPreviewDark { ContentToPreview(state) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(state: RageshakePreferencesState) {
|
||||
RageshakePreferencesView(state)
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.rageshake
|
||||
|
||||
interface RageShake {
|
||||
/**
|
||||
* Check if the feature is available on this device.
|
||||
*/
|
||||
fun isAvailable(): Boolean
|
||||
|
||||
fun start(sensitivity: Float)
|
||||
|
||||
fun stop()
|
||||
|
||||
/**
|
||||
* sensitivity will be {0, O.25, 0.5, 0.75, 1} and converted to
|
||||
* [ShakeDetector.SENSITIVITY_LIGHT (=11), ShakeDetector.SENSITIVITY_HARD (=15)].
|
||||
*/
|
||||
fun setSensitivity(sensitivity: Float)
|
||||
|
||||
fun setInterceptor(interceptor: (() -> Unit)?)
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.rageshake
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface RageshakeDataStore {
|
||||
fun isEnabled(): Flow<Boolean>
|
||||
|
||||
suspend fun setIsEnabled(isEnabled: Boolean)
|
||||
|
||||
fun sensitivity(): Flow<Float>
|
||||
|
||||
suspend fun setSensitivity(sensitivity: Float)
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.reporter
|
||||
|
||||
import io.element.android.features.rageshake.api.reporter.BugReporterListener
|
||||
import io.element.android.features.rageshake.api.reporter.ReportType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
interface BugReporter {
|
||||
/**
|
||||
* Send a bug report.
|
||||
*
|
||||
* @param coroutineScope The coroutine scope
|
||||
* @param reportType The report type (bug, suggestion, feedback)
|
||||
* @param withDevicesLogs true to include the device log
|
||||
* @param withCrashLogs true to include the crash logs
|
||||
* @param withKeyRequestHistory true to include the crash logs
|
||||
* @param withScreenshot true to include the screenshot
|
||||
* @param theBugDescription the bug description
|
||||
* @param serverVersion version of the server
|
||||
* @param canContact true if the user opt in to be contacted directly
|
||||
* @param customFields fields which will be sent with the report
|
||||
* @param listener the listener
|
||||
*/
|
||||
fun sendBugReport(
|
||||
coroutineScope: CoroutineScope,
|
||||
reportType: ReportType,
|
||||
withDevicesLogs: Boolean,
|
||||
withCrashLogs: Boolean,
|
||||
withKeyRequestHistory: Boolean,
|
||||
withScreenshot: Boolean,
|
||||
theBugDescription: String,
|
||||
serverVersion: String,
|
||||
canContact: Boolean = false,
|
||||
customFields: Map<String, String>? = null,
|
||||
listener: BugReporterListener?
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.reporter
|
||||
|
||||
/**
|
||||
* Bug report upload listener.
|
||||
*/
|
||||
interface BugReporterListener {
|
||||
/**
|
||||
* The bug report has been cancelled.
|
||||
*/
|
||||
fun onUploadCancelled()
|
||||
|
||||
/**
|
||||
* The bug report upload failed.
|
||||
*
|
||||
* @param reason the failure reason
|
||||
*/
|
||||
fun onUploadFailed(reason: String?)
|
||||
|
||||
/**
|
||||
* The upload progress (in percent).
|
||||
*
|
||||
* @param progress the upload progress
|
||||
*/
|
||||
fun onProgress(progress: Int)
|
||||
|
||||
/**
|
||||
* The bug report upload succeeded.
|
||||
*/
|
||||
fun onUploadSucceed(reportUrl: String?)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.reporter
|
||||
|
||||
enum class ReportType {
|
||||
BUG_REPORT,
|
||||
SUGGESTION,
|
||||
SPACE_BETA_FEEDBACK,
|
||||
THREADS_BETA_FEEDBACK,
|
||||
AUTO_UISI,
|
||||
AUTO_UISI_SENDER,
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.screenshot
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.PixelCopy
|
||||
import android.view.View
|
||||
|
||||
fun View.screenshot(bitmapCallback: (ImageResult) -> Unit) {
|
||||
try {
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
val bitmap = Bitmap.createBitmap(
|
||||
width,
|
||||
height,
|
||||
Bitmap.Config.ARGB_8888,
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
PixelCopy.request(
|
||||
(this.context as Activity).window,
|
||||
clipBounds,
|
||||
bitmap,
|
||||
{
|
||||
when (it) {
|
||||
PixelCopy.SUCCESS -> {
|
||||
bitmapCallback.invoke(ImageResult.Success(bitmap))
|
||||
}
|
||||
else -> {
|
||||
bitmapCallback.invoke(ImageResult.Error(Exception(it.toString())))
|
||||
}
|
||||
}
|
||||
},
|
||||
handler
|
||||
)
|
||||
} else {
|
||||
handler.post {
|
||||
val canvas = Canvas(bitmap)
|
||||
.apply {
|
||||
translate(-clipBounds.left.toFloat(), -clipBounds.top.toFloat())
|
||||
}
|
||||
this.draw(canvas)
|
||||
canvas.setBitmap(null)
|
||||
bitmapCallback.invoke(ImageResult.Success(bitmap))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
bitmapCallback.invoke(ImageResult.Error(e))
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface ImageResult {
|
||||
data class Error(val exception: Exception) : ImageResult
|
||||
data class Success(val data: Bitmap) : ImageResult
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.rageshake.api.screenshot
|
||||
|
||||
import android.graphics.Bitmap
|
||||
|
||||
interface ScreenshotHolder {
|
||||
fun writeBitmap(data: Bitmap)
|
||||
fun getFileUri(): String?
|
||||
fun reset()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue