feat(gp): rm feedback and analysis

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2024-02-03 13:22:27 +01:00
parent c891d4528c
commit 33abcf4cbb
8 changed files with 29 additions and 307 deletions

View File

@ -114,8 +114,6 @@ android {
shrinkResources true shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField "String", "SENTRY_DSN", "\"${buildproperty('sentry.dsn', 'RVX_SENTRY_DSN')}\"" buildConfigField "String", "SENTRY_DSN", "\"${buildproperty('sentry.dsn', 'RVX_SENTRY_DSN')}\""
buildConfigField "Boolean", "ANALYSIS_ENABLED", "${buildproperty('analysis.enabled', 'RVX_ANALYSIS_ENABLED')}"
buildConfigField "String", "ANALYSIS_BASEURL", "\"${buildproperty('analysis.base_url', 'RVX_ANALYSIS_BASEURL')}\""
} }
debug { debug {
@ -126,8 +124,6 @@ android {
resValue "string", "app_name", buildproperty('build.debug.app_name', 'RVX_DEBUG_APP_NAME') resValue "string", "app_name", buildproperty('build.debug.app_name', 'RVX_DEBUG_APP_NAME')
buildConfigField "String", "SENTRY_DSN", "\"${buildproperty('sentry.dsn', 'RVX_SENTRY_DSN')}\"" buildConfigField "String", "SENTRY_DSN", "\"${buildproperty('sentry.dsn', 'RVX_SENTRY_DSN')}\""
buildConfigField "Boolean", "ANALYSIS_ENABLED", "${buildproperty('analysis.enabled', 'RVX_ANALYSIS_ENABLED')}"
buildConfigField "String", "ANALYSIS_BASEURL", "\"${buildproperty('analysis.base_url', 'RVX_ANALYSIS_BASEURL')}\""
} }
} }
compileOptions { compileOptions {

View File

@ -35,7 +35,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.dialog
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import chat.revolt.BuildConfig import chat.revolt.BuildConfig
import chat.revolt.R import chat.revolt.R
@ -52,7 +51,6 @@ import chat.revolt.screens.SplashScreen
import chat.revolt.screens.about.AboutScreen import chat.revolt.screens.about.AboutScreen
import chat.revolt.screens.about.AttributionScreen import chat.revolt.screens.about.AttributionScreen
import chat.revolt.screens.chat.ChatRouterScreen import chat.revolt.screens.chat.ChatRouterScreen
import chat.revolt.screens.chat.dialogs.FeedbackDialog
import chat.revolt.screens.labs.LabsRootScreen import chat.revolt.screens.labs.LabsRootScreen
import chat.revolt.screens.login.LoginGreetingScreen import chat.revolt.screens.login.LoginGreetingScreen
import chat.revolt.screens.login.LoginScreen import chat.revolt.screens.login.LoginScreen
@ -375,7 +373,6 @@ fun AppEntrypoint(
composable("settings/appearance") { AppearanceSettingsScreen(navController) } composable("settings/appearance") { AppearanceSettingsScreen(navController) }
composable("settings/debug") { DebugSettingsScreen(navController) } composable("settings/debug") { DebugSettingsScreen(navController) }
composable("settings/changelogs") { ChangelogsSettingsScreen(navController) } composable("settings/changelogs") { ChangelogsSettingsScreen(navController) }
dialog("settings/feedback") { FeedbackDialog(navController) }
composable("about") { AboutScreen(navController) } composable("about") { AboutScreen(navController) }
composable("about/oss") { AttributionScreen(navController) } composable("about/oss") { AttributionScreen(navController) }

View File

@ -52,7 +52,7 @@ const val REVOLT_INVITES = "https://rvlt.gg"
const val REVOLT_WEBSOCKET = "wss://ws.revolt.chat" const val REVOLT_WEBSOCKET = "wss://ws.revolt.chat"
fun buildUserAgent(accessMethod: String = "Ktor"): String { fun buildUserAgent(accessMethod: String = "Ktor"): String {
return "$accessMethod RevoltAndroid/${BuildConfig.VERSION_NAME} ${BuildConfig.APPLICATION_ID} (Android ${android.os.Build.VERSION.SDK_INT}; ${android.os.Build.MANUFACTURER} ${android.os.Build.DEVICE}; Analysis ${BuildConfig.ANALYSIS_ENABLED} ${BuildConfig.ANALYSIS_BASEURL}; (Kotlin ${KotlinVersion.CURRENT})" return "$accessMethod RevoltAndroid/${BuildConfig.VERSION_NAME} ${BuildConfig.APPLICATION_ID} (Android ${android.os.Build.VERSION.SDK_INT}; ${android.os.Build.MANUFACTURER} ${android.os.Build.DEVICE}; (Kotlin ${KotlinVersion.CURRENT})"
} }
private const val BACKEND_IS_STABLE = false private const val BACKEND_IS_STABLE = false

View File

@ -1,280 +0,0 @@
package chat.revolt.screens.chat.dialogs
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.revolt.BuildConfig
import chat.revolt.R
import chat.revolt.api.REVOLT_BASE
import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp
import chat.revolt.components.generic.FormTextField
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import io.ktor.http.contentType
import kotlinx.coroutines.launch
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
enum class FeedbackType(val value: String) {
Satisfaction("satisfaction"),
FeatureRequest("featurerequest"),
BugReport("bug"),
UxFeedback("ux"),
Performance("performance"),
Security("security"),
Other("other")
}
@Serializable
data class FeedbackBody(
val type: String,
val message: String,
@SerialName("api_host")
val apiHost: String,
@SerialName("app_id")
val appId: String,
@SerialName("app_version")
val appVersion: String,
@SerialName("app_build")
val appBuild: String,
@SerialName("android_api")
val androidApi: String,
@SerialName("android_device")
val androidDevice: String,
@SerialName("android_manufacturer")
val androidManufacturer: String,
@SerialName("id_for_spam_protection_pls_dont_spam_but_if_you_do_i_will_know")
val author: String
)
suspend fun sendFeedback(type: FeedbackType, message: String): String {
val response = RevoltHttp.post("${BuildConfig.ANALYSIS_BASEURL}/api/feedback/android") {
setBody(
FeedbackBody(
type = type.value,
message = message,
apiHost = REVOLT_BASE,
appId = BuildConfig.APPLICATION_ID,
appVersion = BuildConfig.VERSION_NAME,
appBuild = BuildConfig.VERSION_CODE.toString(),
androidApi = android.os.Build.VERSION.SDK_INT.toString(),
androidDevice = android.os.Build.DEVICE,
androidManufacturer = android.os.Build.MANUFACTURER,
author = RevoltAPI.selfId ?: "RevoltAPI.selfId is null"
)
)
contentType(ContentType.Application.Json)
}
Log.d("FeedbackDialog", "Feedback sent: ${response.bodyAsText()}")
return response.bodyAsText()
}
@Composable
fun FeedbackDialog(navController: NavController) {
if (!BuildConfig.ANALYSIS_ENABLED) {
AlertDialog(onDismissRequest = {
navController.popBackStack()
}, title = {
Text(
text = stringResource(id = R.string.settings_feedback_disabled_title),
modifier = Modifier.fillMaxWidth()
)
}, text = {
Text(
text = stringResource(
id = R.string.settings_feedback_disabled_message,
BuildConfig.VERSION_NAME,
BuildConfig.BUILD_TYPE
)
)
}, confirmButton = {
TextButton(onClick = {
navController.popBackStack()
}) {
Text(text = stringResource(id = R.string.ok))
}
})
return
}
val category = mapOf(
FeedbackType.Satisfaction to stringResource(R.string.settings_feedback_category_satisfaction),
FeedbackType.FeatureRequest to stringResource(R.string.settings_feedback_category_feature),
FeedbackType.BugReport to stringResource(R.string.settings_feedback_category_bug),
FeedbackType.UxFeedback to stringResource(R.string.settings_feedback_category_ux),
FeedbackType.Performance to stringResource(R.string.settings_feedback_category_performance),
FeedbackType.Security to stringResource(R.string.settings_feedback_category_security),
FeedbackType.Other to stringResource(R.string.settings_feedback_category_other)
)
val categoryDropdownExpanded = remember { mutableStateOf(false) }
val categoryDropdownSelected = remember { mutableStateOf(FeedbackType.Satisfaction) }
val message = remember { mutableStateOf("") }
val error = remember { mutableStateOf("") }
val sending = remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val context = LocalContext.current
AlertDialog(
onDismissRequest = {
navController.popBackStack()
},
title = {
Text(
text = stringResource(id = R.string.settings_feedback),
modifier = Modifier.fillMaxWidth()
)
},
text = {
Column {
Text(
text = stringResource(id = R.string.settings_feedback_introduction)
)
Spacer(modifier = Modifier.height(16.dp))
Box {
TextField(
value = category[categoryDropdownSelected.value]
?: stringResource(id = R.string.unknown),
onValueChange = {},
label = {
Text(
text = stringResource(id = R.string.settings_feedback_category)
)
},
readOnly = true,
trailingIcon = {
IconToggleButton(
checked = categoryDropdownExpanded.value,
onCheckedChange = {
categoryDropdownExpanded.value = it
}
) {
Icon(
imageVector = Icons.Default.ArrowDropDown,
contentDescription = stringResource(
id = R.string.settings_feedback_category
)
)
}
},
modifier = Modifier.fillMaxWidth()
)
DropdownMenu(
expanded = categoryDropdownExpanded.value,
onDismissRequest = {
categoryDropdownExpanded.value = false
}
) {
category.forEach { (key, value) ->
DropdownMenuItem(
text = {
Text(text = value)
},
onClick = {
categoryDropdownSelected.value = key
categoryDropdownExpanded.value = false
}
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
FormTextField(
value = message.value,
label = stringResource(id = R.string.settings_feedback_message),
onChange = {
message.value = it
},
supportingText = {
Text(
text = "${message.value.length}/1250"
)
},
enabled = !sending.value,
singleLine = false,
modifier = Modifier.fillMaxWidth()
)
}
},
dismissButton = {
TextButton(
onClick = {
navController.popBackStack()
},
modifier = Modifier.testTag("feedback_cancel"),
enabled = !sending.value
) {
Text(text = stringResource(id = R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
if (message.value.length > 1250) {
error.value =
context.getString(R.string.settings_feedback_message_too_long, 1250)
} else {
error.value = ""
sending.value = true
scope.launch {
try {
val result =
sendFeedback(categoryDropdownSelected.value, message.value)
Log.d("FeedbackDialog", "Feedback sent with result: $result")
if (result.isBlank()) {
navController.popBackStack()
} else {
error.value = result
Toast.makeText(context, error.value, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.e("FeedbackDialog", "Error sending feedback", e)
error.value = context.getString(R.string.settings_feedback_error)
} finally {
sending.value = false
}
}
}
},
enabled = !sending.value && message.value.isNotBlank(),
modifier = Modifier.testTag("feedback_submit")
) {
Text(text = stringResource(id = R.string.report_submit))
}
}
)
}

View File

@ -1,5 +1,6 @@
package chat.revolt.screens.settings package chat.revolt.screens.settings
import android.content.Intent
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -28,16 +29,19 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import chat.revolt.BuildConfig import chat.revolt.BuildConfig
import chat.revolt.R import chat.revolt.R
import chat.revolt.activities.InviteActivity
import chat.revolt.api.RevoltAPI import chat.revolt.api.RevoltAPI
import chat.revolt.api.settings.FeatureFlags import chat.revolt.api.settings.FeatureFlags
import chat.revolt.api.settings.GlobalState import chat.revolt.api.settings.GlobalState
@ -68,6 +72,7 @@ fun SettingsScreen(
navController: NavController, navController: NavController,
viewModel: SettingsScreenViewModel = hiltViewModel() viewModel: SettingsScreenViewModel = hiltViewModel()
) { ) {
val context = LocalContext.current
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold( Scaffold(
@ -274,16 +279,27 @@ fun SettingsScreen(
text = stringResource(id = R.string.settings_feedback) text = stringResource(id = R.string.settings_feedback)
) )
}, },
supportingContent = {
Text(
text = stringResource(id = R.string.settings_feedback_description)
)
},
leadingContent = { leadingContent = {
Icon( Icon(
imageVector = Icons.Default.ArrowForward, painter = painterResource(R.drawable.ic_comment_quote_24dp),
contentDescription = null, contentDescription = null,
) )
}, },
modifier = Modifier modifier = Modifier
.testTag("settings_view_feedback") .testTag("settings_view_feedback")
.clickable { .clickable {
navController.navigate("settings/feedback") val intent = Intent(
context,
InviteActivity::class.java
).setAction(Intent.ACTION_VIEW)
intent.data = "https://rvlt.gg/Testers".toUri()
context.startActivity(intent)
} }
) )

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M20 2H4C2.9 2 2 2.9 2 4V16C2 17.1 2.9 18 4 18H8V21C8 21.6 8.4 22 9 22H9.5C9.7 22 10 21.9 10.2 21.7L13.9 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2M11 13H7V8.8L8.3 6H10.3L8.9 9H11V13M17 13H13V8.8L14.3 6H16.3L14.9 9H17V13Z" />
</vector>

View File

@ -528,21 +528,7 @@
<string name="settings_appearance_colour_overrides_import_error">This file is not a valid colour override file.</string> <string name="settings_appearance_colour_overrides_import_error">This file is not a valid colour override file.</string>
<string name="settings_feedback">Feedback</string> <string name="settings_feedback">Feedback</string>
<string name="settings_feedback_introduction">Any feedback you have for Revolt is greatly appreciated and all feedback is read by the development team of our Android app.</string> <string name="settings_feedback_description">Join the Revolt server to give feedback or suggestions and report bugs.</string>
<string name="settings_feedback_category">Category</string>
<string name="settings_feedback_category_satisfaction">General-purpose feedback</string>
<string name="settings_feedback_category_feature">Feature request</string>
<string name="settings_feedback_category_bug">Bug report</string>
<string name="settings_feedback_category_ux">User experience (UI/UX)</string>
<string name="settings_feedback_category_performance">Performance</string>
<string name="settings_feedback_category_security">Security</string>
<string name="settings_feedback_category_other">Other</string>
<string name="settings_feedback_message">Message</string>
<string name="settings_feedback_message_too_long">Message is too long. Please shorten it to %1$d characters or less.</string>
<string name="settings_feedback_error">An error occurred while sending your feedback. Please try again later.</string>
<string name="settings_feedback_disabled_title">Feedback unavailable</string>
<string name="settings_feedback_disabled_message">Feedback is not available on this build of Revolt. Support for this build is limited. (Build: %1$s %2$s)</string>
<string name="settings_changelogs">Changelogs</string> <string name="settings_changelogs">Changelogs</string>
<string name="settings_changelogs_new_header">What\'s been cooking ✨</string> <string name="settings_changelogs_new_header">What\'s been cooking ✨</string>

View File

@ -1,5 +1,3 @@
sentry.dsn= sentry.dsn=
sentry.upload_mappings=true sentry.upload_mappings=true
analysis.enabled=false
analysis.base_url=
build.debug.app_name= build.debug.app_name=