Skip to content

Commit

Permalink
feat: add statistics to main screen
Browse files Browse the repository at this point in the history
Removed Details screen and moved tunnel statistics to be shown on expansion of a tunnel config row

Fixes bug where not scanning a QR code could cause app to crash when navigating back from camera view

Remove vibrations from notifications

Improve navigation of settings screen on AndroidTV
  • Loading branch information
zaneschepke committed Nov 24, 2023
1 parent 90b006a commit 11ad494
Show file tree
Hide file tree
Showing 23 changed files with 180 additions and 322 deletions.
11 changes: 4 additions & 7 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,18 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# fix hardcode changelog file name
body_path: ${{ github.workspace }}/fastlane/metadata/android/en-US/changelogs/32100.txt
body_path: ${{ github.workspace }}/fastlane/metadata/android/en-US/changelogs/32200.txt
tag_name: ${{ github.ref_name }}
name: Release ${{ github.ref_name }}
draft: false
prerelease: false
files: ${{ github.workspace }}/${{ steps.apk-path.outputs.path }}
deploy:
name: Deploy with fastlane
needs: build
runs-on: ubuntu-latest
steps:
- uses: ruby/setup-ruby@v1
- name: Deploy with fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2' # Not needed with a .ruby-version file
bundler-cache: true

- name: Distribute app to Beta track 🚀
run: (cd ${{ github.workspace }} && bundle install && bundle exec fastlane beta)

22 changes: 7 additions & 15 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ android {
}

signingConfigs {
create("release") {
create(Constants.RELEASE) {
val properties = Properties().apply {
//created local file for signing details
try {
Expand All @@ -59,7 +59,7 @@ android {
variant.outputs
.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
.forEach { output ->
val outputFileName = "wgtunnel-${variant.flavorName}-${variant.buildType.name}-${variant.versionName}.apk"
val outputFileName = "${Constants.APP_NAME}-${variant.flavorName}-${variant.buildType.name}-${variant.versionName}.apk"
output.outputFileName = outputFileName
}
}
Expand All @@ -71,20 +71,20 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("release")
signingConfig = signingConfigs.getByName(Constants.RELEASE)
}
debug {
isDebuggable = true
}
}
flavorDimensions.add("type")
flavorDimensions.add(Constants.TYPE)
productFlavors {
create("fdroid") {
dimension = "type"
dimension = Constants.TYPE
proguardFile("fdroid-rules.pro")
}
create("general") {
dimension = "type"
dimension = Constants.TYPE
if (BuildHelper.isReleaseBuild(gradle) && BuildHelper.isGeneralFlavor(gradle))
{
apply(plugin = "com.google.gms.google-services")
Expand All @@ -98,7 +98,7 @@ android {
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = "17"
jvmTarget = Constants.JVM_TARGET
}
buildFeatures {
compose = true
Expand All @@ -115,14 +115,6 @@ android {
}
}

tasks.register("printVersionCode") {
doLast {
//print version code for CI
println(Constants.VERSION_CODE)
}
}


val generalImplementation by configurations
dependencies {
implementation(libs.androidx.core.ktx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object Constants {
const val MANUAL_TUNNEL_CONFIG_ID = "0"
const val WATCHER_SERVICE_WAKE_LOCK_TIMEOUT = 10*60*1000L /*10 minute*/
const val VPN_CONNECTIVITY_CHECK_INTERVAL = 3000L
const val VPN_STATISTIC_CHECK_INTERVAL = 10000L
const val VPN_STATISTIC_CHECK_INTERVAL = 1000L
const val TOGGLE_TUNNEL_DELAY = 500L
const val FADE_IN_ANIMATION_DURATION = 1000
const val SLIDE_IN_ANIMATION_DURATION = 500
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.text.DecimalFormat
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

Expand All @@ -22,3 +24,8 @@ fun BroadcastReceiver.goAsync(
}
}
}

fun BigDecimal.toThreeDecimalPlaceString() : String {
val df = DecimalFormat("#.###")
return df.format(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
val notification = notificationService.createNotification(
channelId = getString(R.string.watcher_channel_id),
channelName = getString(R.string.watcher_channel_name),
description = getString(R.string.watcher_notification_text)
description = getString(R.string.watcher_notification_text),
vibration = false
)
super.startForeground(foregroundId, notification)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class WireGuardTunnelService : ForegroundService() {
channelName = getString(R.string.vpn_channel_name),
title = getString(R.string.tunnel_start_title),
onGoing = false,
vibration = false,
showTimestamp = true,
description = "${getString(R.string.tunnel_start_text)} $tunnelName"
)
Expand All @@ -132,6 +133,7 @@ class WireGuardTunnelService : ForegroundService() {
channelName = getString(R.string.vpn_channel_name),
title = getString(R.string.vpn_starting),
onGoing = false,
vibration = false,
showTimestamp = true,
description = getString(R.string.attempt_connection)
)
Expand All @@ -147,6 +149,7 @@ class WireGuardTunnelService : ForegroundService() {
actionText = getString(R.string.restart),
title = getString(R.string.vpn_connection_failed),
onGoing = false,
vibration = true,
showTimestamp = true,
description = message
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.net.NetworkCapabilities
import kotlinx.coroutines.flow.Flow

interface NetworkService<T> {
fun getNetworkName(networkCapabilities: NetworkCapabilities) : String?
val networkStatus : Flow<NetworkStatus>

}
fun getNetworkName(networkCapabilities: NetworkCapabilities): String?
val networkStatus: Flow<NetworkStatus>
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface NotificationService {
description: String,
showTimestamp : Boolean = false,
importance: Int = NotificationManager.IMPORTANCE_HIGH,
vibration: Boolean = true,
vibration: Boolean = false,
onGoing: Boolean = true,
lights: Boolean = true
): Notification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,24 @@ class TunnelControlTile : TileService() {

private suspend fun updateTileState() {
vpnService.state.collect {
when(it) {
Tunnel.State.UP -> {
qsTile.state = Tile.STATE_ACTIVE
}
Tunnel.State.DOWN -> {
qsTile.state = Tile.STATE_INACTIVE
}
else -> {
qsTile.state = Tile.STATE_UNAVAILABLE
try {
when(it) {
Tunnel.State.UP -> {
qsTile.state = Tile.STATE_ACTIVE
}
Tunnel.State.DOWN -> {
qsTile.state = Tile.STATE_INACTIVE
}
else -> {
qsTile.state = Tile.STATE_UNAVAILABLE
}
}
val config = determineTileTunnel()
setTileDescription(config?.name ?: this.resources.getString(R.string.no_tunnel_available))
qsTile.updateTile()
} catch (e : Exception) {
Timber.e("Unable to update tile state")
}
val config = determineTileTunnel()
setTileDescription(config?.name ?: this.resources.getString(R.string.no_tunnel_available))
qsTile.updateTile()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ import timber.log.Timber
import javax.inject.Inject


class WireGuardTunnel @Inject constructor(private val backend : Backend,
) : VpnService {
class WireGuardTunnel @Inject constructor(private val backend : Backend) : VpnService {

private val _tunnelName = MutableStateFlow("")
override val tunnelName get() = _tunnelName.asStateFlow()
Expand Down Expand Up @@ -115,11 +114,11 @@ class WireGuardTunnel @Inject constructor(private val backend : Backend,
_handshakeStatus.emit(HandshakeStatus.NOT_STARTED)
}
if(neverHadHandshakeCounter <= HandshakeStatus.NEVER_CONNECTED_TO_UNHEALTHY_TIME_LIMIT_SEC) {
neverHadHandshakeCounter += 10
neverHadHandshakeCounter += (1 * Constants.VPN_STATISTIC_CHECK_INTERVAL/1000).toInt()
}
return@forEach
}
if(NumberUtils.getSecondsBetweenTimestampAndNow(handshakeEpoch) >= HandshakeStatus.UNHEALTHY_TIME_LIMIT_SEC) {
if((NumberUtils.getSecondsBetweenTimestampAndNow(handshakeEpoch) ?: 0L) >= HandshakeStatus.UNHEALTHY_TIME_LIMIT_SEC) {
_handshakeStatus.emit(HandshakeStatus.UNHEALTHY)
} else {
_handshakeStatus.emit(HandshakeStatus.HEALTHY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import com.zaneschepke.wireguardautotunnel.ui.common.PermissionRequestFailedScre
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.CustomSnackBar
import com.zaneschepke.wireguardautotunnel.ui.screens.config.ConfigScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.detail.DetailScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.main.MainScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.settings.SettingsScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen
Expand Down Expand Up @@ -230,14 +229,6 @@ class MainActivity : AppCompatActivity() {
val id = it.arguments?.getString("id")
if(!id.isNullOrBlank()) {
ConfigScreen(navController = navController, id = id, showSnackbarMessage = { message -> showSnackBarMessage(message) }, focusRequester = focusRequester)}
}
composable("${Routes.Detail.name}/{id}", enterTransition = {
fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION))
}) {
val id = it.arguments?.getString("id")
if(!id.isNullOrBlank()) {
DetailScreen(padding = padding, focusRequester = focusRequester, id = id)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ enum class Routes {
Main,
Settings,
Support,
Config,
Detail;
Config;


companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
package com.zaneschepke.wireguardautotunnel.ui.common

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.wireguard.android.backend.Statistics
import com.zaneschepke.wireguardautotunnel.toThreeDecimalPlaceString
import com.zaneschepke.wireguardautotunnel.util.NumberUtils

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun RowListItem(icon : @Composable() () -> Unit, text : String, onHold : () -> Unit, onClick: () -> Unit, rowButton : @Composable() () -> Unit ) {
fun RowListItem(icon : @Composable () -> Unit, text : String, onHold : () -> Unit,
onClick: () -> Unit, rowButton : @Composable () -> Unit,
expanded : Boolean, statistics: Statistics?
) {
Box(
modifier = Modifier
.animateContentSize()
.clip(RoundedCornerShape(30.dp))
.combinedClickable(
onClick = {
onClick()
Expand All @@ -27,19 +40,45 @@ fun RowListItem(icon : @Composable() () -> Unit, text : String, onHold : () -> U
}
)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(14.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically,) {
icon()
Text(text)
Column {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 14.dp, vertical = 5.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically,) {
icon()
Text(text)
}
rowButton()
}
if(expanded) {
statistics?.peers()?.forEach {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(end = 10.dp, bottom = 10.dp, start = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
val handshakeEpoch = statistics.peer(it)!!.latestHandshakeEpochMillis
val peerTx = statistics.peer(it)!!.txBytes
val peerRx = statistics.peer(it)!!.rxBytes
val peerId = it.toBase64().subSequence(0,3).toString() + "***"
val handshakeSec = NumberUtils.getSecondsBetweenTimestampAndNow(handshakeEpoch)
val handshake = if(handshakeSec == null) "never" else "$handshakeSec secs ago"
val peerTxMB = NumberUtils.bytesToMB(peerTx).toThreeDecimalPlaceString()
val peerRxMB = NumberUtils.bytesToMB(peerRx).toThreeDecimalPlaceString()
val fontSize = 9.sp
Text("peer: $peerId", fontSize = fontSize)
Text("handshake: $handshake", fontSize = fontSize)
Text("tx: $peerTxMB MB", fontSize = fontSize)
Text("rx: $peerRxMB MB", fontSize = fontSize)
}
}
}

rowButton()
}
}
}
Loading

0 comments on commit 11ad494

Please sign in to comment.