Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions app/src/main/java/com/greybox/projectmesh/GlobalApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,10 @@ class GlobalApp : Application(), DIAware {
bind<SharedPreferences>(tag = "settings") with singleton {
applicationContext.getSharedPreferences("settings", Context.MODE_PRIVATE)
}

bind<SharedPreferences>(tag = "mesh") with singleton {
applicationContext.getSharedPreferences("project_mesh_prefs", Context.MODE_PRIVATE)
}
bind<UserRepository>() with singleton {
UserRepository(instance<MeshDatabase>().userDao())
}
Expand Down
105 changes: 51 additions & 54 deletions app/src/main/java/com/greybox/projectmesh/MainActivity.kt
Comment thread
Kteja03 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.greybox.projectmesh
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
Expand Down Expand Up @@ -90,6 +89,9 @@ import kotlinx.coroutines.launch
import com.greybox.projectmesh.messaging.data.entities.Conversation
import com.greybox.projectmesh.messaging.ui.viewmodels.ChatScreenViewModel
import com.greybox.projectmesh.views.LogScreen
import com.greybox.projectmesh.mainscreen.MainViewModel
import com.greybox.projectmesh.mainscreen.MeshUiState
import com.greybox.projectmesh.mainscreen.MeshUiEvent


import com.greybox.projectmesh.views.RequestPermissionsScreen
Expand All @@ -102,7 +104,6 @@ class MainActivity : ComponentActivity(), DIAware {
super.onCreate(savedInstanceState)
// crash screen
CrashHandler.init(applicationContext, CrashScreenActivity::class.java)
val settingPref: SharedPreferences by di.instance(tag = "settings")
val appServer: AppServer by di.instance()
// Run this task asynchronously (default directory creation)
lifecycleScope.launch(Dispatchers.IO) {
Expand All @@ -112,47 +113,38 @@ class MainActivity : ComponentActivity(), DIAware {
TestDeviceService.initialize()
Log.d("MainActivity", "Test device initialized")
setContent {
val meshPrefs = getSharedPreferences("project_mesh_prefs", MODE_PRIVATE)
var hasRunBefore by rememberSaveable {
mutableStateOf(meshPrefs.getBoolean("hasRunBefore", false))
}
// Check if the app was launched from a notification
val launchedFromNotification = intent?.getBooleanExtra("from_notification", false) ?: false
// Request all permission in order
RequestPermissionsScreen(skipPermissions = launchedFromNotification)
var appTheme by remember {
mutableStateOf(AppTheme.valueOf(
settingPref.getString("app_theme", AppTheme.SYSTEM.name) ?:
AppTheme.SYSTEM.name))
}
var languageCode by remember {
mutableStateOf(settingPref.getString(
"language", "en") ?: "en")
}
var restartServerKey by remember {mutableStateOf(0)}
var deviceName by remember {
mutableStateOf(settingPref.getString("device_name", Build.MODEL) ?: Build.MODEL)
}

var autoFinish by remember {
mutableStateOf(settingPref.getBoolean("auto_finish", false))
}

var saveToFolder by remember {
mutableStateOf(
settingPref.getString("save_to_folder", null)
?: "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/Project Mesh"
// Get MainViewModel (this holds all screen state)
val mainViewModel: MainViewModel = viewModel(
factory = ViewModelFactory(
di = localDI(),
owner = LocalSavedStateRegistryOwner.current,
defaultArgs = null,
vmFactory = { di, _ -> MainViewModel(di) }
)
}
)

// State to trigger recomposition when locale changes
// Observe state from ViewModel
val uiState by mainViewModel.uiState.collectAsState()

// Use state from ViewModel instead of local state
val hasRunBefore = uiState.hasRunBefore
val currentScreen = uiState.currentScreen
val deviceName = uiState.deviceName
val appTheme = uiState.appTheme
val languageCode = uiState.languageCode
val autoFinish = uiState.autoFinish
val saveToFolder = uiState.saveToFolder
val launchedFromNotification =
intent?.getStringExtra("navigateTo") == BottomNavItem.Receive.route ||
intent?.action == "OPEN_CHAT_SCREEN" ||
intent?.action == "OPEN_CHAT_CONVERSATION"

var restartServerKey by remember { mutableStateOf(0) }
var localeState by rememberSaveable { mutableStateOf(Locale.getDefault()) }

// Remember the current screen across recompositions
var currentScreen by rememberSaveable { mutableStateOf(BottomNavItem.Home.route) }
LaunchedEffect(intent?.getStringExtra("navigateTo")) {
if (intent?.getStringExtra("navigateTo") == BottomNavItem.Receive.route) {
currentScreen = BottomNavItem.Receive.route
if (intent?.getStringExtra("navigateTo") == BottomNavItem.Receive.route){
mainViewModel.onEvent(MeshUiEvent.NavigateToScreen(BottomNavItem.Receive.route)) // ✅ CORRECT
}
}

Expand All @@ -166,19 +158,19 @@ class MainActivity : ComponentActivity(), DIAware {
InetAddress.getByName(ip)
// If that succeeds, navigate to chat screen with this IP
val route = "chatScreen/$ip"
currentScreen = route
mainViewModel.onEvent(MeshUiEvent.NavigateToScreen(route))
} catch (e: Exception) {
Log.e("MainActivity", "Invalid IP address in intent: $ip", e)
// Fall back to home screen
currentScreen = BottomNavItem.Home.route
mainViewModel.onEvent(MeshUiEvent.NavigateToScreen(BottomNavItem.Home.route))
}
}
} else if (action == "OPEN_CHAT_CONVERSATION") {
val conversationId = intent.getStringExtra("conversationId")
if (conversationId != null) {
// Navigate to chat screen with this conversation ID
val route = "chatScreen/$conversationId"
currentScreen = route
mainViewModel.onEvent(MeshUiEvent.NavigateToScreen(route))
}
}

Expand All @@ -193,26 +185,29 @@ class MainActivity : ComponentActivity(), DIAware {
localeState = updateLocale(languageCode)
}
key(localeState) {
ProjectMeshTheme(appTheme = appTheme) {
ProjectMeshTheme(appTheme = AppTheme.valueOf(appTheme)) {
RequestPermissionsScreen(skipPermissions = launchedFromNotification)

if (!hasRunBefore) {
OnboardingScreen(
onComplete = {meshPrefs.edit().putBoolean("hasRunBefore", true).apply()
hasRunBefore = true }
onComplete = {mainViewModel.onEvent(MeshUiEvent.CompleteOnboarding)
}
)
}
else{
BottomNavApp(
di,
startDestination = currentScreen,
onThemeChange = { selectedTheme -> appTheme = selectedTheme},
onLanguageChange = { selectedLanguage -> languageCode = selectedLanguage},
onThemeChange = { selectedTheme -> mainViewModel.onEvent(MeshUiEvent.UpdateTheme(selectedTheme.name)) },
onLanguageChange = { selectedLanguage -> mainViewModel.onEvent(MeshUiEvent.UpdateLanguage(selectedLanguage)) },
onNavigateToScreen = {screen ->
currentScreen = screen },
mainViewModel.onEvent(MeshUiEvent.NavigateToScreen(screen)) },
onRestartServer = {restartServerKey++},
onDeviceNameChange = {deviceName = it},
onDeviceNameChange = {newName -> mainViewModel.onEvent(MeshUiEvent.UpdateDeviceName(newName)) },
deviceName = deviceName,
onAutoFinishChange = {autoFinish = it},
onSaveToFolderChange = {saveToFolder = it}
autoFinish = autoFinish,
onAutoFinishChange = { autoFinishValue -> mainViewModel.onEvent(MeshUiEvent.UpdateAutoFinish(autoFinishValue)) },
onSaveToFolderChange = { saveToFolder -> mainViewModel.onEvent(MeshUiEvent.UpdateSaveToFolder(saveToFolder)) }
)
}
}
Expand Down Expand Up @@ -258,6 +253,7 @@ fun BottomNavApp(di: DI,
onRestartServer: () -> Unit,
onDeviceNameChange: (String) -> Unit,
deviceName: String,
autoFinish: Boolean,
onAutoFinishChange: (Boolean) -> Unit,
onSaveToFolderChange: (String) -> Unit
) = withDI(di)
Expand Down Expand Up @@ -352,6 +348,7 @@ fun BottomNavApp(di: DI,
)
}
composable(BottomNavItem.Receive.route) { ReceiveScreen(
autoFinish = autoFinish,
onAutoFinishChange = onAutoFinishChange
) }
composable(BottomNavItem.Log.route) {
Expand Down Expand Up @@ -398,6 +395,7 @@ fun BottomNavApp(di: DI,
Log.e("BottomNavApp", "Local UUID not found; cannot update user")
}
},
autoFinish = autoFinish,
onAutoFinishChange = onAutoFinishChange,
onSaveToFolderChange = onSaveToFolderChange,
)
Expand Down Expand Up @@ -486,8 +484,8 @@ fun BottomNavApp(di: DI,

@Composable
fun ConversationChatScreen (
conversationId: String,
onBackClick: () -> Unit
conversationId: String,
onBackClick: () -> Unit
){
Log.d("ConversationChatScreen", "Starting to load conversation: $conversationId")

Expand Down Expand Up @@ -644,5 +642,4 @@ fun ConversationChatScreen (
)
)
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
import androidx.savedstate.SavedStateRegistryOwner
import org.kodein.di.DI


// This is a custom factory class for creating ViewModels that can be injected with DI
class ViewModelFactory<T: ViewModel>(
private val di: DI,
Expand Down
Loading