diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index f307397..4d5cef1 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -57,6 +57,7 @@ dependencies {
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.material.icons.extended)
+ implementation(libs.androidx.interpolator)
debugImplementation(libs.androidx.ui.tooling)
// Navigation
@@ -72,4 +73,7 @@ dependencies {
// Coroutines
implementation(libs.kotlinx.coroutines.android)
+
+ //Splash Screen
+ implementation(libs.androidx.core.splashscreen)
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f67e717..4bfcaeb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,7 +2,6 @@
-
@@ -20,18 +19,15 @@
android:supportsRtl="true"
android:theme="@style/Theme.AppFence">
-
-
-
-
-
+ android:theme="@style/Theme.AppFence.Splash">
+
+
+
-
-
-
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..1ff4ad4
Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/com/yogesh/appfence/ui/MainActivity.kt b/app/src/main/java/com/yogesh/appfence/ui/MainActivity.kt
index c02f6c1..d53917d 100644
--- a/app/src/main/java/com/yogesh/appfence/ui/MainActivity.kt
+++ b/app/src/main/java/com/yogesh/appfence/ui/MainActivity.kt
@@ -1,7 +1,6 @@
package com.yogesh.appfence.ui
import android.app.Activity
-import android.content.Intent
import android.net.VpnService
import android.os.Bundle
import android.widget.Toast
@@ -13,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -23,7 +23,6 @@ import com.yogesh.appfence.ui.screens.SettingsScreen
import com.yogesh.appfence.ui.theme.AppFenceTheme
import com.yogesh.appfence.ui.viewmodel.MainViewModel
import com.yogesh.appfence.ui.viewmodel.SettingsViewModel
-import com.yogesh.appfence.vpn.NetworkType
/**
* Single-activity host for the entire Compose UI.
@@ -42,7 +41,6 @@ class MainActivity : ComponentActivity() {
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
- // Permission granted — start VPN and complete onboarding
settingsViewModel.startVpn()
settingsViewModel.completeOnboarding()
} else {
@@ -55,54 +53,58 @@ class MainActivity : ComponentActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
+
+ val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
settingsViewModel = ViewModelProvider(this)[SettingsViewModel::class.java]
+
+ splashScreen.setKeepOnScreenCondition { false }
+
+ enableEdgeToEdge()
+
setContent {
AppFenceTheme {
val navController = rememberNavController()
val onboardingCompleted by settingsViewModel.onboardingCompleted.collectAsState()
val networkType by settingsViewModel.networkMonitor.networkType.collectAsState()
+ val isLoading by mainViewModel.isLoading.collectAsState()
- val startDestination = if (onboardingCompleted) "main" else "onboarding"
-
- NavHost(
- navController = navController,
- startDestination = startDestination,
- modifier = Modifier.fillMaxSize()
- ) {
- composable("onboarding") {
- OnboardingScreen(
- onGrantVpnPermission = { requestVpnPermission() }
- )
- }
+ if (isLoading) {
+ com.yogesh.appfence.ui.screens.AppFenceSplashScreen()
+ } else {
+ val startDestination = if (onboardingCompleted) "main" else "onboarding"
- composable("main") {
- MainScreen(
- viewModel = mainViewModel,
- networkType = networkType,
- onNavigateToSettings = {
- navController.navigate("settings")
- }
- )
+ NavHost(
+ navController = navController,
+ startDestination = startDestination,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ composable("onboarding") {
+ OnboardingScreen(onGrantVpnPermission = { requestVpnPermission() })
+ }
+ composable("main") {
+ MainScreen(
+ viewModel = mainViewModel,
+ networkType = networkType,
+ onNavigateToSettings = { navController.navigate("settings") }
+ )
+ }
+ composable("settings") {
+ SettingsScreen(
+ viewModel = settingsViewModel,
+ onNavigateBack = { navController.popBackStack() },
+ onRequestVpnPermission = { requestVpnPermission() }
+ )
+ }
}
- composable("settings") {
- SettingsScreen(
- viewModel = settingsViewModel,
- onNavigateBack = { navController.popBackStack() },
- onRequestVpnPermission = { requestVpnPermission() }
- )
- }
- }
-
- // If onboarding was just completed, navigate to main
- if (onboardingCompleted && navController.currentDestination?.route == "onboarding") {
- navController.navigate("main") {
- popUpTo("onboarding") { inclusive = true }
+ if (onboardingCompleted && navController.currentDestination?.route == "onboarding") {
+ navController.navigate("main") {
+ popUpTo("onboarding") { inclusive = true }
+ }
}
}
}
@@ -124,9 +126,8 @@ class MainActivity : ComponentActivity() {
if (prepareIntent != null) {
vpnPermissionLauncher.launch(prepareIntent)
} else {
- // Permission already granted
settingsViewModel.startVpn()
settingsViewModel.completeOnboarding()
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/yogesh/appfence/ui/screens/SplashScreen.kt b/app/src/main/java/com/yogesh/appfence/ui/screens/SplashScreen.kt
new file mode 100644
index 0000000..2652599
--- /dev/null
+++ b/app/src/main/java/com/yogesh/appfence/ui/screens/SplashScreen.kt
@@ -0,0 +1,48 @@
+package com.yogesh.appfence.ui.screens
+
+import androidx.compose.animation.core.*
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.yogesh.appfence.R
+
+@Composable
+fun AppFenceSplashScreen() {
+ val infiniteTransition = rememberInfiniteTransition(label = "SplashRotation")
+ val rotationAngle by infiniteTransition.animateFloat(
+ initialValue = 0f,
+ targetValue = 360f,
+ animationSpec = infiniteRepeatable(
+ animation = tween(
+ durationMillis = 1000,
+ easing = LinearEasing
+ ),
+ repeatMode = RepeatMode.Restart
+ ),
+ label = "LogoAngle"
+ )
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color(0xFF001A35)),
+ contentAlignment = Alignment.Center
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.circle_logo),
+ contentDescription = "Loading...",
+ modifier = Modifier
+ .size(192.dp)
+ .rotate(rotationAngle)
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circle_logo.png b/app/src/main/res/drawable/circle_logo.png
new file mode 100644
index 0000000..b24e793
Binary files /dev/null and b/app/src/main/res/drawable/circle_logo.png differ
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 7680e5f..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..fd7decc
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
deleted file mode 100644
index a76fff5..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..30ee392
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 1f4a96e..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..0d6df0f
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index a8b89dd..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..0dc0be9
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
deleted file mode 100644
index 99105ec..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..376cd3f
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index 5593535..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..bcb1ead
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index e4911ed..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..92f7d27
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 40c8430..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..35546a4
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 5c0665d..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9a6ed90
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index bea1718..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..1379a9d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 6366b2b..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..a7ed1e2
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index 10c954a..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..f9d31d8
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index ce73f3e..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..a24e3b5
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
deleted file mode 100644
index 9a70dc1..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..55d953a
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 118c434..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1a3d9f2
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..5efdb61
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #0D1B2A
+ #00E5CC
+
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
index 05fb2e3..9c0476a 100644
--- a/app/src/main/res/values/ic_launcher_background.xml
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #0D1B2A
-
+ #041D3B
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index f278cff..b9758e3 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,4 +1,11 @@
-
-
+
+
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bd0d544..c2805ab 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -10,6 +10,8 @@ navigationCompose = "2.8.5"
room = "2.6.1"
coroutines = "1.9.0"
datastorePreferences = "1.1.1"
+splashscreen = "1.0.1"
+interpolator = "1.0.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -30,6 +32,8 @@ androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref =
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" }
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" }
+androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splashscreen" }
+androidx-interpolator = { group = "androidx.interpolator", name = "interpolator", version.ref = "interpolator" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }