Skip to content

Commit

Permalink
WIP: "Request a feature" button is Settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Iliyan Germanov committed Nov 5, 2021
1 parent 229fa4d commit e66adb4
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 15 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/com/ivy/wallet/network/RestClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,5 @@ class RestClient private constructor(
val bankIntegrationsService: BankIntegrationsService by lazy {
retrofit.create(BankIntegrationsService::class.java)
}
val githubService: GithubService by lazy { retrofit.create(GithubService::class.java) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ivy.wallet.network.request.github

data class OpenIssueRequest(
val title: String,
val body: String,
val labels: List<String>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.ivy.wallet.network.request.github

data class OpenIssueResponse(
val url: String
)
20 changes: 20 additions & 0 deletions app/src/main/java/com/ivy/wallet/network/service/GithubService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ivy.wallet.network.service

import com.ivy.wallet.network.request.github.OpenIssueRequest
import com.ivy.wallet.network.request.github.OpenIssueResponse
import retrofit2.http.Body
import retrofit2.http.POST

interface GithubService {
companion object {
private const val BASE_URL = "https://api.github.com"
const val OPEN_ISSUE_URL = "$BASE_URL/repos/ILIYANGERMANOV/ivy-wallet/issues"

const val LABEL_USER_REQUEST = "user request"
}

@POST(OPEN_ISSUE_URL)
suspend fun openIssue(
@Body request: OpenIssueRequest
): OpenIssueResponse
}
21 changes: 14 additions & 7 deletions app/src/main/java/com/ivy/wallet/ui/IvyActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -484,13 +484,20 @@ class IvyActivity : AppCompatActivity() {
startActivity(intent)
}

fun openCalculatorApp() {
//TODO: It doesn't work better implement our own calculator
// val intent = Intent().apply {
// action = Intent.ACTION_MAIN
// addCategory(Intent.CATEGORY_APP_CALCULATOR)
// }
// startActivity(intent)
private fun openUrlInDefaultBrowser(url: String) {
try {
val browserIntent = Intent(Intent.ACTION_VIEW)
browserIntent.data = Uri.parse(url)
startActivity(browserIntent)
} catch (e: Exception) {
e.printStackTrace()
e.sendToCrashlytics("Cannot open URL in browser, intent not supported.")
Toast.makeText(
this,
"No browser app found. Visit manually: $url",
Toast.LENGTH_LONG
).show()
}
}

fun reviewIvyWallet(dismissReviewCard: Boolean) {
Expand Down
43 changes: 41 additions & 2 deletions app/src/main/java/com/ivy/wallet/ui/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.ivy.wallet.ui.theme.components.IvyToolbar
import com.ivy.wallet.ui.theme.modal.ChooseStartDateOfMonthModal
import com.ivy.wallet.ui.theme.modal.CurrencyModal
import com.ivy.wallet.ui.theme.modal.NameModal
import com.ivy.wallet.ui.theme.modal.RequestFeatureModal
import java.util.*

@ExperimentalFoundationApi
Expand All @@ -61,6 +62,7 @@ fun BoxWithConstraintsScope.SettingsScreen(screen: Screen.Settings) {
viewModel.start()
}

val ivyActivity = LocalContext.current as IvyActivity
val context = LocalContext.current
UI(
user = user,
Expand All @@ -82,7 +84,14 @@ fun BoxWithConstraintsScope.SettingsScreen(screen: Screen.Settings) {
viewModel.exportToCSV(context)
},
onSetLockApp = viewModel::setLockApp,
onSetStartDateOfMonth = viewModel::setStartDateOfMonth
onSetStartDateOfMonth = viewModel::setStartDateOfMonth,
onRequestFeature = { title, body ->
viewModel.requestFeature(
ivyActivity = ivyActivity,
title = title,
body = body
)
}
)
}

Expand All @@ -107,11 +116,13 @@ private fun BoxWithConstraintsScope.UI(
onLogin: () -> Unit,
onExportToCSV: () -> Unit = {},
onSetLockApp: (Boolean) -> Unit = {},
onSetStartDateOfMonth: (Int) -> Unit = {}
onSetStartDateOfMonth: (Int) -> Unit = {},
onRequestFeature: (String, String) -> Unit = { _, _ -> }
) {
var currencyModalVisible by remember { mutableStateOf(false) }
var nameModalVisible by remember { mutableStateOf(false) }
var chooseStartDateOfMonthVisible by remember { mutableStateOf(false) }
var requestFeatureModalVisible by remember { mutableStateOf(false) }

LazyColumn(
modifier = Modifier
Expand Down Expand Up @@ -246,6 +257,12 @@ private fun BoxWithConstraintsScope.UI(

Spacer(Modifier.height(12.dp))

RequestFeature {
requestFeatureModalVisible = true
}

Spacer(Modifier.height(12.dp))

ContactSupport()

Spacer(Modifier.height(12.dp))
Expand Down Expand Up @@ -282,6 +299,14 @@ private fun BoxWithConstraintsScope.UI(
) {
onSetStartDateOfMonth(it)
}

RequestFeatureModal(
visible = requestFeatureModalVisible,
dismiss = {
requestFeatureModalVisible = false
},
onSubmit = onRequestFeature
)
}

@Composable
Expand Down Expand Up @@ -327,6 +352,20 @@ private fun StartDateOfMonth(
}
}

@Composable
private fun RequestFeature(
onClick: () -> Unit
) {
SettingsPrimaryButton(
icon = R.drawable.ic_custom_rocket_m,
text = "Request a feature/improvement",
backgroundGradient = Gradient.solid(IvyTheme.colors.medium),
textColor = IvyTheme.colors.pureInverse
) {
onClick()
}
}

@Composable
private fun ContactSupport() {
val ivyContext = LocalIvyContext.current
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/com/ivy/wallet/ui/settings/SettingsViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import com.ivy.wallet.model.entity.User
import com.ivy.wallet.network.FCMClient
import com.ivy.wallet.network.RestClient
import com.ivy.wallet.network.request.auth.GoogleSignInRequest
import com.ivy.wallet.network.request.github.OpenIssueRequest
import com.ivy.wallet.network.service.GithubService
import com.ivy.wallet.persistence.SharedPrefs
import com.ivy.wallet.persistence.dao.SettingsDao
import com.ivy.wallet.persistence.dao.UserDao
Expand Down Expand Up @@ -203,4 +205,28 @@ class SettingsViewModel @Inject constructor(
_lockApp.value = lockApp
}
}

fun requestFeature(
ivyActivity: IvyActivity,
title: String,
body: String
) {
viewModelScope.launch {
try {
val response = restClient.githubService.openIssue(
OpenIssueRequest(
title = title,
body = body,
labels = listOf(
GithubService.LABEL_USER_REQUEST
)
)
)

ivyActivity.openUrlInBrowser(response.url)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
12 changes: 6 additions & 6 deletions app/src/main/java/com/ivy/wallet/ui/theme/modal/BudgetModal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ fun BoxWithConstraintsScope.BudgetModal(
ModalNameInput(
hint = "Budget name",
autoFocusKeyboard = modal?.autoFocusKeyboard ?: true,
nameTextFieldValue = nameTextFieldValue,
setNameTextFieldValue = {
textFieldValue = nameTextFieldValue,
setTextFieldValue = {
nameTextFieldValue = it
}
)
Expand Down Expand Up @@ -190,8 +190,8 @@ fun ModalNameInput(
hint: String,
autoFocusKeyboard: Boolean,

nameTextFieldValue: TextFieldValue,
setNameTextFieldValue: (TextFieldValue) -> Unit,
textFieldValue: TextFieldValue,
setTextFieldValue: (TextFieldValue) -> Unit,
) {
val nameFocus = FocusRequester()

Expand All @@ -207,7 +207,7 @@ fun ModalNameInput(
.padding(start = 32.dp, end = 36.dp)
.focusRequester(nameFocus),
underlineModifier = Modifier.padding(start = 32.dp, end = 32.dp),
value = nameTextFieldValue,
value = textFieldValue,
hint = hint,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Words,
Expand All @@ -221,7 +221,7 @@ fun ModalNameInput(
}
),
) { newValue ->
setNameTextFieldValue(newValue)
setTextFieldValue(newValue)
}
}

Expand Down
110 changes: 110 additions & 0 deletions app/src/main/java/com/ivy/wallet/ui/theme/modal/RequestFeatureModal.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.ivy.wallet.ui.theme.modal

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.ivy.wallet.base.selectEndTextFieldValue
import com.ivy.wallet.ui.IvyAppPreview
import com.ivy.wallet.ui.theme.Gray
import com.ivy.wallet.ui.theme.components.IvyDescriptionTextField
import java.util.*

@Composable
fun BoxWithConstraintsScope.RequestFeatureModal(
id: UUID = UUID.randomUUID(),
visible: Boolean,

dismiss: () -> Unit,
onSubmit: (title: String, body: String) -> Unit
) {
var title by remember(id) {
mutableStateOf(selectEndTextFieldValue(""))
}
var body by remember(id) {
mutableStateOf(selectEndTextFieldValue(""))
}


IvyModal(
id = id,
visible = visible,
dismiss = dismiss,
PrimaryAction = {
ModalSet(
label = "Submit",
enabled = title.text.isNotBlank()
) {
onSubmit(
title.text,
body.text
)
}
}
) {
Spacer(Modifier.height(32.dp))

ModalTitle(text = "Request a feature")

Spacer(Modifier.height(24.dp))

ModalNameInput(
hint = "What do you want?",
autoFocusKeyboard = true,
textFieldValue = title,
setTextFieldValue = {
title = it
}
)

Spacer(Modifier.height(16.dp))

IvyDescriptionTextField(
modifier = Modifier
.padding(horizontal = 32.dp)
.fillMaxWidth(),
keyboardOptions = KeyboardOptions(
autoCorrect = true,
capitalization = KeyboardCapitalization.Sentences,
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Default
),
keyboardActions = KeyboardActions(
onAny = {
body = body.copy(
text = StringBuilder(body.text)
.insert(body.selection.end, "\n")
.toString(),
selection = TextRange(body.selection.end + 1)
)
}
),
hint = "Explain it with one sentence. (supports markdown)",
hintColor = Gray,
value = body,
) {
body = it
}

Spacer(Modifier.height(24.dp))
}
}

@Preview
@Composable
private fun Preview() {
IvyAppPreview {
RequestFeatureModal(
visible = true,
dismiss = {},
onSubmit = { _, _ -> }
)
}
}

0 comments on commit e66adb4

Please sign in to comment.