diff --git a/app/src/main/java/net/nymtech/nymvpn/NymVPN.kt b/app/src/main/java/net/nymtech/nymvpn/NymVPN.kt index 7009dc3..245739f 100644 --- a/app/src/main/java/net/nymtech/nymvpn/NymVPN.kt +++ b/app/src/main/java/net/nymtech/nymvpn/NymVPN.kt @@ -1,9 +1,6 @@ package net.nymtech.nymvpn -import android.annotation.SuppressLint import android.app.Application -import android.content.res.Configuration -import android.system.Os import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit import dagger.hilt.android.HiltAndroidApp diff --git a/app/src/main/java/net/nymtech/nymvpn/module/AppModule.kt b/app/src/main/java/net/nymtech/nymvpn/module/AppModule.kt index 32fa1d8..078de95 100644 --- a/app/src/main/java/net/nymtech/nymvpn/module/AppModule.kt +++ b/app/src/main/java/net/nymtech/nymvpn/module/AppModule.kt @@ -1,22 +1,10 @@ package net.nymtech.nymvpn.module - -import android.net.VpnService import dagger.Module -import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import net.nymtech.vpn.NymVpnClient -import net.nymtech.vpn.NymVpnService -import net.nymtech.vpn.VpnClient -import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) class AppModule { - @Singleton - @Provides - fun provideVpnClient(): VpnClient { - return NymVpnClient() - } } \ No newline at end of file diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt b/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt index da62470..e1ef046 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/AppViewModel.kt @@ -2,7 +2,6 @@ package net.nymtech.nymvpn.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.squareup.moshi.Json import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted @@ -14,8 +13,8 @@ import net.nymtech.nymvpn.model.Country import net.nymtech.nymvpn.service.gateway.GatewayApiService import net.nymtech.nymvpn.ui.theme.Theme import net.nymtech.nymvpn.util.Constants +import timber.log.Timber import java.util.Locale -import java.util.Locale.IsoCountryCode import javax.inject.Inject @HiltViewModel @@ -34,12 +33,16 @@ class AppViewModel @Inject constructor( fun updateCountryListCache() { viewModelScope.launch(Dispatchers.IO) { - val gateways = gatewayApiService.getDescribedGateways() - val countries = gateways.map { - val countryIso = it.bond.gateway.location - Country(countryIso, Locale(countryIso.lowercase(), countryIso).displayCountry) - }.toSet() - dataStoreManager.saveToDataStore(DataStoreManager.NODE_COUNTRIES, countries.toString()) + try { + val gateways = gatewayApiService.getDescribedGateways() + val countries = gateways.map { + val countryIso = it.bond.gateway.location + Country(countryIso, Locale(countryIso.lowercase(), countryIso).displayCountry) + }.toSet() + dataStoreManager.saveToDataStore(DataStoreManager.NODE_COUNTRIES, countries.toString()) + } catch (e : Exception) { + Timber.e(e.message) + } } } } \ No newline at end of file diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt b/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt index 70fe89f..b10826a 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt @@ -1,12 +1,9 @@ package net.nymtech.nymvpn.ui import android.Manifest -import android.net.VpnService import android.os.Build import android.os.Bundle import androidx.activity.ComponentActivity -import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold @@ -17,9 +14,7 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.hilt.navigation.compose.hiltViewModel @@ -35,7 +30,6 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.nymtech.nymvpn.data.datastore.DataStoreManager -import net.nymtech.nymvpn.model.Country import net.nymtech.nymvpn.ui.common.labels.CustomSnackBar import net.nymtech.nymvpn.ui.common.navigation.NavBar import net.nymtech.nymvpn.ui.screens.hop.HopScreen diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/SearchBar.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/SearchBar.kt index 89a8496..d16ca10 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/SearchBar.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/SearchBar.kt @@ -1,24 +1,17 @@ package net.nymtech.nymvpn.ui.common import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.InteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Text @@ -29,19 +22,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import net.nymtech.nymvpn.R import net.nymtech.nymvpn.ui.theme.iconSize -import net.nymtech.nymvpn.util.scaledHeight @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/ListOptionSelectionButton.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/ListOptionSelectionButton.kt index 1713397..3f54dea 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/ListOptionSelectionButton.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/ListOptionSelectionButton.kt @@ -4,22 +4,16 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.defaultMinSize -import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeContentPadding -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Text -import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -29,9 +23,7 @@ import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.window.core.layout.WindowHeightSizeClass import net.nymtech.nymvpn.R -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.util.scaledHeight @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/RadioSurfaceButton.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/RadioSurfaceButton.kt index 907b33d..cefcf73 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/RadioSurfaceButton.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/RadioSurfaceButton.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -24,8 +23,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp -import androidx.window.core.layout.WindowHeightSizeClass -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.ui.theme.iconSize import net.nymtech.nymvpn.util.scaledHeight import net.nymtech.nymvpn.util.scaledWidth diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/SurfaceSelectionGroupButton.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/SurfaceSelectionGroupButton.kt index bf6e50a..4b7fe58 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/SurfaceSelectionGroupButton.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/buttons/SurfaceSelectionGroupButton.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Divider import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -24,9 +23,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp -import androidx.window.core.layout.WindowHeightSizeClass import net.nymtech.nymvpn.R -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.ui.theme.iconSize import net.nymtech.nymvpn.util.scaledHeight import net.nymtech.nymvpn.util.scaledWidth diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/GroupLabel.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/GroupLabel.kt index c6edc2d..40fc476 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/GroupLabel.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/GroupLabel.kt @@ -2,12 +2,10 @@ package net.nymtech.nymvpn.ui.common.labels import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier @Composable fun GroupLabel(title: String) { diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/PillLabel.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/PillLabel.kt index 863252d..406fd0f 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/PillLabel.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/labels/PillLabel.kt @@ -1,11 +1,8 @@ package net.nymtech.nymvpn.ui.common.labels -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme @@ -17,10 +14,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.window.core.layout.WindowHeightSizeClass -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.util.scaledHeight -import net.nymtech.nymvpn.util.scaledWidth @Composable fun PillLabel(text: String, backgroundColor : Color, textColor : Color) { diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/common/navigation/NavBar.kt b/app/src/main/java/net/nymtech/nymvpn/ui/common/navigation/NavBar.kt index f6e02ad..12abd48 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/common/navigation/NavBar.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/common/navigation/NavBar.kt @@ -1,6 +1,5 @@ package net.nymtech.nymvpn.ui.common.navigation -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api @@ -12,12 +11,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import androidx.navigation.NavController import androidx.navigation.compose.currentBackStackEntryAsState -import androidx.window.core.layout.WindowHeightSizeClass -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.ui.NavItem import net.nymtech.nymvpn.ui.theme.iconSize diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/model/ConnectionState.kt b/app/src/main/java/net/nymtech/nymvpn/ui/model/ConnectionState.kt index 7e937ca..d4cca0b 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/model/ConnectionState.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/model/ConnectionState.kt @@ -2,10 +2,37 @@ package net.nymtech.nymvpn.ui.model import net.nymtech.nymvpn.R import net.nymtech.nymvpn.util.StringValue +import net.nymtech.vpn.model.VpnState sealed class ConnectionState(val status: StringValue) { - data object Connected : ConnectionState(StringValue.StringResource(R.string.connected)) - data object Connecting : ConnectionState(StringValue.StringResource(R.string.connecting)) - data object Disconnecting : ConnectionState(StringValue.StringResource(R.string.disconnecting)) - data object Disconnected : ConnectionState(StringValue.StringResource(R.string.disconnected)) + + abstract val stateMessage : StateMessage + data object Connected : ConnectionState(StringValue.StringResource(R.string.connected)){ + override val stateMessage: StateMessage + get() = StateMessage.Info(StringValue.StringResource(R.string.connection_time)) + } + data object Connecting : ConnectionState(StringValue.StringResource(R.string.connecting)) { + override val stateMessage: StateMessage + get() = StateMessage.Info(StringValue.StringResource(R.string.init_client)) + } + data object Disconnecting : ConnectionState(StringValue.StringResource(R.string.disconnecting)) { + override val stateMessage: StateMessage + get() = StateMessage.Info(StringValue.Empty) + } + data object Disconnected : ConnectionState(StringValue.StringResource(R.string.disconnected)) { + override val stateMessage: StateMessage + get() = StateMessage.Info(StringValue.Empty) + } + + + companion object { + fun from(vpnState: VpnState) : ConnectionState { + return when(vpnState) { + VpnState.DOWN -> Disconnected + VpnState.UP -> Connected + VpnState.CONNECTING -> Connecting + VpnState.DISCONNECTING -> Disconnecting + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt b/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt index d88f2e3..cef3886 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -29,12 +28,10 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController -import androidx.window.core.layout.WindowHeightSizeClass import net.nymtech.nymvpn.R import net.nymtech.nymvpn.model.Country import net.nymtech.nymvpn.model.NetworkMode import net.nymtech.nymvpn.ui.AppUiState -import net.nymtech.nymvpn.ui.MainActivity import net.nymtech.nymvpn.ui.NavItem import net.nymtech.nymvpn.ui.common.animations.SpinningIcon import net.nymtech.nymvpn.ui.common.buttons.ListOptionSelectionButton diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainViewModel.kt b/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainViewModel.kt index bc3e7ae..097e333 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainViewModel.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainViewModel.kt @@ -4,26 +4,22 @@ import android.app.Application import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import net.nymtech.nymvpn.R import net.nymtech.nymvpn.data.datastore.DataStoreManager import net.nymtech.nymvpn.model.Country import net.nymtech.nymvpn.model.NetworkMode import net.nymtech.nymvpn.ui.model.ConnectionState -import net.nymtech.nymvpn.ui.model.StateMessage import net.nymtech.nymvpn.util.Constants import net.nymtech.nymvpn.util.NumberUtils -import net.nymtech.nymvpn.util.StringValue -import net.nymtech.vpn.NymVpnClient -import net.nymtech.vpn.ServiceManager -import net.nymtech.vpn.VpnClient +import net.nymtech.vpn.NymVpn +import net.nymtech.vpn.model.EntryPoint +import net.nymtech.vpn.model.ExitPoint +import javax.inject.Inject @HiltViewModel class MainViewModel @@ -31,40 +27,41 @@ class MainViewModel constructor( private val dataStoreManager: DataStoreManager, private val application: Application, - private val vpnClient: VpnClient ) : ViewModel() { private val _uiState = MutableStateFlow(MainUiState()) val uiState = - combine(dataStoreManager.preferencesFlow, _uiState, vpnClient.statistics) { + combine(dataStoreManager.preferencesFlow, _uiState, NymVpn.stateFlow, NymVpn.statistics) { prefs, - state, + uiState, + vpnState, stats -> val lastHopCountry = Country.from( prefs?.get(DataStoreManager.LAST_HOP_COUNTRY) - ?: state.lastHopCountry.toString()) + ?: uiState.lastHopCountry.toString()) val firstHopCountry = Country.from( prefs?.get(DataStoreManager.FIRST_HOP_COUNTRY) - ?: state.firstHopCounty.toString()) + ?: uiState.firstHopCounty.toString()) val connectionTime = stats.connectionSeconds?.let { NumberUtils.convertSecondsToTimeString(it) } val networkMode = NetworkMode.valueOf( - prefs?.get(DataStoreManager.NETWORK_MODE) ?: state.networkMode.name) + prefs?.get(DataStoreManager.NETWORK_MODE) ?: uiState.networkMode.name) val firstHopEnabled: Boolean = (prefs?.get(DataStoreManager.FIRST_HOP_SELECTION) ?: false) + val connectionState = ConnectionState.from(vpnState) MainUiState( false, lastHopCountry = lastHopCountry, firstHopCounty = firstHopCountry, connectionTime = connectionTime ?: "", networkMode = networkMode, - connectionState = state.connectionState, + connectionState = connectionState, firstHopEnabled = firstHopEnabled, - stateMessage = state.stateMessage) + stateMessage = connectionState.stateMessage) } .stateIn( viewModelScope, @@ -85,39 +82,14 @@ constructor( fun onConnect() = viewModelScope.launch(Dispatchers.IO) { - ServiceManager.startVpnService(application.applicationContext) - _uiState.value = - _uiState.value.copy( - connectionState = ConnectionState.Connecting, - stateMessage = StateMessage.Info(StringValue.StringResource(R.string.init_client))) - delay(1000) - _uiState.value = - _uiState.value.copy( - connectionState = ConnectionState.Connecting, - stateMessage = - StateMessage.Info(StringValue.StringResource(R.string.establishing_connection))) - delay(1000) - _uiState.value = - _uiState.value.copy( - connectionState = ConnectionState.Connected, - stateMessage = - StateMessage.Info(StringValue.StringResource(R.string.connection_time))) - vpnClient.connect() - } + NymVpn.connect(application,EntryPoint.Location(uiState.value.firstHopCounty.isoCode), + ExitPoint.Location(uiState.value.lastHopCountry.isoCode), + isTwoHop = (uiState.value.networkMode == NetworkMode.TWO_HOP_WIREGUARD)) + } + fun onDisconnect() = viewModelScope.launch { - ServiceManager.stopVpnService(application) - vpnClient.disconnect() - _uiState.value = - _uiState.value.copy( - connectionState = ConnectionState.Disconnecting, - stateMessage = StateMessage.Info(StringValue.Empty), - ) - delay(1000) - _uiState.value = - _uiState.value.copy( - connectionState = ConnectionState.Disconnected, - stateMessage = StateMessage.Info(StringValue.Empty)) + NymVpn.disconnect(application) } } diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt index 2cd1cce..e583f30 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt @@ -1,15 +1,11 @@ package net.nymtech.nymvpn.ui.screens.settings import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt index 50520ea..917e77e 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/feedback/FeedbackViewModel.kt b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/feedback/FeedbackViewModel.kt index afba986..e0741ea 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/feedback/FeedbackViewModel.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/feedback/FeedbackViewModel.kt @@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.nymtech.nymvpn.data.datastore.DataStoreManager -import net.nymtech.nymvpn.ui.screens.settings.SettingsUiState import net.nymtech.nymvpn.util.Constants import javax.inject.Inject diff --git a/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt b/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt index 9861c88..60f2635 100644 --- a/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt +++ b/app/src/main/java/net/nymtech/nymvpn/ui/theme/Theme.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.unit.dp import androidx.core.view.WindowCompat enum class Theme { diff --git a/app/src/main/java/net/nymtech/nymvpn/util/StringUtils.kt b/app/src/main/java/net/nymtech/nymvpn/util/StringUtils.kt index fcfc17d..e7b71c0 100644 --- a/app/src/main/java/net/nymtech/nymvpn/util/StringUtils.kt +++ b/app/src/main/java/net/nymtech/nymvpn/util/StringUtils.kt @@ -4,7 +4,6 @@ import android.content.Context import androidx.compose.ui.text.buildAnnotatedString import net.nymtech.nymvpn.R import net.nymtech.nymvpn.model.Country -import timber.log.Timber object StringUtils { fun buildCountryNameString(country : Country, context : Context) : String { diff --git a/app/src/main/res/drawable-anydpi/ic_stat_name.xml b/app/src/main/res/drawable-anydpi/ic_stat_name.xml new file mode 100644 index 0000000..792d07b --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_stat_name.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_stat_name.png b/app/src/main/res/drawable-hdpi/ic_stat_name.png new file mode 100644 index 0000000..064717d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_stat_name.png b/app/src/main/res/drawable-mdpi/ic_stat_name.png new file mode 100644 index 0000000..fcfad7b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/app/src/main/res/drawable-xhdpi/ic_stat_name.png new file mode 100644 index 0000000..01f33ab Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png new file mode 100644 index 0000000..d801bb0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ diff --git a/buildSrc/src/main/kotlin/Constants.kt b/buildSrc/src/main/kotlin/Constants.kt index 250ff85..ff9981c 100644 --- a/buildSrc/src/main/kotlin/Constants.kt +++ b/buildSrc/src/main/kotlin/Constants.kt @@ -27,4 +27,6 @@ object Constants { const val FDROID = "fdroid" const val GENERAL = "general" const val BUILD_LIB_TASK = "buildDeps" + + const val SANDBOX_URL = "https://sandbox-nym-api1.nymtech.net/api" } \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt new file mode 100644 index 0000000..681fda9 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/4.txt @@ -0,0 +1,4 @@ +What's new: +- Refactor VPN client +- Add image assets +- Fix UI state sync with VPN \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.jpg b/fastlane/metadata/android/en-US/images/featureGraphic.jpg new file mode 100644 index 0000000..3d3c62a Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.jpg differ diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000..ed47d88 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/countryScreen.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/countryScreen.png new file mode 100644 index 0000000..0fc5338 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/countryScreen.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/homeScreen.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/homeScreen.png new file mode 100644 index 0000000..3b25301 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/homeScreen.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/countryScreenTablet10.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/countryScreenTablet10.png new file mode 100644 index 0000000..f241af6 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/countryScreenTablet10.png differ diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/homeScreenTablet10.png b/fastlane/metadata/android/en-US/images/tenInchScreenshots/homeScreenTablet10.png new file mode 100644 index 0000000..f06cd8c Binary files /dev/null and b/fastlane/metadata/android/en-US/images/tenInchScreenshots/homeScreenTablet10.png differ diff --git a/vpn-client/build.gradle.kts b/vpn-client/build.gradle.kts index 86c83a4..1178710 100644 --- a/vpn-client/build.gradle.kts +++ b/vpn-client/build.gradle.kts @@ -26,6 +26,8 @@ android { ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86") } + //TODO change this later to sandbox and mainnet switch depending on build + buildConfigField("String", "API_URL", "\"${Constants.SANDBOX_URL}\"") } buildTypes { @@ -50,6 +52,9 @@ android { kotlinOptions { jvmTarget = Constants.JVM_TARGET } + buildFeatures { + buildConfig = true + } } dependencies { diff --git a/vpn-client/src/main/java/net/nymtech/vpn/ConnectivityListener.kt b/vpn-client/src/main/java/net/nymtech/vpn/ConnectivityListener.kt index 06f3969..b5f4381 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/ConnectivityListener.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/ConnectivityListener.kt @@ -6,8 +6,8 @@ import android.net.ConnectivityManager.NetworkCallback import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest -import kotlin.properties.Delegates.observable import net.nymtech.vpn.util.EventNotifier +import kotlin.properties.Delegates.observable class ConnectivityListener { private val availableNetworks = HashSet() diff --git a/vpn-client/src/main/java/net/nymtech/vpn/NymVpn.kt b/vpn-client/src/main/java/net/nymtech/vpn/NymVpn.kt new file mode 100644 index 0000000..32d4433 --- /dev/null +++ b/vpn-client/src/main/java/net/nymtech/vpn/NymVpn.kt @@ -0,0 +1,72 @@ +package net.nymtech.vpn + +import android.content.Context +import android.content.Intent +import android.net.VpnService +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import net.nymtech.vpn.model.EntryPoint +import net.nymtech.vpn.model.ExitPoint +import net.nymtech.vpn.model.VpnState +import net.nymtech.vpn.model.VpnStatistics +import net.nymtech.vpn.util.ServiceManager + +object NymVpn : VpnClient { + + private val _state = MutableStateFlow(VpnState.DOWN) + override val stateFlow: Flow = _state.asStateFlow() + + private val _statistics = MutableStateFlow(VpnStatistics()) + override val statistics: StateFlow = _statistics.asStateFlow() + + private val scope = CoroutineScope(Dispatchers.IO) + + private var statsJob: Job? = null + override fun prepare(context : Context): Intent? { + return VpnService.prepare(context) + } + + override fun connect(context: Context, entryPoint: EntryPoint, exitPoint: ExitPoint, isTwoHop: Boolean) { + val extras = mapOf( + ENTRY_POINT_EXTRA_KEY to entryPoint.toString(), + EXIT_POINT_EXTRA_KEY to exitPoint.toString(), + TWO_HOP_EXTRA_KEY to isTwoHop.toString() + ) + statsJob = gatherStatistics() + ServiceManager.startVpnService(context, extras) + } + + private fun gatherStatistics() = scope.launch { + var seconds = 0L + do { + _statistics.value = _statistics.value.copy( + connectionSeconds = seconds + ) + delay(1000) + seconds++ + } while (true) + } + + internal fun setState(state : VpnState) = scope.launch { + _state.value = state + } + + + override fun disconnect(context: Context) { + statsJob?.cancel() + _statistics.value = _statistics.value.copy( + connectionSeconds = null + ) + ServiceManager.stopVpnService(context) + } + const val ENTRY_POINT_EXTRA_KEY = "entryPoint" + const val EXIT_POINT_EXTRA_KEY = "exitPoint" + const val TWO_HOP_EXTRA_KEY = "twoHop" +} \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/NymVpnClient.kt b/vpn-client/src/main/java/net/nymtech/vpn/NymVpnClient.kt deleted file mode 100644 index 4400ec7..0000000 --- a/vpn-client/src/main/java/net/nymtech/vpn/NymVpnClient.kt +++ /dev/null @@ -1,51 +0,0 @@ -package net.nymtech.vpn - -import android.content.Context -import android.content.Intent -import android.net.VpnService -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch - -import timber.log.Timber - -class NymVpnClient : VpnClient { - - private val _statistics = MutableStateFlow(VpnStatistics()) - override val statistics: StateFlow = _statistics.asStateFlow() - val scope = CoroutineScope(Dispatchers.IO) - - - private var job : Job? = null - override fun prepare(context: Context) : Intent? { - return VpnService.prepare(context) - } - - override fun connect() { - job = scope.launch { - var seconds = 0L - do { - _statistics.value = _statistics.value.copy( - connectionSeconds = seconds - ) - delay(1000) - seconds++ - } while (true) - } - } - - override fun disconnect() { - //TODO reset statistics here too - _statistics.value = _statistics.value.copy( - connectionSeconds = null - ) - job?.cancel() - } -} \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/NymVpnService.kt b/vpn-client/src/main/java/net/nymtech/vpn/NymVpnService.kt index d08424e..ead033e 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/NymVpnService.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/NymVpnService.kt @@ -15,7 +15,11 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import net.nymtech.vpn.model.VpnState import net.nymtech.vpn.tun_provider.TunConfig +import net.nymtech.vpn.util.Action +import net.nymtech.vpn_client.BuildConfig +import net.nymtech.vpn_client.R import timber.log.Timber import java.net.Inet4Address import java.net.Inet6Address @@ -23,7 +27,7 @@ import java.net.InetAddress import kotlin.properties.Delegates.observable -open class NymVpnService : VpnService() { +class NymVpnService : VpnService() { companion object { init { @@ -67,22 +71,32 @@ open class NymVpnService : VpnService() { } val notificationBuilder = NotificationCompat.Builder(this, channelId) val notification = notificationBuilder.setOngoing(true) - .setSmallIcon(androidx.core.R.drawable.notification_bg) + .setContentTitle("NymVpn") + .setContentText("Running") + .setSmallIcon(R.drawable.ic_stat_name) .setCategory(Notification.CATEGORY_SERVICE) .build() startForeground(123, notification) Timber.d("new vpn action") return if (intent?.action == Action.START.name) { + NymVpn.setState(VpnState.CONNECTING) currentTunConfig = defaultTunConfig() Timber.d("VPN start") try { if(prepare(this) == null) { - val entry = "{ \"Location\": { \"location\": \"DE\" }}" - val exit = "{ \"Location\": { \"location\": \"DE\" }}" - initVPN(false, "https://sandbox-nym-api1.nymtech.net/api",entry,exit,this) - GlobalScope.launch(Dispatchers.IO) { - runVPN() + val isTwoHop = intent.extras?.getString(NymVpn.TWO_HOP_EXTRA_KEY).toBoolean() + val entry = intent.extras?.getString(NymVpn.ENTRY_POINT_EXTRA_KEY) + val exit = intent.extras?.getString(NymVpn.EXIT_POINT_EXTRA_KEY) + if(!entry.isNullOrBlank() && !exit.isNullOrBlank()) { + initVPN(isTwoHop, BuildConfig.API_URL, entry, exit,this) + GlobalScope.launch(Dispatchers.IO) { + launch { + runVPN() + } + //TODO fix to where we know if it is actually up + NymVpn.setState(VpnState.UP) + } } } } catch (e : Exception) { @@ -90,9 +104,11 @@ open class NymVpnService : VpnService() { } START_STICKY } else { + NymVpn.setState(VpnState.DISCONNECTING) Timber.d("VPN stop") stopVPN() stopSelf() + NymVpn.setState(VpnState.DOWN) START_NOT_STICKY } } @@ -113,20 +129,20 @@ open class NymVpnService : VpnService() { override fun onCreate() { connectivityListener.register(this) - val channelId = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - createNotificationChannel() - } else { - // If earlier version channel ID is not used - // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) - "" - } - val notificationBuilder = NotificationCompat.Builder(this, channelId) - val notification = notificationBuilder.setOngoing(true) - .setSmallIcon(androidx.core.R.drawable.notification_bg) - .setCategory(Notification.CATEGORY_SERVICE) - .build() - startForeground(123, notification) +// val channelId = +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// createNotificationChannel() +// } else { +// // If earlier version channel ID is not used +// // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) +// "" +// } +// val notificationBuilder = NotificationCompat.Builder(this, channelId) +// val notification = notificationBuilder.setOngoing(true) +// .setSmallIcon(R.drawable.ic_stat_name) +// .setCategory(Notification.CATEGORY_SERVICE) +// .build() +// startForeground(123, notification) } override fun onDestroy() { diff --git a/vpn-client/src/main/java/net/nymtech/vpn/VpnClient.kt b/vpn-client/src/main/java/net/nymtech/vpn/VpnClient.kt index 7a5e9d3..5d0ee81 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/VpnClient.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/VpnClient.kt @@ -3,10 +3,15 @@ package net.nymtech.vpn import android.content.Context import android.content.Intent import kotlinx.coroutines.flow.Flow +import net.nymtech.vpn.model.EntryPoint +import net.nymtech.vpn.model.ExitPoint +import net.nymtech.vpn.model.VpnState +import net.nymtech.vpn.model.VpnStatistics interface VpnClient { fun prepare(context : Context) : Intent? - fun connect() - fun disconnect() + fun connect(context: Context, entryPoint: EntryPoint, exitPoint: ExitPoint, isTwoHop: Boolean) + fun disconnect(context: Context) val statistics : Flow + val stateFlow : Flow } \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/model/EntryPoint.kt b/vpn-client/src/main/java/net/nymtech/vpn/model/EntryPoint.kt new file mode 100644 index 0000000..f7c2f7c --- /dev/null +++ b/vpn-client/src/main/java/net/nymtech/vpn/model/EntryPoint.kt @@ -0,0 +1,14 @@ +package net.nymtech.vpn.model + +sealed class EntryPoint { + //TODO enforce only two char countryISO + data class Location(private val location: String) : EntryPoint() { + + //TODO make this serialize later + override fun toString(): String { + return "{ \"Location\": { \"location\": \"${location}\" }}" + } + } + //TODO impl later + private sealed class Gateway() : EntryPoint() +} \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/model/ExitPoint.kt b/vpn-client/src/main/java/net/nymtech/vpn/model/ExitPoint.kt new file mode 100644 index 0000000..67eecfe --- /dev/null +++ b/vpn-client/src/main/java/net/nymtech/vpn/model/ExitPoint.kt @@ -0,0 +1,13 @@ +package net.nymtech.vpn.model + +sealed class ExitPoint { + data class Location(private val location: String) : ExitPoint() { + override fun toString(): String { + return "{ \"Location\": { \"location\": \"${location}\" }}" + } + } + //TODO impl later + private sealed class Gateway() : ExitPoint() + private sealed class Address() : ExitPoint() + +} \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/model/VpnState.kt b/vpn-client/src/main/java/net/nymtech/vpn/model/VpnState.kt new file mode 100644 index 0000000..3953356 --- /dev/null +++ b/vpn-client/src/main/java/net/nymtech/vpn/model/VpnState.kt @@ -0,0 +1,8 @@ +package net.nymtech.vpn.model + +enum class VpnState { + UP, + DOWN, + CONNECTING, + DISCONNECTING +} \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/VpnStatistics.kt b/vpn-client/src/main/java/net/nymtech/vpn/model/VpnStatistics.kt similarity index 78% rename from vpn-client/src/main/java/net/nymtech/vpn/VpnStatistics.kt rename to vpn-client/src/main/java/net/nymtech/vpn/model/VpnStatistics.kt index 77da636..2a1baa0 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/VpnStatistics.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/model/VpnStatistics.kt @@ -1,4 +1,4 @@ -package net.nymtech.vpn +package net.nymtech.vpn.model data class VpnStatistics( val connectionSeconds: Long? = null, diff --git a/vpn-client/src/main/java/net/nymtech/vpn/net/Endpoint.kt b/vpn-client/src/main/java/net/nymtech/vpn/net/Endpoint.kt index b5cdf4d..d23bbf2 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/net/Endpoint.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/net/Endpoint.kt @@ -1,8 +1,8 @@ package net.nymtech.vpn.net import android.os.Parcelable -import java.net.InetSocketAddress import kotlinx.parcelize.Parcelize +import java.net.InetSocketAddress @Parcelize data class Endpoint(val address: InetSocketAddress, val protocol: TransportProtocol) : Parcelable \ No newline at end of file diff --git a/vpn-client/src/main/java/net/nymtech/vpn/tunnel/ErrorStateCause.kt b/vpn-client/src/main/java/net/nymtech/vpn/tunnel/ErrorStateCause.kt index 53ac474..104577c 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/tunnel/ErrorStateCause.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/tunnel/ErrorStateCause.kt @@ -1,8 +1,8 @@ package net.nymtech.vpn.tunnel import android.os.Parcelable -import java.net.InetAddress import kotlinx.parcelize.Parcelize +import java.net.InetAddress private const val AUTH_FAILED_REASON_EXPIRED_ACCOUNT = "[EXPIRED_ACCOUNT]" diff --git a/vpn-client/src/main/java/net/nymtech/vpn/Action.kt b/vpn-client/src/main/java/net/nymtech/vpn/util/Action.kt similarity index 68% rename from vpn-client/src/main/java/net/nymtech/vpn/Action.kt rename to vpn-client/src/main/java/net/nymtech/vpn/util/Action.kt index 03cc0cb..a6eabe4 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/Action.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/util/Action.kt @@ -1,4 +1,4 @@ -package net.nymtech.vpn +package net.nymtech.vpn.util enum class Action { START, diff --git a/vpn-client/src/main/java/net/nymtech/vpn/ServiceManager.kt b/vpn-client/src/main/java/net/nymtech/vpn/util/ServiceManager.kt similarity index 88% rename from vpn-client/src/main/java/net/nymtech/vpn/ServiceManager.kt rename to vpn-client/src/main/java/net/nymtech/vpn/util/ServiceManager.kt index c2ed280..021f74b 100644 --- a/vpn-client/src/main/java/net/nymtech/vpn/ServiceManager.kt +++ b/vpn-client/src/main/java/net/nymtech/vpn/util/ServiceManager.kt @@ -1,9 +1,10 @@ -package net.nymtech.vpn +package net.nymtech.vpn.util import android.app.Service import android.content.Context import android.content.Intent import android.os.Build +import net.nymtech.vpn.NymVpnService import timber.log.Timber @@ -39,12 +40,13 @@ object ServiceManager { } } - fun startVpnService(context: Context) { + fun startVpnService(context: Context, extras : Map?) { Timber.d("Called start vpn service") actionOnService( Action.START, context, NymVpnService::class.java, + extras = extras ) } diff --git a/vpn-client/src/main/res/drawable-anydpi/ic_stat_name.xml b/vpn-client/src/main/res/drawable-anydpi/ic_stat_name.xml new file mode 100644 index 0000000..792d07b --- /dev/null +++ b/vpn-client/src/main/res/drawable-anydpi/ic_stat_name.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/vpn-client/src/main/res/drawable-hdpi/ic_stat_name.png b/vpn-client/src/main/res/drawable-hdpi/ic_stat_name.png new file mode 100644 index 0000000..064717d Binary files /dev/null and b/vpn-client/src/main/res/drawable-hdpi/ic_stat_name.png differ diff --git a/vpn-client/src/main/res/drawable-mdpi/ic_stat_name.png b/vpn-client/src/main/res/drawable-mdpi/ic_stat_name.png new file mode 100644 index 0000000..fcfad7b Binary files /dev/null and b/vpn-client/src/main/res/drawable-mdpi/ic_stat_name.png differ diff --git a/vpn-client/src/main/res/drawable-xhdpi/ic_stat_name.png b/vpn-client/src/main/res/drawable-xhdpi/ic_stat_name.png new file mode 100644 index 0000000..01f33ab Binary files /dev/null and b/vpn-client/src/main/res/drawable-xhdpi/ic_stat_name.png differ diff --git a/vpn-client/src/main/res/drawable-xxhdpi/ic_stat_name.png b/vpn-client/src/main/res/drawable-xxhdpi/ic_stat_name.png new file mode 100644 index 0000000..d801bb0 Binary files /dev/null and b/vpn-client/src/main/res/drawable-xxhdpi/ic_stat_name.png differ