diff --git a/app/src/main/java/com/aurora/Constants.kt b/app/src/main/java/com/aurora/Constants.kt index 46e8f9225..b57f42ade 100644 --- a/app/src/main/java/com/aurora/Constants.kt +++ b/app/src/main/java/com/aurora/Constants.kt @@ -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" diff --git a/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt b/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt index 083c3a519..68f6343d6 100644 --- a/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt +++ b/app/src/main/java/com/aurora/store/data/model/ProxyInfo.kt @@ -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 diff --git a/app/src/main/java/com/aurora/store/view/ui/dispenser/InputDispenserDialog.kt b/app/src/main/java/com/aurora/store/view/ui/dispenser/InputDispenserDialog.kt index 46bffbe6e..2f774a043 100644 --- a/app/src/main/java/com/aurora/store/view/ui/dispenser/InputDispenserDialog.kt +++ b/app/src/main/java/com/aurora/store/view/ui/dispenser/InputDispenserDialog.kt @@ -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) } diff --git a/app/src/main/java/com/aurora/store/view/ui/preferences/NetworkPreference.kt b/app/src/main/java/com/aurora/store/view/ui/preferences/NetworkPreference.kt index e1e777e94..fd52e7d4f 100644 --- a/app/src/main/java/com/aurora/store/view/ui/preferences/NetworkPreference.kt +++ b/app/src/main/java/com/aurora/store/view/ui/preferences/NetworkPreference.kt @@ -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(Preferences.PREFERENCE_DISPENSER_URLS)?.apply { setOnPreferenceClickListener { findNavController().navigate(R.id.dispenserFragment) @@ -53,18 +56,14 @@ class NetworkPreference : BasePreferenceFragment() { } } - findPreference(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(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(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(PREFERENCE_PROXY_ENABLED)?.isChecked = + Preferences.getString(requireContext(), PREFERENCE_PROXY_URL).isNotBlank() } } } diff --git a/app/src/main/java/com/aurora/store/view/ui/preferences/ProxyURLDialog.kt b/app/src/main/java/com/aurora/store/view/ui/preferences/ProxyURLDialog.kt new file mode 100644 index 000000000..e6fba6480 --- /dev/null +++ b/app/src/main/java/com/aurora/store/view/ui/preferences/ProxyURLDialog.kt @@ -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) + } + } +} diff --git a/app/src/main/java/com/aurora/store/view/ui/preferences/SettingsViewModel.kt b/app/src/main/java/com/aurora/store/view/ui/preferences/SettingsViewModel.kt deleted file mode 100644 index 5124ae8b5..000000000 --- a/app/src/main/java/com/aurora/store/view/ui/preferences/SettingsViewModel.kt +++ /dev/null @@ -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() - 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) - } - } - } -} diff --git a/app/src/main/res/layout/dialog_dispenser_input.xml b/app/src/main/res/layout/dialog_text_input_edit_text.xml similarity index 86% rename from app/src/main/res/layout/dialog_dispenser_input.xml rename to app/src/main/res/layout/dialog_text_input_edit_text.xml index 0018c7fbe..e0cb55b06 100644 --- a/app/src/main/res/layout/dialog_dispenser_input.xml +++ b/app/src/main/res/layout/dialog_text_input_edit_text.xml @@ -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" /> diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 6da7ad08d..7d03ed59b 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -484,4 +484,8 @@ app:popUpTo="@id/mobile_navigation" app:popUpToInclusive="true" /> + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 848fea0d9..59568d40c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -233,6 +233,7 @@ "Enable proxy" "Allow all traffic from app to go through the proxy" "Proxy URL" + Enter a valid proxy URL to pass all data through the proxy. "Accent" "Black" "Dark" diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml index 7aca1db2d..c46aa9b5a 100644 --- a/app/src/main/res/xml/preferences_network.xml +++ b/app/src/main/res/xml/preferences_network.xml @@ -38,12 +38,6 @@ app:summary="@string/pref_network_proxy_enable_desc" app:title="@string/pref_network_proxy_enable" /> - -