diff options
Diffstat (limited to 'android/app')
24 files changed, 7 insertions, 835 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/RecyclerViewMatcher.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/RecyclerViewMatcher.kt deleted file mode 100644 index c5093f3ceb..0000000000 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/RecyclerViewMatcher.kt +++ /dev/null @@ -1,52 +0,0 @@ -package net.mullvad.mullvadvpn - -import android.content.res.Resources -import android.content.res.Resources.NotFoundException -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import org.hamcrest.Description -import org.hamcrest.Matcher -import org.hamcrest.TypeSafeMatcher - -class RecyclerViewMatcher(private val recyclerViewId: Int) { - fun atPosition(position: Int): Matcher<View> { - return atPositionOnView(position) - } - - fun atPositionOnView(position: Int, targetViewId: Int? = null): Matcher<View> = - object : TypeSafeMatcher<View>() { - var resources: Resources? = null - var childView: View? = null - - override fun describeTo(description: Description) { - val idDescription = - resources?.let { - try { - it.getResourceName(recyclerViewId) - } catch (var4: NotFoundException) { - "$recyclerViewId (resource name not found)" - } - } - ?: recyclerViewId.toString() - description.appendText("with id: $idDescription") - } - - override fun matchesSafely(view: View): Boolean { - resources = view.resources - val recyclerView = view.rootView.findViewById<View>(recyclerViewId) as RecyclerView? - if (recyclerView == null || recyclerView.id != recyclerViewId) { - return false - } - childView = recyclerView.findViewHolderForAdapterPosition(position)?.itemView - val targetView = - targetViewId?.let { id -> childView?.findViewById<View>(id) } ?: childView - return view == targetView - } - } - - companion object { - fun withRecyclerView(recyclerViewId: Int): RecyclerViewMatcher { - return RecyclerViewMatcher(recyclerViewId) - } - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CustomTransformationMethod.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CustomTransformationMethod.kt deleted file mode 100644 index 451c51fa3f..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/CustomTransformationMethod.kt +++ /dev/null @@ -1,50 +0,0 @@ -package net.mullvad.mullvadvpn.ui - -import android.graphics.Rect -import android.text.method.PasswordTransformationMethod -import android.text.method.TransformationMethod -import android.view.View - -private const val BIG_DOT_CHAR = '●' -private const val DOT_CHAR = '\u2022' -private const val EMPTY_STRING = "" -private const val SPACE_CHAR = ' ' - -class GroupedTransformationMethod : TransformationMethod { - override fun getTransformation(source: CharSequence?, view: View?): CharSequence { - return source?.groupWithSpaces() ?: EMPTY_STRING - } - - override fun onFocusChanged( - view: View?, - sourceText: CharSequence?, - focused: Boolean, - direction: Int, - previouslyFocusedRect: Rect? - ) { - // No focus handling required. - } -} - -class GroupedPasswordTransformationMethod : PasswordTransformationMethod() { - override fun getTransformation(source: CharSequence?, view: View?): CharSequence { - return if (source != null && view != null) { - super.getTransformation(source, view) - ?.toString() - ?.replace(DOT_CHAR, BIG_DOT_CHAR) - ?.groupWithSpaces() - ?: EMPTY_STRING - } else { - EMPTY_STRING - } - } -} - -private fun CharSequence.groupWithSpaces(groupCharSize: Int = 4): CharSequence { - return fold(StringBuilder()) { formattedText, nextDigit -> - if ((formattedText.length % (groupCharSize + 1)) == groupCharSize) { - formattedText.append(SPACE_CHAR) - } - formattedText.append(nextDigit) - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/NavigationBarPainter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/NavigationBarPainter.kt deleted file mode 100644 index 1047793f6f..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/NavigationBarPainter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.mullvad.mullvadvpn.ui - -import android.app.Activity -import androidx.annotation.ColorInt - -interface NavigationBarPainter : SystemPainter - -fun NavigationBarPainter.paintNavigationBar(@ColorInt color: Int) { - (getContext() as Activity?)?.window?.navigationBarColor = color -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/StatusBarPainter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/StatusBarPainter.kt deleted file mode 100644 index 48f94e17b5..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/StatusBarPainter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.mullvad.mullvadvpn.ui - -import android.app.Activity -import androidx.annotation.ColorInt - -interface StatusBarPainter : SystemPainter - -fun StatusBarPainter.paintStatusBar(@ColorInt color: Int) { - (getContext() as Activity?)?.window?.statusBarColor = color -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SystemPainter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SystemPainter.kt deleted file mode 100644 index 2f0fc32775..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/SystemPainter.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.mullvad.mullvadvpn.ui - -import android.content.Context - -interface SystemPainter { - fun getContext(): Context? -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt index b0784d62a9..3bd46d9f52 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AccountFragment.kt @@ -11,13 +11,11 @@ import androidx.compose.ui.platform.ComposeView import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.AccountScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.ui.NavigationBarPainter -import net.mullvad.mullvadvpn.ui.StatusBarPainter import net.mullvad.mullvadvpn.ui.extension.requireMainActivity import net.mullvad.mullvadvpn.viewmodel.AccountViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -class AccountFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { +class AccountFragment : BaseFragment() { private val vm by viewModel<AccountViewModel>() @OptIn(ExperimentalMaterial3Api::class) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt index afb2ec9d94..374b27e668 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/ConnectFragment.kt @@ -12,12 +12,11 @@ import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.ConnectScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.ui.MainActivity -import net.mullvad.mullvadvpn.ui.NavigationBarPainter import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild import net.mullvad.mullvadvpn.viewmodel.ConnectViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -class ConnectFragment : BaseFragment(), NavigationBarPainter { +class ConnectFragment : BaseFragment() { // Injected dependencies private val connectViewModel: ConnectViewModel by viewModel() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoadingFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoadingFragment.kt index 0000351c33..d2f0cbfb6e 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoadingFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoadingFragment.kt @@ -10,10 +10,8 @@ import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.LoadingScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.ui.MainActivity -import net.mullvad.mullvadvpn.ui.NavigationBarPainter -import net.mullvad.mullvadvpn.ui.StatusBarPainter -class LoadingFragment : Fragment(), StatusBarPainter, NavigationBarPainter { +class LoadingFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt index 9fd6e5aceb..92d58066ee 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/LoginFragment.kt @@ -13,12 +13,11 @@ import net.mullvad.mullvadvpn.compose.screen.LoginScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.model.AccountToken import net.mullvad.mullvadvpn.ui.MainActivity -import net.mullvad.mullvadvpn.ui.NavigationBarPainter import net.mullvad.mullvadvpn.viewmodel.LoginUiSideEffect import net.mullvad.mullvadvpn.viewmodel.LoginViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -class LoginFragment : BaseFragment(), NavigationBarPainter { +class LoginFragment : BaseFragment() { private val vm: LoginViewModel by viewModel() override fun onCreateView( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/PrivacyDisclaimerFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/PrivacyDisclaimerFragment.kt index 4b500d3f58..ed45382013 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/PrivacyDisclaimerFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/PrivacyDisclaimerFragment.kt @@ -13,13 +13,11 @@ import net.mullvad.mullvadvpn.compose.screen.PrivacyDisclaimerScreen import net.mullvad.mullvadvpn.lib.endpoint.getApiEndpointConfigurationExtras import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.ui.MainActivity -import net.mullvad.mullvadvpn.ui.NavigationBarPainter -import net.mullvad.mullvadvpn.ui.StatusBarPainter import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild import net.mullvad.mullvadvpn.viewmodel.PrivacyDisclaimerViewModel import org.koin.android.ext.android.inject -class PrivacyDisclaimerFragment : Fragment(), StatusBarPainter, NavigationBarPainter { +class PrivacyDisclaimerFragment : Fragment() { private val privacyDisclaimerViewModel: PrivacyDisclaimerViewModel by inject() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt index d56b51850b..d1c4ac72bf 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SelectLocationFragment.kt @@ -9,12 +9,10 @@ import androidx.compose.ui.platform.ComposeView import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.SelectLocationScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.ui.NavigationBarPainter -import net.mullvad.mullvadvpn.ui.StatusBarPainter import net.mullvad.mullvadvpn.viewmodel.SelectLocationViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -class SelectLocationFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { +class SelectLocationFragment : BaseFragment() { private val vm by viewModel<SelectLocationViewModel>() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt index 64b3e6b425..e5faf6bb11 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/SettingsFragment.kt @@ -11,12 +11,10 @@ import androidx.fragment.app.Fragment import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.screen.SettingsScreen import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.ui.NavigationBarPainter -import net.mullvad.mullvadvpn.ui.StatusBarPainter import net.mullvad.mullvadvpn.viewmodel.SettingsViewModel import org.koin.androidx.viewmodel.ext.android.viewModel -class SettingsFragment : BaseFragment(), StatusBarPainter, NavigationBarPainter { +class SettingsFragment : BaseFragment() { private val vm by viewModel<SettingsViewModel>() @OptIn(ExperimentalMaterial3Api::class) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt deleted file mode 100644 index efa2d6f5a6..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt +++ /dev/null @@ -1,75 +0,0 @@ -package net.mullvad.mullvadvpn.ui.widget - -import android.content.Context -import android.util.AttributeSet -import android.util.TypedValue -import android.view.Gravity -import android.view.LayoutInflater -import android.widget.LinearLayout -import android.widget.TextView -import net.mullvad.mullvadvpn.R - -class BackButton : LinearLayout { - private val container = - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service -> - val inflater = service as LayoutInflater - - inflater.inflate(R.layout.settings_back_button, this) - } - - private val label = container.findViewById<TextView>(R.id.label) - - constructor(context: Context) : super(context) - - constructor(context: Context, attributes: AttributeSet) : super(context, attributes) { - loadAttributes(attributes) - } - - constructor( - context: Context, - attributes: AttributeSet, - defaultStyleAttribute: Int - ) : super(context, attributes, defaultStyleAttribute) { - loadAttributes(attributes) - } - - constructor( - context: Context, - attributes: AttributeSet, - defaultStyleAttribute: Int, - defaultStyleResource: Int - ) : super(context, attributes, defaultStyleAttribute, defaultStyleResource) { - loadAttributes(attributes) - } - - init { - isFocusable = true - isClickable = true - gravity = Gravity.CENTER_VERTICAL or Gravity.START - orientation = HORIZONTAL - - resources.getDimensionPixelSize(R.dimen.settings_back_button_padding).let { padding -> - setPadding(padding, padding, padding, padding) - } - - loadBackground() - } - - private fun loadAttributes(attributes: AttributeSet) { - context.theme.obtainStyledAttributes(attributes, R.styleable.TextAttribute, 0, 0).apply { - try { - label.text = getString(R.styleable.TextAttribute_text) ?: "" - } finally { - recycle() - } - } - } - - private fun loadBackground() { - val typedValue = TypedValue() - - context.theme.resolveAttribute(android.R.attr.selectableItemBackground, typedValue, true) - - setBackgroundResource(typedValue.resourceId) - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Button.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Button.kt deleted file mode 100644 index e6c266683b..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Button.kt +++ /dev/null @@ -1,171 +0,0 @@ -package net.mullvad.mullvadvpn.ui.widget - -import android.content.Context -import android.graphics.drawable.Drawable -import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.View -import android.widget.FrameLayout -import android.widget.ImageView -import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.lib.common.util.JobTracker - -open class Button : FrameLayout { - enum class ButtonColor { - Blue, - Green, - Red; - - companion object { - internal fun fromCode(code: Int): ButtonColor { - when (code) { - 0 -> return Blue - 1 -> return Green - 2 -> return Red - else -> throw Exception("Invalid buttonColor attribute value") - } - } - } - } - - private val container = - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service -> - val inflater = service as LayoutInflater - - inflater.inflate(R.layout.button, this) - } - - private val button = container.findViewById<android.widget.Button>(R.id.button) - private val spinner: View = container.findViewById(R.id.spinner) - private val image: ImageView = container.findViewById(R.id.image) - - private var clickJobName: String? = null - private var onClickAction: (suspend () -> Unit)? = null - - protected var jobTracker: JobTracker? = null - - var buttonColor: ButtonColor = ButtonColor.Blue - set(value) { - field = value - - val backgroundResource = - when (value) { - ButtonColor.Blue -> R.drawable.blue_button_background - ButtonColor.Green -> R.drawable.green_button_background - ButtonColor.Red -> R.drawable.red_button_background - } - - button.setBackgroundResource(backgroundResource) - } - - var detailImage: Drawable? = null - set(value) { - field = value - - image.apply { - if (value == null) { - visibility = GONE - } else { - visibility = VISIBLE - setImageDrawable(value) - } - } - } - - var label: CharSequence - get() = button.text - set(value) { - button.text = value - } - - var showSpinner = false - - constructor(context: Context) : super(context) - - constructor(context: Context, attributes: AttributeSet) : super(context, attributes) { - loadAttributes(attributes) - } - - constructor( - context: Context, - attributes: AttributeSet, - defaultStyleAttribute: Int - ) : super(context, attributes, defaultStyleAttribute) { - loadAttributes(attributes) - } - - constructor( - context: Context, - attributes: AttributeSet, - defaultStyleAttribute: Int, - defaultStyleResource: Int - ) : super(context, attributes, defaultStyleAttribute, defaultStyleResource) { - loadAttributes(attributes) - } - - override fun setEnabled(enabled: Boolean) { - super.setEnabled(enabled) - button.isEnabled = enabled - - if (enabled) { - alpha = 1.0f - } else { - alpha = 0.5f - } - } - - init { - button.setOnClickListener { - jobTracker?.newUiJob(clickJobName!!) { - isEnabled = false - - if (showSpinner) { - image.visibility = GONE - spinner.visibility = VISIBLE - } - - onClickAction!!.invoke() - - spinner.visibility = GONE - - if (detailImage != null) { - image.visibility = VISIBLE - } - - isEnabled = true - } - } - } - - fun setOnClickAction(jobName: String, tracker: JobTracker, action: suspend () -> Unit) { - clickJobName = jobName - jobTracker = tracker - onClickAction = action - } - - fun setText(textResource: Int) { - button.setText(textResource) - } - - private fun loadAttributes(attributes: AttributeSet) { - var styleableId = R.styleable.Button - - context.theme.obtainStyledAttributes(attributes, styleableId, 0, 0).apply { - try { - buttonColor = ButtonColor.fromCode(getInteger(R.styleable.Button_buttonColor, 0)) - detailImage = getDrawable(R.styleable.Button_detailImage) - showSpinner = getBoolean(R.styleable.Button_showSpinner, false) - } finally { - recycle() - } - } - - context.theme.obtainStyledAttributes(attributes, R.styleable.TextAttribute, 0, 0).apply { - try { - button.text = getString(R.styleable.TextAttribute_text) ?: "" - } finally { - recycle() - } - } - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt deleted file mode 100644 index 788bc92691..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/HeaderBar.kt +++ /dev/null @@ -1,73 +0,0 @@ -package net.mullvad.mullvadvpn.ui.widget - -import android.content.Context -import android.util.AttributeSet -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.widget.LinearLayout -import androidx.core.content.ContextCompat -import androidx.core.view.isVisible -import kotlin.properties.Delegates.observable -import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.model.TunnelState -import net.mullvad.mullvadvpn.ui.MainActivity -import net.mullvad.mullvadvpn.ui.StatusBarPainter -import net.mullvad.mullvadvpn.ui.paintStatusBar - -class HeaderBar -@JvmOverloads -constructor( - context: Context, - attributes: AttributeSet? = null, - defStyleAttr: Int = 0, - defStyleRes: Int = 0 -) : LinearLayout(context, attributes, defStyleAttr, defStyleRes), StatusBarPainter { - private val container = LayoutInflater.from(context).inflate(R.layout.header_bar, this) - private val settingsButton = findViewById<View>(R.id.settings) - private val accountButton = findViewById<View>(R.id.account) - - private val disabledColor = ContextCompat.getColor(context, android.R.color.transparent) - private val securedColor = ContextCompat.getColor(context, R.color.green) - private val unsecuredColor = ContextCompat.getColor(context, R.color.red) - - var tunnelState by - observable<TunnelState?>(null) { _, _, state -> - val backgroundColor = - if (state == null) { - disabledColor - } else if (state.isSecured()) { - securedColor - } else { - unsecuredColor - } - - container.setBackgroundColor(backgroundColor) - paintStatusBar(backgroundColor) - } - - init { - gravity = Gravity.CENTER_VERTICAL - orientation = HORIZONTAL - - accountButton.apply { - isEnabled = true - setOnClickListener { (context as? MainActivity)?.openAccount() } - } - - settingsButton.apply { - isEnabled = true - setOnClickListener { (context as? MainActivity)?.openSettings() } - } - - tunnelState = null - } - - fun setAccountButtonVisibility(isVisible: Boolean) { - accountButton.isVisible = isVisible - } - - fun setSettingsButtonEnabled(isEnabled: Boolean) { - settingsButton.isEnabled = isEnabled - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ListenableScrollView.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ListenableScrollView.kt deleted file mode 100644 index 0b65325f42..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/ListenableScrollView.kt +++ /dev/null @@ -1,31 +0,0 @@ -package net.mullvad.mullvadvpn.ui.widget - -import android.content.Context -import android.util.AttributeSet -import android.widget.ScrollView -import net.mullvad.mullvadvpn.util.ListenableScrollableView - -class ListenableScrollView : ScrollView, ListenableScrollableView { - override val horizontalScrollOffset - get() = scrollX - - override val verticalScrollOffset - get() = scrollY - - override var onScrollListener: ((Int, Int, Int, Int) -> Unit)? = null - - constructor(context: Context) : super(context) - - constructor(context: Context, attributes: AttributeSet) : super(context, attributes) - - constructor( - context: Context, - attributes: AttributeSet, - defaultStyleAttribute: Int - ) : super(context, attributes, defaultStyleAttribute) - - override fun onScrollChanged(left: Int, top: Int, oldLeft: Int, oldTop: Int) { - super.onScrollChanged(left, top, oldLeft, oldTop) - onScrollListener?.invoke(left, top, oldLeft, oldTop) - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt deleted file mode 100644 index 4d0406cdc3..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt +++ /dev/null @@ -1,41 +0,0 @@ -package net.mullvad.mullvadvpn.util - -import kotlin.properties.Delegates.observable -import kotlinx.coroutines.delay -import net.mullvad.mullvadvpn.lib.common.util.JobTracker - -// Helper to filter out bursts of events so that only the latest event in an interval is notified. -// -// An interval of zero means that it will only debounce events that are sent before the job is -// started. If the events are coming from the UI thread, this means that this class will only send -// the last event received before the UI thread finishes its current task. -// -// This can be used for example to filter out focus events coming from different views. Android will -// first send a "focus lost" event from a view followed by a "focus gained" event from another view. -// If the only thing the listener is interested in is if any of a set of views has focus, this class -// can be used to debounce focus events from the set of views to obtain an event that represents a -// change from when the set contains a focused view to when the set contains no focused views (and -// an event for the reverse situation). -class Debouncer<T>(initialValue: T, val intervalInMs: Long = 0) { - private val jobTracker = JobTracker() - - var listener: ((T) -> Unit)? = null - - var debouncedValue = initialValue - private set - - var rawValue by - observable(initialValue) { _, oldValue, newValue -> - if (newValue != oldValue) { - jobTracker.cancelJob("notifyNewValue") - - if (newValue != debouncedValue) { - jobTracker.newUiJob("notifyNewValue") { - delay(intervalInMs) - listener?.invoke(newValue) - debouncedValue = newValue - } - } - } - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/LinearInterpolation.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/LinearInterpolation.kt deleted file mode 100644 index ff03844e91..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/LinearInterpolation.kt +++ /dev/null @@ -1,46 +0,0 @@ -package net.mullvad.mullvadvpn.util - -import kotlin.properties.Delegates.observable -import kotlin.reflect.KProperty - -class LinearInterpolation { - private val observer = { _: KProperty<*>, oldValue: Float, newValue: Float -> - if (!updated && oldValue != newValue) { - updated = true - } - } - - private val realStart - get() = start - reference - - private val realEnd - get() = end - reference - - var reference by observable(0.0f, observer) - var start by observable(0.0f, observer) - var end by observable(0.0f, observer) - - var updated = true - get() { - return if (field) { - field = false - true - } else { - false - } - } - - fun interpolate(progress: Float): Float { - return progress * (realEnd - realStart) + realStart - } - - fun progress(interpolation: Float): Float { - val length = realEnd - realStart - - if (length == 0.0f) { - return 0.0f - } - - return (interpolation - realStart) / length - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/ListenableScrollableView.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/ListenableScrollableView.kt deleted file mode 100644 index 61deecacb2..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/ListenableScrollableView.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.mullvad.mullvadvpn.util - -interface ListenableScrollableView { - val horizontalScrollOffset: Int - val verticalScrollOffset: Int - - var onScrollListener: ((Int, Int, Int, Int) -> Unit)? -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedInputFormatter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedInputFormatter.kt deleted file mode 100644 index 6d3a3e5cc8..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedInputFormatter.kt +++ /dev/null @@ -1,147 +0,0 @@ -package net.mullvad.mullvadvpn.util - -import android.text.Editable -import android.text.TextWatcher -import android.widget.EditText -import java.util.Locale - -class SegmentedInputFormatter(val input: EditText, var separator: Char) : TextWatcher { - private var editing = false - private var removing = false - private var separatorSkipCount = 5 - - var allCaps = false - var isValidInputCharacter: (Char) -> Boolean = { _ -> true } - - var segmentSize = 4 - set(value) { - field = value - separatorSkipCount = value + 1 - } - - init { - input.addTextChangedListener(this) - } - - override fun beforeTextChanged(text: CharSequence, start: Int, count: Int, after: Int) { - if (!editing) { - editing = true - removing = after < count - } - } - - override fun onTextChanged(text: CharSequence, start: Int, before: Int, count: Int) {} - - override fun afterTextChanged(text: Editable) { - val string = text.toString() - - if (isValidInput(string)) { - editing = false - maybeUpdateSelection(text) - } else { - formatInput(text) - } - } - - private fun maybeUpdateSelection(text: Editable) { - if (removing) { - var start = input.selectionStart - var end = input.selectionEnd - var changed = false - - if (start % separatorSkipCount == 0 && start > 0) { - start -= 1 - changed = true - } - - if (end % separatorSkipCount == 0 && end > 0) { - end -= 1 - changed = true - } - - if (changed) { - input.setSelection(start, end) - - if (start == end && end == text.length - 1) { - // The cursor was previously at the last character, and now after the character - // was removed it has been moved to before the separator. It's best now to - // remove the unnecessary trailing separator - text.delete(text.length - 1, text.length) - } - } - } - } - - private fun isValidInput(string: String): Boolean { - return string.asSequence().withIndex().all { item -> - val index = item.index - val character = item.value - - if ((index + 1) % separatorSkipCount == 0) { - character == separator - } else { - isValidInputCharacter(character) - } - } - } - - private fun formatInput(input: Editable) { - var index = 0 - val length = input.length - var changed = false - - while (index < length && !changed) { - val segmentStart = index - val segmentEnd = index + segmentSize - 1 - val separatorPosition = segmentEnd + 1 - - changed = - formatSegment(input, segmentStart..segmentEnd) || - formatSeparator(input, separatorPosition) - - index = separatorPosition + 1 - } - } - - private fun formatSegment(input: Editable, range: IntRange): Boolean { - val length = input.length - val start = range.start - var end = range.endInclusive - - if (start < length) { - end = minOf(end, length - 1) - - for (index in start..end) { - val character = input[index] - - if (allCaps && character >= 'a' && character <= 'z') { - input.replace( - index, - index + 1, - character.toString().uppercase(Locale.getDefault()) - ) - } else if (!isValidInputCharacter(character)) { - input.delete(index, index + 1) - } else { - // Only continue looping if no changes were made to the string - continue - } - - // Abort loop because the input was edited and `afterTextChanged` will be called - // again - return true - } - } - - return false - } - - private fun formatSeparator(input: Editable, index: Int): Boolean { - if (index < input.length && input[index] != separator) { - input.insert(index, "$separator") - return true - } else { - return false - } - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedTextFormatter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedTextFormatter.kt deleted file mode 100644 index 4ba6fe97e0..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/SegmentedTextFormatter.kt +++ /dev/null @@ -1,14 +0,0 @@ -package net.mullvad.mullvadvpn.util - -class SegmentedTextFormatter(var separator: Char) { - var isValidInputCharacter: (Char) -> Boolean = { _ -> true } - var segmentSize = 4 - - fun format(string: String) = - string - .asSequence() - .filter(isValidInputCharacter) - .chunked(segmentSize) - .map { segmentCharacters -> segmentCharacters.joinToString("") } - .joinToString("$separator") -} diff --git a/android/app/src/main/res/layout/button.xml b/android/app/src/main/res/layout/button.xml deleted file mode 100644 index 5db4501a46..0000000000 --- a/android/app/src/main/res/layout/button.xml +++ /dev/null @@ -1,23 +0,0 @@ -<merge xmlns:android="http://schemas.android.com/apk/res/android"> - <Button android:id="@+id/button" - android:gravity="center" - android:text="" - style="@style/Button" /> - <ProgressBar android:id="@+id/spinner" - android:layout_width="20dp" - android:layout_height="20dp" - android:layout_marginHorizontal="9dp" - android:layout_gravity="end|center_vertical" - android:indeterminate="true" - android:indeterminateOnly="true" - android:indeterminateDuration="600" - android:indeterminateDrawable="@drawable/icon_spinner" - android:visibility="gone" /> - <ImageView android:id="@+id/image" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginHorizontal="9dp" - android:layout_gravity="end|center_vertical" - android:src="@android:color/transparent" - android:visibility="gone" /> -</merge> diff --git a/android/app/src/main/res/layout/header_bar.xml b/android/app/src/main/res/layout/header_bar.xml deleted file mode 100644 index f040afd9cb..0000000000 --- a/android/app/src/main/res/layout/header_bar.xml +++ /dev/null @@ -1,46 +0,0 @@ -<merge xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" - android:layout_height="@dimen/top_bar_height"> - - <ImageView android:id="@+id/appIcon" - android:layout_width="44dp" - android:layout_height="44dp" - android:src="@drawable/logo_icon" - android:layout_marginStart="16dp" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" /> - <ImageView android:id="@+id/appLogo" - android:layout_height="16dp" - android:layout_width="wrap_content" - android:adjustViewBounds="true" - android:scaleType="fitCenter" - android:src="@drawable/logo_text" - android:layout_marginStart="8dp" - android:alpha="0.8" - app:layout_constraintStart_toEndOf="@id/appIcon" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" /> - <ImageButton android:id="@+id/account" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:background="?android:attr/selectableItemBackground" - android:paddingHorizontal="16dp" - android:src="@drawable/icon_account" - app:layout_constraintEnd_toStartOf="@id/settings" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - android:contentDescription="@string/settings_account" /> - <ImageButton android:id="@+id/settings" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:background="?android:attr/selectableItemBackground" - android:paddingHorizontal="16dp" - android:src="@drawable/icon_settings" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - android:contentDescription="@string/settings" /> - </androidx.constraintlayout.widget.ConstraintLayout> -</merge> diff --git a/android/app/src/main/res/layout/settings_back_button.xml b/android/app/src/main/res/layout/settings_back_button.xml deleted file mode 100644 index 442437fca8..0000000000 --- a/android/app/src/main/res/layout/settings_back_button.xml +++ /dev/null @@ -1,12 +0,0 @@ -<merge xmlns:android="http://schemas.android.com/apk/res/android"> - <ImageView android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginEnd="8dp" - android:src="@drawable/icon_back" /> - <TextView android:id="@+id/label" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="@color/white60" - android:textSize="@dimen/text_small" - android:textStyle="bold" /> -</merge> |
