NetworkPreference: Move out and simply proxy logic

No need to check connectivity as soon as URL is set as SplashFragment will
only let you login when a valid connection is available.

Use a modern dialog and EditText to do set the URL with minimal verification.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-07-14 14:04:15 +07:00
parent ab39597296
commit 1c701ec7f0
10 changed files with 113 additions and 110 deletions

View File

@@ -43,8 +43,6 @@ object Constants {
const val GITLAB_URL = "https://gitlab.com/AuroraOSS/AuroraStore"
const val URL_DISPENSER = "https://auroraoss.com/api/auth"
const val ANDROID_CONNECTIVITY_URL = "https://connectivitycheck.android.com/generate_204"
//ACCOUNTS
const val ACCOUNT_SIGNED_IN = "ACCOUNT_SIGNED_IN"
const val ACCOUNT_SIGNED_TIMESTAMP = "ACCOUNT_SIGNED_TIMESTAMP"

View File

@@ -1,9 +1,13 @@
package com.aurora.store.data.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class ProxyInfo(
var protocol: String,
var host: String,
var port: Int,
var proxyUser: String?,
var proxyPassword: String?
)
) : Parcelable

View File

@@ -25,7 +25,7 @@ class InputDispenserDialog: DialogFragment() {
get() = Preferences.getStringSet(requireContext(), PREFERENCE_DISPENSER_URLS)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_dispenser_input, null)
val view = layoutInflater.inflate(R.layout.dialog_text_input_edit_text, null)
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.add_dispenser_title)
.setMessage(R.string.add_dispenser_summary)
@@ -37,7 +37,10 @@ class InputDispenserDialog: DialogFragment() {
override fun onResume() {
super.onResume()
textInputLayout?.editText?.showKeyboard()
textInputLayout?.editText?.apply {
hint = requireContext().getString(R.string.add_dispenser_hint)
showKeyboard()
}
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
}

View File

@@ -19,33 +19,36 @@
package com.aurora.store.view.ui.preferences
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.SwitchPreferenceCompat
import com.aurora.extensions.runOnUiThread
import com.aurora.extensions.toast
import com.aurora.store.R
import com.aurora.store.util.CommonUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_ENABLED
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_URL
import com.aurora.store.util.remove
import com.aurora.store.util.save
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
@AndroidEntryPoint
class NetworkPreference : BasePreferenceFragment() {
class NetworkPreference : BasePreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
private val viewModel: SettingsViewModel by viewModels()
private lateinit var sharedPreferences: SharedPreferences
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences_network, rootKey)
sharedPreferences = Preferences.getPrefs(requireContext())
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
findPreference<Preference>(Preferences.PREFERENCE_DISPENSER_URLS)?.apply {
setOnPreferenceClickListener {
findNavController().navigate(R.id.dispenserFragment)
@@ -53,18 +56,14 @@ class NetworkPreference : BasePreferenceFragment() {
}
}
findPreference<EditTextPreference>(Preferences.PREFERENCE_PROXY_URL)?.let {
it.summary =
Preferences.getString(requireContext(), Preferences.PREFERENCE_PROXY_URL, "")
it.setOnPreferenceChangeListener { _, newValue ->
val newProxyUrl = newValue.toString()
val newProxyInfo = CommonUtil.parseProxyUrl(newProxyUrl)
if (newProxyInfo == null) {
requireContext().toast(getString(R.string.toast_proxy_invalid))
findPreference<SwitchPreferenceCompat>(PREFERENCE_PROXY_ENABLED)?.apply {
isChecked = Preferences.getString(context, PREFERENCE_PROXY_URL).isNotBlank()
setOnPreferenceChangeListener { _, newValue ->
if (newValue.toString().toBoolean()) {
findNavController().navigate(R.id.proxyURLDialog)
} else {
viewModel.saveProxyDetails(newProxyUrl, newProxyInfo)
remove(PREFERENCE_PROXY_URL)
remove(PREFERENCE_PROXY_INFO)
}
false
}
@@ -96,23 +95,17 @@ class NetworkPreference : BasePreferenceFragment() {
title = getString(R.string.pref_network_title)
setNavigationOnClickListener { findNavController().navigateUp() }
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.proxyURL.filter { it.isNotBlank() }.collect { pURL ->
findPreference<EditTextPreference>(Preferences.PREFERENCE_PROXY_URL)?.let {
it.summary = pURL
}
}
}
override fun onDestroyView() {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onDestroyView()
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.proxyInfo.collect {
if (it == null) {
requireContext().toast(getText(R.string.toast_proxy_failed))
} else {
requireContext().toast(getString(R.string.toast_proxy_success))
}
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == PREFERENCE_PROXY_URL) {
findPreference<SwitchPreferenceCompat>(PREFERENCE_PROXY_ENABLED)?.isChecked =
Preferences.getString(requireContext(), PREFERENCE_PROXY_URL).isNotBlank()
}
}
}

View File

@@ -0,0 +1,70 @@
package com.aurora.store.view.ui.preferences
import android.annotation.SuppressLint
import android.app.Dialog
import android.os.Bundle
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import com.aurora.extensions.showKeyboard
import com.aurora.extensions.toast
import com.aurora.store.R
import com.aurora.store.util.CommonUtil
import com.aurora.store.util.Preferences
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_URL
import com.aurora.store.util.save
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.Gson
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class ProxyURLDialog: DialogFragment() {
@Inject
lateinit var gson: Gson
private val textInputLayout: TextInputLayout?
get() = dialog?.findViewById(R.id.textInputLayout)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_text_input_edit_text, null)
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.pref_network_proxy_url)
.setMessage(R.string.pref_network_proxy_url_message)
.setView(view)
.setPositiveButton(getString(R.string.add)) { _, _ -> saveProxyUrl() }
.setNegativeButton(getString(android.R.string.cancel)) { _, _ -> dialog?.dismiss()}
.create()
}
@SuppressLint("AuthLeak") // False-positive
override fun onResume() {
super.onResume()
textInputLayout?.editText?.apply {
hint = "protocol://user:password@host:port"
setText(Preferences.getString(context, PREFERENCE_PROXY_URL))
showKeyboard()
}
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
}
private fun saveProxyUrl() {
val url = textInputLayout?.editText?.text?.toString()
if (url.isNullOrEmpty()) {
toast(R.string.add_dispenser_error)
return
}
val proxyInfo = CommonUtil.parseProxyUrl(url)
if (proxyInfo != null) {
save(PREFERENCE_PROXY_URL, url)
save(PREFERENCE_PROXY_INFO, gson.toJson(proxyInfo))
toast(R.string.toast_proxy_success)
return
} else {
toast(R.string.toast_proxy_failed)
}
}
}

View File

@@ -1,63 +0,0 @@
package com.aurora.store.view.ui.preferences
import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aurora.Constants
import com.aurora.store.data.model.ProxyInfo
import com.aurora.store.data.network.HttpClient
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_INFO
import com.aurora.store.util.Preferences.PREFERENCE_PROXY_URL
import com.aurora.store.util.save
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
@SuppressLint("StaticFieldLeak") // false positive, see https://github.com/google/dagger/issues/3253
class SettingsViewModel @Inject constructor(
private val gson: Gson,
@ApplicationContext private val context: Context
): ViewModel() {
private val TAG = SettingsViewModel::class.java.simpleName
private val _proxyURL = MutableStateFlow(String())
val proxyURL = _proxyURL.asStateFlow()
private val _proxyInfo = MutableSharedFlow<ProxyInfo?>()
val proxyInfo = _proxyInfo.asSharedFlow()
fun saveProxyDetails(url: String, info: ProxyInfo) {
viewModelScope.launch(Dispatchers.IO) {
try {
val result = HttpClient
.getPreferredClient(context)
.setProxy(info)
.get(Constants.ANDROID_CONNECTIVITY_URL, mapOf())
if (result.code == 204) {
context.save(PREFERENCE_PROXY_URL, url)
_proxyURL.value = url
context.save(PREFERENCE_PROXY_INFO, gson.toJson(info))
_proxyInfo.emit(info)
} else {
throw Exception("Failed to set proxy")
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to set proxy", exception)
_proxyInfo.emit(null)
}
}
}
}

View File

@@ -10,7 +10,6 @@
android:id="@+id/textInputEditText"
style="@style/Widget.Material3.TextInputEditText.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/add_dispenser_hint" />
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>

View File

@@ -484,4 +484,8 @@
app:popUpTo="@id/mobile_navigation"
app:popUpToInclusive="true" />
</dialog>
<dialog
android:id="@+id/proxyURLDialog"
android:name="com.aurora.store.view.ui.preferences.ProxyURLDialog"
android:label="@string/pref_network_proxy_url" />
</navigation>

View File

@@ -233,6 +233,7 @@
<string name="pref_network_proxy_enable">"Enable proxy"</string>
<string name="pref_network_proxy_enable_desc">"Allow all traffic from app to go through the proxy"</string>
<string name="pref_network_proxy_url">"Proxy URL"</string>
<string name="pref_network_proxy_url_message">Enter a valid proxy URL to pass all data through the proxy.</string>
<string name="pref_ui_accent_title">"Accent"</string>
<string name="pref_ui_theme_black">"Black"</string>
<string name="pref_ui_theme_dark">"Dark"</string>

View File

@@ -38,12 +38,6 @@
app:summary="@string/pref_network_proxy_enable_desc"
app:title="@string/pref_network_proxy_enable" />
<EditTextPreference
app:dependency="PREFERENCE_PROXY_ENABLED"
app:iconSpaceReserved="false"
app:key="PREFERENCE_PROXY_URL"
app:title="@string/pref_network_proxy_url" />
<PreferenceCategory
app:iconSpaceReserved="false"
app:singleLineTitle="false"