SettingsScreenTV.kt 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. package com.vpn.fastestvpnservice.screensTV
  2. import android.app.Activity
  3. import android.content.Context
  4. import android.content.Intent
  5. import android.os.Build
  6. import android.os.Bundle
  7. import android.os.Handler
  8. import android.util.Log
  9. import android.widget.Toast
  10. import androidx.activity.compose.BackHandler
  11. import androidx.compose.foundation.ExperimentalFoundationApi
  12. import androidx.compose.foundation.Image
  13. import androidx.compose.foundation.LocalOverscrollConfiguration
  14. import androidx.compose.foundation.background
  15. import androidx.compose.foundation.clickable
  16. import androidx.compose.foundation.focusable
  17. import androidx.compose.foundation.gestures.detectTapGestures
  18. import androidx.compose.foundation.isSystemInDarkTheme
  19. import androidx.compose.foundation.layout.Arrangement
  20. import androidx.compose.foundation.layout.Box
  21. import androidx.compose.foundation.layout.Column
  22. import androidx.compose.foundation.layout.ColumnScope
  23. import androidx.compose.foundation.layout.Row
  24. import androidx.compose.foundation.layout.Spacer
  25. import androidx.compose.foundation.layout.fillMaxSize
  26. import androidx.compose.foundation.layout.fillMaxWidth
  27. import androidx.compose.foundation.layout.height
  28. import androidx.compose.foundation.layout.padding
  29. import androidx.compose.foundation.layout.size
  30. import androidx.compose.foundation.lazy.LazyColumn
  31. import androidx.compose.foundation.lazy.items
  32. import androidx.compose.foundation.rememberScrollState
  33. import androidx.compose.foundation.selection.selectable
  34. import androidx.compose.foundation.shape.RoundedCornerShape
  35. import androidx.compose.foundation.verticalScroll
  36. import androidx.compose.material3.DockedSearchBar
  37. import androidx.compose.material3.ExperimentalMaterial3Api
  38. import androidx.compose.material3.Icon
  39. import androidx.compose.material3.MaterialTheme
  40. import androidx.compose.material3.ModalBottomSheet
  41. import androidx.compose.material3.RadioButton
  42. import androidx.compose.material3.RadioButtonDefaults
  43. import androidx.compose.material3.SearchBarDefaults
  44. import androidx.compose.material3.Surface
  45. import androidx.compose.material3.Switch
  46. import androidx.compose.material3.SwitchDefaults
  47. import androidx.compose.material3.Text
  48. import androidx.compose.material3.TextFieldDefaults
  49. import androidx.compose.material3.rememberModalBottomSheetState
  50. import androidx.compose.runtime.Composable
  51. import androidx.compose.runtime.CompositionLocalProvider
  52. import androidx.compose.runtime.LaunchedEffect
  53. import androidx.compose.runtime.getValue
  54. import androidx.compose.runtime.livedata.observeAsState
  55. import androidx.compose.runtime.mutableStateOf
  56. import androidx.compose.runtime.remember
  57. import androidx.compose.runtime.rememberCoroutineScope
  58. import androidx.compose.runtime.setValue
  59. import androidx.compose.ui.Alignment
  60. import androidx.compose.ui.Modifier
  61. import androidx.compose.ui.draw.alpha
  62. import androidx.compose.ui.draw.clip
  63. import androidx.compose.ui.draw.scale
  64. import androidx.compose.ui.focus.FocusRequester
  65. import androidx.compose.ui.focus.focusRequester
  66. import androidx.compose.ui.focus.onFocusChanged
  67. import androidx.compose.ui.graphics.Color
  68. import androidx.compose.ui.graphics.ColorFilter
  69. import androidx.compose.ui.graphics.toArgb
  70. import androidx.compose.ui.graphics.vector.ImageVector
  71. import androidx.compose.ui.input.key.Key
  72. import androidx.compose.ui.input.key.key
  73. import androidx.compose.ui.input.key.onKeyEvent
  74. import androidx.compose.ui.input.pointer.pointerInput
  75. import androidx.compose.ui.platform.LocalContext
  76. import androidx.compose.ui.platform.LocalFocusManager
  77. import androidx.compose.ui.platform.LocalView
  78. import androidx.compose.ui.res.colorResource
  79. import androidx.compose.ui.res.painterResource
  80. import androidx.compose.ui.text.TextStyle
  81. import androidx.compose.ui.unit.Dp
  82. import androidx.compose.ui.unit.TextUnit
  83. import androidx.compose.ui.unit.dp
  84. import androidx.compose.ui.unit.sp
  85. import androidx.core.content.ContextCompat
  86. import androidx.lifecycle.viewmodel.compose.viewModel
  87. import androidx.navigation.NavHostController
  88. import androidx.navigation.compose.currentBackStackEntryAsState
  89. import com.vpn.fastestvpnservice.R
  90. import com.vpn.fastestvpnservice.beans.isDarkTheme
  91. import com.vpn.fastestvpnservice.beans.themesList
  92. import com.vpn.fastestvpnservice.constants.smartConnect
  93. import com.vpn.fastestvpnservice.customItems.ServerSpecificItem
  94. import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
  95. import com.vpn.fastestvpnservice.navigation.customNavigation
  96. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.AddTextSettings
  97. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.getAvailableProtocols
  98. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.vpnConnectionsUtil
  99. import com.vpn.fastestvpnservice.screens.searchListViewModelSplash
  100. import com.vpn.fastestvpnservice.sealedClass.BottomBarScreen
  101. import com.vpn.fastestvpnservice.sealedClass.Screen
  102. import com.vpn.fastestvpnservice.utils.isTablet
  103. import com.vpn.fastestvpnservice.viewmodels.HomeViewModel
  104. import de.blinkt.openvpn.core.App
  105. import kotlinx.coroutines.delay
  106. import kotlinx.coroutines.launch
  107. @OptIn(ExperimentalFoundationApi::class)
  108. @Composable
  109. fun SettingsTV(navHostController: NavHostController) {
  110. val context = LocalContext.current
  111. val focusRequester1 = remember { FocusRequester() }
  112. val focusRequester2 = remember { FocusRequester() }
  113. val focusRequester3 = remember { FocusRequester() }
  114. val focusRequester4 = remember { FocusRequester() }
  115. val focusRequester5 = remember { FocusRequester() }
  116. if (isSettingsScreenPressed.value) {
  117. LaunchedEffect(Unit) {
  118. focusRequester1.requestFocus()
  119. }
  120. isSettingsScreenPressed.value = false
  121. }
  122. val navBackStackEntry = navHostController.currentBackStackEntryAsState()
  123. BackHandler {
  124. Toast.makeText(
  125. context, "BackHandler Settings TV", Toast.LENGTH_SHORT
  126. ).show()
  127. // customNavigation(navHostController, BottomBarScreen.Settings)
  128. }
  129. CompositionLocalProvider(
  130. LocalOverscrollConfiguration provides null
  131. ) {
  132. Box(
  133. modifier = Modifier
  134. // .background(MaterialTheme.colorScheme.background)
  135. .background(colorResource(id = R.color.background_color_gray))
  136. .fillMaxSize()
  137. .padding(vertical = 10.dp),
  138. ) {
  139. val view = LocalView.current
  140. val window = (view.context as Activity).window
  141. window.statusBarColor = Color.Transparent.toArgb()
  142. window.navigationBarColor = Color.Transparent.toArgb()
  143. Column(
  144. verticalArrangement = Arrangement.Top,
  145. horizontalAlignment = Alignment.Start,
  146. modifier = Modifier
  147. .padding(start = 16.dp, end = 0.dp)
  148. .fillMaxSize()
  149. .verticalScroll(rememberScrollState())
  150. .background(Color.Transparent)
  151. ) {
  152. // if (BottomBarScreen.Settings.isTrue) {
  153. // AddRowSettingsSmart(
  154. // icon = R.drawable.smart_connect3x,
  155. // text = "Smart Connect",
  156. // isRowShown = false,
  157. // isSheetShown = true,
  158. // navHostController
  159. // )
  160. // }
  161. Spacer(modifier = Modifier.height(50.dp))
  162. AddTextSettingsTV(
  163. text = "Settings",
  164. size = 28.sp,
  165. color = MaterialTheme.colorScheme.inversePrimary,
  166. style = MaterialTheme.typography.headlineLarge
  167. )
  168. Spacer(modifier = Modifier.height(22.dp))
  169. AddRowSettingsColumnTV(
  170. icon = R.drawable.vpn_protocols3x,
  171. text = "VPN Protocols",
  172. focusRequester1,
  173. focusRequester2,
  174. navHostController
  175. )
  176. AddRowSettingsSmartTV(
  177. icon = R.drawable.smart_connect3x,
  178. text = "Smart Connect",
  179. isRowShown = true,
  180. isSheetShown = false,
  181. navHostController,
  182. focusRequester2,
  183. focusRequester3
  184. )
  185. AddRowSwitchTV(
  186. icon = R.drawable.adblock3x,
  187. text = "AdBlock",
  188. focusRequester3
  189. )
  190. AddRowSettingsTV(
  191. icon = R.drawable.kill_switch3x,
  192. text = "Kill Switch",
  193. topPadding = 40.dp,
  194. onClick = {
  195. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  196. gotoVPNSettingsTV(context)
  197. }
  198. }
  199. )
  200. AddRowSettingsTV(
  201. icon = R.drawable.split_tunneling3x,
  202. text = "Split Tunneling",
  203. onClick = { navHostController.navigate(Screen.SplitTunneling.route) }
  204. )
  205. AddRowSettingsTV(
  206. icon = R.drawable.notification3x,
  207. text = "Notifications",
  208. onClick = { navHostController.navigate(Screen.Notifications.route) }
  209. )
  210. // AddRowDarkLightThemeTV(
  211. // icon = Icons.Default.DarkMode,
  212. // text = "Theme")
  213. }
  214. }
  215. }
  216. }
  217. private fun gotoVPNSettingsTV(context: Context) {
  218. try {
  219. val intent = Intent("android.net.vpn.SETTINGS")
  220. intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
  221. ContextCompat.startActivity(context, intent, Bundle())
  222. } catch (e: Exception) {
  223. e.printStackTrace()
  224. }
  225. }
  226. @Composable
  227. fun ColumnScope.AddRowSettingsTV(
  228. icon: Int,
  229. text: String,
  230. topPadding: Dp = 40.dp,
  231. onClick: () -> Unit
  232. ) {
  233. var isRowFocused by remember { mutableStateOf(false) }
  234. Row(
  235. modifier = Modifier
  236. .fillMaxWidth()
  237. .padding(top = 5.dp, end = 27.dp)
  238. .clip(RoundedCornerShape(4.dp))
  239. .background(if (isRowFocused) Color.LightGray else Color.White)
  240. .onFocusChanged {
  241. isRowFocused = it.isFocused
  242. }
  243. .height(61.dp)
  244. .pointerInput(Unit) {
  245. detectTapGestures {
  246. onClick()
  247. }
  248. }
  249. .clickable {
  250. onClick()
  251. },
  252. horizontalArrangement = Arrangement.Start,
  253. verticalAlignment = Alignment.CenterVertically
  254. ) {
  255. Surface(
  256. modifier = Modifier.padding(start = 20.dp),
  257. color = Color.Transparent
  258. ) {
  259. Image(
  260. painter = painterResource(id = icon),
  261. contentDescription = "World",
  262. modifier = Modifier
  263. .padding(start = 0.dp)
  264. .size(24.dp)
  265. .weight(1f),
  266. colorFilter = ColorFilter.tint(
  267. MaterialTheme.colorScheme.inversePrimary) )
  268. }
  269. Surface(
  270. modifier = Modifier.padding(start = 0.dp),
  271. color = Color.Transparent
  272. ) {
  273. Text(text = text,
  274. style = MaterialTheme.typography.titleSmall,
  275. color = MaterialTheme.colorScheme.inversePrimary,
  276. maxLines = 1,
  277. modifier = Modifier
  278. .padding(start = 18.dp, end = 0.dp)
  279. .weight(1f)
  280. )
  281. }
  282. Spacer(modifier = Modifier.weight(1f))
  283. Surface(
  284. modifier = Modifier
  285. .padding(end = 20.dp)
  286. .align(Alignment.CenterVertically),
  287. color = Color.Transparent
  288. ) {
  289. Image(
  290. painter = painterResource(id = R.drawable.frontarrow3x),
  291. contentDescription = "Front_Arrow",
  292. modifier = Modifier
  293. .padding(start = 0.dp, end = 0.dp)
  294. .size(10.dp, 18.dp)
  295. .weight(1f),
  296. colorFilter = ColorFilter.tint(
  297. MaterialTheme.colorScheme.inversePrimary
  298. )
  299. )
  300. }
  301. }
  302. }
  303. @Composable
  304. fun ColumnScope.AddTextSettingsTV(
  305. text: String,
  306. size: TextUnit,
  307. color: Color,
  308. bottomPadding: Dp = 0.dp,
  309. startPadding: Dp = 0.dp,
  310. style: TextStyle
  311. ) {
  312. Text(
  313. text = text,
  314. style = style,
  315. color = color,
  316. modifier = Modifier.padding(bottom = bottomPadding, start = startPadding)
  317. )
  318. }
  319. @Composable
  320. fun ColumnScope.AddRowSwitchTV(icon: Int, text: String, focusRequester3: FocusRequester) {
  321. val context = LocalContext.current
  322. val basePreferenceHelper = BasePreferenceHelper(context)
  323. var isRowFocused by remember { mutableStateOf(false) }
  324. var isSwitch by remember { mutableStateOf(basePreferenceHelper.getAdBlockState()) }
  325. val scope = rememberCoroutineScope()
  326. val homeViewModel: HomeViewModel = viewModel{
  327. HomeViewModel(context, scope)
  328. }
  329. val isConnect: Int? = homeViewModel.isConnect.observeAsState().value
  330. Row(
  331. modifier = Modifier
  332. .fillMaxWidth()
  333. .padding(top = 5.dp, end = 27.dp)
  334. .clip(RoundedCornerShape(4.dp))
  335. .background(if (isRowFocused) Color.LightGray else Color.White)
  336. // .focusRequester(focusRequester3)
  337. .onFocusChanged {
  338. isRowFocused = it.isFocused
  339. }
  340. .clickable {
  341. isSwitch = !isSwitch
  342. basePreferenceHelper.saveAdBlockState(isSwitch)
  343. if (isConnect == App.CONNECTED || isConnect == App.CONNECTING) {
  344. Log.d("isConnect_State_vpn", "stopVPN")
  345. vpnConnectionsUtil.stopVpn()
  346. Handler().postDelayed(Runnable {
  347. vpnConnectionsUtil.startVpn()
  348. }, 500)
  349. }
  350. }
  351. .height(61.dp),
  352. horizontalArrangement = Arrangement.Start,
  353. verticalAlignment = Alignment.CenterVertically
  354. ) {
  355. Surface(
  356. modifier = Modifier.padding(start = 20.dp),
  357. color = Color.Transparent
  358. ) {
  359. Image(
  360. painter = painterResource(id = icon),
  361. contentDescription = "World",
  362. modifier = Modifier
  363. .padding(start = 0.dp)
  364. .size(24.dp)
  365. .weight(1f),
  366. colorFilter = ColorFilter.tint(
  367. MaterialTheme.colorScheme.inversePrimary) )
  368. }
  369. Surface(
  370. modifier = Modifier.padding(start = 0.dp),
  371. color = Color.Transparent
  372. ) {
  373. Text(text = text,
  374. style = MaterialTheme.typography.titleSmall,
  375. color = MaterialTheme.colorScheme.inversePrimary,
  376. maxLines = 1,
  377. modifier = Modifier
  378. .padding(start = 18.dp, end = 0.dp)
  379. .weight(1f)
  380. )
  381. }
  382. Spacer(modifier = Modifier.weight(1f))
  383. // val vpnConnectionsUtil = VPNConnectionsUtil(context, act, homeViewModel)
  384. Surface(
  385. modifier = Modifier
  386. .padding(start = 0.dp, end = 13.dp)
  387. .align(Alignment.CenterVertically),
  388. color = Color.Transparent
  389. ) {
  390. Switch(
  391. checked = isSwitch,
  392. onCheckedChange = {
  393. isSwitch = it
  394. basePreferenceHelper.saveAdBlockState(it)
  395. if (isConnect == App.CONNECTED || isConnect == App.CONNECTING) {
  396. Log.d("isConnect_State_vpn", "stopVPN")
  397. vpnConnectionsUtil.stopVpn()
  398. Handler().postDelayed(Runnable {
  399. vpnConnectionsUtil.startVpn()
  400. }, 500)
  401. } },
  402. modifier = Modifier.scale(0.8F),
  403. colors = SwitchDefaults.colors(
  404. checkedThumbColor = Color.White,
  405. // checkedTrackColor = MaterialTheme.colorScheme.surfaceContainerLowest,
  406. checkedTrackColor = colorResource(id = R.color.switch_green),
  407. // uncheckedThumbColor = MaterialTheme.colorScheme.onSecondaryContainer,
  408. uncheckedThumbColor = colorResource(id = R.color.white),
  409. // uncheckedTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest,
  410. uncheckedTrackColor = colorResource(id = R.color.switch_gray),
  411. // uncheckedBorderColor = MaterialTheme.colorScheme.surfaceContainerHighest
  412. uncheckedBorderColor = colorResource(id = R.color.switch_gray)
  413. ),
  414. thumbContent = {}
  415. )
  416. }
  417. }
  418. }
  419. @OptIn(ExperimentalMaterial3Api::class)
  420. @Composable
  421. fun ColumnScope.AddRowSettingsColumnTV(
  422. icon: Int,
  423. text: String,
  424. focusRequester1: FocusRequester,
  425. focusRequester2: FocusRequester,
  426. navHostController: NavHostController
  427. ) {
  428. val context = LocalContext.current
  429. val basePreferenceHelper = BasePreferenceHelper(context = context)
  430. val availableProtocols = getAvailableProtocols(basePreferenceHelper)
  431. var isSheetOpen by remember { mutableStateOf(false) }
  432. val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
  433. val protocols = listOf(
  434. "Auto", "WireGuard", "IKEv2", "OpenVPN TCP", "OpenVPN UDP"
  435. )
  436. var selectedProtocol by remember { mutableStateOf(basePreferenceHelper.getProtocol().full_name) }
  437. var isFirstRowFocused by remember { mutableStateOf(false) }
  438. // val serverListViewModel = serverListViewModelSplash
  439. // val serverListViewModel: ServerListViewModel = viewModel{
  440. // ServerListViewModel(context)
  441. // }
  442. // val configuration = LocalConfiguration.current
  443. // val isTablet = configuration.screenWidthDp > 840
  444. Row(
  445. modifier = Modifier
  446. .fillMaxWidth()
  447. .padding(top = 5.dp, end = 27.dp)
  448. .clip(RoundedCornerShape(4.dp))
  449. .background(if (isFirstRowFocused) Color.LightGray else Color.White)
  450. .height(61.dp)
  451. .onKeyEvent {
  452. when (it.key) {
  453. Key.DirectionDown -> {
  454. Log.d("test_settings_keys", "DirectionDown")
  455. Toast
  456. .makeText(
  457. context, "DirectionDown", Toast.LENGTH_SHORT
  458. )
  459. .show()
  460. focusRequester2.requestFocus()
  461. true
  462. }
  463. Key.DirectionLeft -> {
  464. Log.d("test_settings_keys", "DirectionLeft")
  465. Toast
  466. .makeText(
  467. context, "DirectionLeft", Toast.LENGTH_SHORT
  468. )
  469. .show()
  470. customNavigation(navHostController = navHostController, screen = BottomBarScreen.Settings)
  471. true
  472. }
  473. //
  474. // Key.DirectionRight -> {
  475. // Log.d("test_settings_keys", "DirectionRight")
  476. // Toast
  477. // .makeText(
  478. // context, "DirectionRight", Toast.LENGTH_SHORT
  479. // )
  480. // .show()
  481. // customNavigation(navHostController = navHostController, screen = BottomBarScreen.Help)
  482. // true
  483. // }
  484. else -> {
  485. false
  486. }
  487. }
  488. }
  489. .focusRequester(focusRequester1)
  490. .onFocusChanged {
  491. isFirstRowFocused = it.isFocused
  492. // if (!it.isFocused) focusRequester2.requestFocus()
  493. }
  494. .focusable()
  495. // .pointerInput(Unit) {
  496. // detectTapGestures {
  497. // isSheetOpen = true
  498. // }
  499. // }
  500. .clickable { isSheetOpen = true }
  501. ,
  502. horizontalArrangement = Arrangement.Start,
  503. verticalAlignment = Alignment.CenterVertically
  504. ) {
  505. Surface(
  506. modifier = Modifier.padding(start = 20.dp),
  507. color = Color.Transparent
  508. ) {
  509. Image(
  510. painter = painterResource(id = icon),
  511. contentDescription = "World",
  512. modifier = Modifier
  513. .padding(start = 0.dp)
  514. .size(24.dp)
  515. .weight(1f),
  516. colorFilter = ColorFilter.tint(
  517. MaterialTheme.colorScheme.inversePrimary)
  518. )
  519. }
  520. Surface(
  521. modifier = Modifier
  522. .padding(start = 0.dp)
  523. .align(Alignment.CenterVertically),
  524. color = Color.Transparent
  525. ) {
  526. Column(
  527. modifier = Modifier.background(Color.Transparent),
  528. verticalArrangement = Arrangement.Center
  529. ) {
  530. Text(text = text,
  531. color = MaterialTheme.colorScheme.inversePrimary,
  532. style = MaterialTheme.typography.titleSmall,
  533. maxLines = 1,
  534. modifier = Modifier
  535. .padding(start = 18.dp, end = 0.dp)
  536. // .weight(1f)
  537. )
  538. Spacer(modifier = Modifier.height(2.dp))
  539. Text(text = selectedProtocol,
  540. style = MaterialTheme.typography.headlineSmall.copy(
  541. fontSize = if (isTablet()) 14.sp else 12.sp
  542. ),
  543. color = MaterialTheme.colorScheme.inversePrimary,
  544. maxLines = 1,
  545. modifier = Modifier
  546. .padding(start = 18.dp, end = 0.dp)
  547. // .weight(1f)
  548. .alpha(0.6F),
  549. )
  550. }
  551. }
  552. Spacer(modifier = Modifier.weight(1f))
  553. Surface(
  554. modifier = Modifier
  555. .padding(end = 20.dp)
  556. .align(Alignment.CenterVertically),
  557. color = Color.Transparent
  558. ) {
  559. Image(
  560. painter = painterResource(id = R.drawable.frontarrow3x),
  561. contentDescription = "Front_Arrow",
  562. modifier = Modifier
  563. .padding(start = 0.dp, end = 0.dp)
  564. .size(10.dp, 18.dp)
  565. .weight(1f),
  566. colorFilter = ColorFilter.tint(
  567. MaterialTheme.colorScheme.inversePrimary
  568. )
  569. )
  570. }
  571. if (isSheetOpen) {
  572. ModalBottomSheet(
  573. onDismissRequest = { isSheetOpen = false },
  574. sheetState = sheetState,
  575. // containerColor = MaterialTheme.colorScheme.onBackground
  576. containerColor = Color.White,
  577. ) {
  578. Box(modifier = Modifier
  579. .background(Color.Transparent)
  580. .fillMaxWidth()
  581. .height(340.dp)
  582. .padding(start = 0.dp, top = 5.dp),
  583. ) {
  584. Column(
  585. verticalArrangement = Arrangement.Top,
  586. horizontalAlignment = Alignment.Start
  587. ) {
  588. AddTextSettings(
  589. text = "VPN Protocols",
  590. size = 18.sp,
  591. color = MaterialTheme.colorScheme.inversePrimary,
  592. bottomPadding = 15.dp,
  593. startPadding = 16.dp,
  594. style = MaterialTheme.typography.titleMedium
  595. )
  596. availableProtocols.forEach { protocol ->
  597. Row(
  598. modifier = Modifier
  599. .fillMaxWidth()
  600. .background(Color.Transparent)
  601. .padding(start = 2.dp)
  602. .selectable(
  603. selected = selectedProtocol == protocol,
  604. onClick = {
  605. selectedProtocol = protocol
  606. isSheetOpen = false
  607. // selectProtocolCallback(
  608. // protocol = protocol,
  609. // context,
  610. // serverListViewModel
  611. // )
  612. },
  613. )
  614. // .indication(
  615. // indication = null,
  616. // interactionSource = remember {
  617. // MutableInteractionSource()
  618. // }
  619. // )
  620. ,
  621. verticalAlignment = Alignment.CenterVertically
  622. ) {
  623. RadioButton(selected = protocol == selectedProtocol,
  624. onClick = {
  625. selectedProtocol = protocol
  626. isSheetOpen = false
  627. // selectProtocolCallback(protocol = protocol, context, serverListViewModel)
  628. },
  629. colors = RadioButtonDefaults.colors(
  630. selectedColor = colorResource(id = R.color.radio_button_blue),
  631. unselectedColor = colorResource(id = R.color.gray_icon),)
  632. )
  633. Text(text = protocol,
  634. modifier = Modifier.padding(start = 12.dp),
  635. color = MaterialTheme.colorScheme.inversePrimary,
  636. style = MaterialTheme.typography.bodySmall
  637. )
  638. }
  639. }
  640. }
  641. }
  642. }
  643. }
  644. }
  645. }
  646. @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
  647. @Composable
  648. fun ColumnScope.AddRowSettingsSmartTV(
  649. icon: Int,
  650. text: String,
  651. isRowShown: Boolean,
  652. isSheetShown: Boolean,
  653. navHostController: NavHostController,
  654. focusRequester2: FocusRequester,
  655. focusRequester3: FocusRequester
  656. ) {
  657. var isSmartSheetOpen by remember { mutableStateOf(false) }
  658. var isAnySpecificSheetOpen by remember { mutableStateOf(false) }
  659. val context = LocalContext.current
  660. val basePreferenceHelper = BasePreferenceHelper(context)
  661. var isRowFocused by remember { mutableStateOf(false) }
  662. // if (isRowShown) { }
  663. Row(
  664. modifier = Modifier
  665. .fillMaxWidth()
  666. .padding(top = 5.dp, end = 27.dp)
  667. .clip(RoundedCornerShape(4.dp))
  668. .background(if (isRowFocused) Color.LightGray else Color.White)
  669. // .onKeyEvent {
  670. // when (it.key) {
  671. // Key.DirectionLeft -> {
  672. // Log.d("test_settings_keys", "DirectionLeft")
  673. // Toast
  674. // .makeText(
  675. // context, "DirectionUp", Toast.LENGTH_SHORT
  676. // )
  677. // .show()
  678. // customNavigation(navHostController = navHostController, screen = BottomBarScreen.Home)
  679. // true
  680. // }
  681. // Key.DirectionRight -> {
  682. // Log.d("test_settings_keys", "DirectionRight")
  683. // Toast
  684. // .makeText(
  685. // context, "DirectionRight", Toast.LENGTH_SHORT
  686. // )
  687. // .show()
  688. // customNavigation(navHostController = navHostController, screen = BottomBarScreen.Help)
  689. // true
  690. // }
  691. // else -> {
  692. // false
  693. // }
  694. // }
  695. // }
  696. .focusRequester(focusRequester2)
  697. .onFocusChanged {
  698. isRowFocused = it.isFocused
  699. // if (!it.isFocused) focusRequester3.requestFocus()
  700. }
  701. .height(61.dp)
  702. .focusable()
  703. .clickable { isSmartSheetOpen = true },
  704. horizontalArrangement = Arrangement.Start,
  705. verticalAlignment = Alignment.CenterVertically
  706. ) {
  707. Surface(
  708. modifier = Modifier.padding(start = 20.dp),
  709. color = Color.Transparent
  710. ) {
  711. Image(
  712. painter = painterResource(id = icon),
  713. contentDescription = "World",
  714. modifier = Modifier
  715. .padding(start = 0.dp)
  716. .size(24.dp)
  717. .weight(1f),
  718. colorFilter = ColorFilter.tint(
  719. MaterialTheme.colorScheme.inversePrimary)
  720. )
  721. }
  722. Surface(
  723. modifier = Modifier.padding(start = 0.dp),
  724. color = Color.Transparent
  725. ) {
  726. Text(text = text,
  727. style = MaterialTheme.typography.titleSmall,
  728. color = MaterialTheme.colorScheme.inversePrimary,
  729. maxLines = 1,
  730. modifier = Modifier
  731. .padding(start = 18.dp, end = 0.dp)
  732. .weight(1f)
  733. )
  734. }
  735. Spacer(modifier = Modifier.weight(1f))
  736. Surface(
  737. modifier = Modifier
  738. .padding(end = 20.dp)
  739. .align(Alignment.CenterVertically),
  740. color = Color.Transparent
  741. ) {
  742. Image(
  743. painter = painterResource(id = R.drawable.frontarrow3x),
  744. contentDescription = "Front_Arrow",
  745. modifier = Modifier
  746. .padding(start = 0.dp, end = 3.dp)
  747. .size(10.dp, 18.dp)
  748. .weight(1f),
  749. colorFilter = ColorFilter.tint(
  750. MaterialTheme.colorScheme.inversePrimary
  751. )
  752. )
  753. }
  754. }
  755. if (isSmartSheetOpen) {
  756. val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
  757. var selectedSmartConnect by remember {
  758. mutableStateOf(basePreferenceHelper.getSmartList()) }
  759. ModalBottomSheet(
  760. onDismissRequest = { isSmartSheetOpen = false
  761. BottomBarScreen.Settings.isTrue = false
  762. },
  763. sheetState = sheetState,
  764. containerColor = Color.White
  765. ) {
  766. Box(modifier = Modifier
  767. .background(Color.Transparent)
  768. .fillMaxWidth()
  769. .height(250.dp)
  770. .padding(start = 0.dp, top = 10.dp),
  771. ) {
  772. val selectedSmartList = basePreferenceHelper.getSmartList()
  773. val smartServer = basePreferenceHelper.getSmartServerObject() ?: basePreferenceHelper.getRecommendedServerObject()
  774. Column(
  775. verticalArrangement = Arrangement.Top,
  776. horizontalAlignment = Alignment.Start
  777. ) {
  778. AddTextSettings(
  779. text = "Smart Connect",
  780. size = 18.sp,
  781. color = MaterialTheme.colorScheme.inversePrimary,
  782. bottomPadding = 20.dp,
  783. startPadding = 16.dp,
  784. style = MaterialTheme.typography.titleMedium
  785. )
  786. smartConnect.forEach { smart ->
  787. Row(
  788. modifier = Modifier
  789. .fillMaxWidth()
  790. .background(Color.Transparent)
  791. .padding(start = 2.dp)
  792. .selectable(
  793. selected = selectedSmartConnect == smart,
  794. onClick = {
  795. selectedSmartConnect = smart
  796. basePreferenceHelper.saveSmartList(smart)
  797. isSmartSheetOpen = false
  798. if (smart == smartConnect[2]) {
  799. Log.d("smartLocationList Row", smart)
  800. isAnySpecificSheetOpen = true
  801. }
  802. },
  803. )
  804. // .indication(
  805. // indication = null,
  806. // interactionSource = remember {
  807. // MutableInteractionSource()
  808. // }
  809. // )
  810. ,
  811. verticalAlignment = Alignment.CenterVertically
  812. ) {
  813. RadioButton(selected = smart == selectedSmartConnect,
  814. onClick = {
  815. selectedSmartConnect = smart
  816. basePreferenceHelper.saveSmartList(smart)
  817. isSmartSheetOpen = false
  818. if (smart == smartConnect[2]) {
  819. Log.d("smartLocationList RB", smart)
  820. isAnySpecificSheetOpen = true
  821. }
  822. },
  823. colors = RadioButtonDefaults.colors(
  824. selectedColor = colorResource(id = R.color.radio_button_blue),
  825. unselectedColor = colorResource(id = R.color.gray_icon),)
  826. )
  827. Column {
  828. Text(text = smart,
  829. modifier = Modifier.padding(start = 12.dp),
  830. color = MaterialTheme.colorScheme.inversePrimary,
  831. style = MaterialTheme.typography.bodySmall
  832. )
  833. if (smart == smartConnect[2]) {
  834. if (selectedSmartList == smartConnect[2]) {
  835. Log.d("smartLocationList Row", smart)
  836. Text(text = "${smartServer?.server_name}",
  837. modifier = Modifier.padding(start = 12.dp),
  838. // color = MaterialTheme.colorScheme.inversePrimary,
  839. style = MaterialTheme.typography.labelLarge.copy(
  840. fontSize = 12.sp,
  841. color = colorResource(id = R.color.gray_icon)
  842. )
  843. )
  844. }
  845. }
  846. }
  847. }
  848. }
  849. }
  850. }
  851. }
  852. }
  853. if (isAnySpecificSheetOpen) {
  854. val sheetStateAny = rememberModalBottomSheetState(skipPartiallyExpanded = true)
  855. val searchListViewModel = searchListViewModelSplash
  856. // val searchText = searchListViewModel.searchText.observeAsState().value
  857. var searchText1 by remember { mutableStateOf("") }
  858. val isActive = searchListViewModel.isActive.observeAsState().value
  859. val scope = rememberCoroutineScope()
  860. ModalBottomSheet(
  861. onDismissRequest = { isAnySpecificSheetOpen = false
  862. BottomBarScreen.Settings.isTrue = false
  863. },
  864. sheetState = sheetStateAny,
  865. containerColor = Color.White,
  866. modifier = Modifier
  867. .padding(top = 15.dp)
  868. .fillMaxSize()
  869. ) {
  870. Box(modifier = Modifier
  871. .background(Color.Transparent)
  872. // .fillMaxWidth()
  873. // .fillMaxHeight()
  874. .padding(start = 0.dp, top = 10.dp)
  875. .fillMaxSize(),
  876. ) {
  877. Column(
  878. verticalArrangement = Arrangement.Top,
  879. horizontalAlignment = Alignment.Start
  880. ) {
  881. CompositionLocalProvider(
  882. LocalOverscrollConfiguration provides null
  883. ) {
  884. LaunchedEffect(key1 = searchText1) {
  885. Log.d("test_search_logic", "LaunchedEffect $searchText1")
  886. val delay = if (searchText1.isEmpty()) 0L else 300L
  887. delay(delay)
  888. val query = searchText1.ifEmpty { "settings_screen" }
  889. searchListViewModel.getCountries(query, true)
  890. }
  891. // if (isActive == false) {
  892. // searchText1 = ""
  893. // }
  894. DockedSearchBar(
  895. query = searchText1,
  896. onQueryChange = {
  897. searchText1 = it
  898. // scope.launch {
  899. // searchListViewModel.searchTextChange(it)
  900. // }
  901. },
  902. onSearch = {
  903. scope.launch {
  904. searchListViewModel.isActiveChange(state = false, true)
  905. }
  906. // keyboardController?.hide()
  907. },
  908. active = isActive!!,
  909. onActiveChange = {
  910. scope.launch {
  911. searchListViewModel.isActiveChange(it, isFromSettings = true)
  912. }
  913. },
  914. placeholder = {
  915. Text(
  916. text = "Search Location",
  917. style = MaterialTheme.typography.displaySmall,
  918. color = colorResource(id = R.color.dark_blue_gray_text)
  919. )
  920. },
  921. leadingIcon = {
  922. Icon(
  923. painter = painterResource(id = R.drawable.search3x),
  924. contentDescription = "Search Icon",
  925. modifier = Modifier
  926. .size(21.dp)
  927. )
  928. },
  929. colors = SearchBarDefaults.colors(
  930. containerColor = colorResource(id = R.color.white),
  931. dividerColor = Color.Transparent,
  932. inputFieldColors = TextFieldDefaults.colors(
  933. focusedTextColor = colorResource(id = R.color.dark_blue_gray_text),
  934. unfocusedTextColor = colorResource(id = R.color.dark_blue_gray_text),
  935. unfocusedIndicatorColor = colorResource(id = R.color.dark_blue_gray_text),
  936. focusedIndicatorColor = colorResource(id = R.color.dark_blue_gray_text),
  937. disabledIndicatorColor = colorResource(id = R.color.dark_blue_gray_text),
  938. cursorColor = colorResource(id = R.color.dark_blue_gray_text),
  939. )
  940. ),
  941. modifier = Modifier
  942. .fillMaxWidth()
  943. .height(50.dp)
  944. .padding(horizontal = 10.dp)
  945. .background(Color.Transparent)
  946. ) {}
  947. val searchServersList = searchListViewModel.countriesListSettings.observeAsState().value
  948. LazyColumn(
  949. modifier = Modifier
  950. .padding(top = 20.dp, bottom = 40.dp)
  951. ) {
  952. items(items = searchServersList!!) { server ->
  953. ServerSpecificItem(
  954. server, navHostController = navHostController,
  955. onServerDisable = { isAnySpecificSheetOpen = false }
  956. )
  957. }
  958. }
  959. }
  960. }
  961. }
  962. }
  963. }
  964. }
  965. @OptIn(ExperimentalMaterial3Api::class)
  966. @Composable
  967. fun AddRowDarkLightThemeTV(
  968. icon: ImageVector,
  969. text: String,
  970. ) {
  971. var isThemeSheetOpen by remember { mutableStateOf(false) }
  972. val sheetState = rememberModalBottomSheetState()
  973. val context = LocalContext.current
  974. val basePreferenceHelper = BasePreferenceHelper(context)
  975. val selectedtheme = remember { mutableStateOf(basePreferenceHelper.getTheme()) }
  976. val isSystemInDarkTheme = isSystemInDarkTheme()
  977. val systemTheme by remember { mutableStateOf(isSystemInDarkTheme) }
  978. Row(
  979. modifier = Modifier
  980. .fillMaxWidth()
  981. .padding(top = 40.dp, end = 27.dp)
  982. .background(Color.Transparent)
  983. .pointerInput(Unit) {
  984. detectTapGestures {
  985. isThemeSheetOpen = true
  986. }
  987. }
  988. .height(24.dp),
  989. horizontalArrangement = Arrangement.Start,
  990. verticalAlignment = Alignment.CenterVertically
  991. ) {
  992. Surface(
  993. modifier = Modifier.padding(start = 0.dp),
  994. color = Color.Transparent
  995. ) {
  996. Image(
  997. imageVector = icon,
  998. contentDescription = "Select Theme",
  999. modifier = Modifier
  1000. .padding(start = 0.dp)
  1001. .size(24.dp)
  1002. .weight(1f),
  1003. colorFilter = ColorFilter.tint(
  1004. MaterialTheme.colorScheme.inversePrimary) )
  1005. }
  1006. Surface(
  1007. modifier = Modifier.padding(start = 0.dp),
  1008. color = Color.Transparent
  1009. ) {
  1010. Text(text = text,
  1011. style = MaterialTheme.typography.titleMedium,
  1012. color = MaterialTheme.colorScheme.inversePrimary,
  1013. maxLines = 1,
  1014. modifier = Modifier
  1015. .padding(start = 18.dp, end = 0.dp)
  1016. .weight(1f)
  1017. )
  1018. }
  1019. Spacer(modifier = Modifier.weight(1f))
  1020. Surface(
  1021. modifier = Modifier
  1022. .padding(start = 15.dp)
  1023. .align(Alignment.CenterVertically),
  1024. color = Color.Transparent
  1025. ) {
  1026. Image(
  1027. painter = painterResource(id = R.drawable.frontarrow3x),
  1028. contentDescription = "Front_Arrow",
  1029. modifier = Modifier
  1030. .padding(start = 0.dp, end = 0.dp)
  1031. .size(10.dp, 18.dp)
  1032. .weight(1f),
  1033. colorFilter = ColorFilter.tint(
  1034. MaterialTheme.colorScheme.inversePrimary
  1035. )
  1036. )
  1037. }
  1038. }
  1039. if (isThemeSheetOpen) {
  1040. ModalBottomSheet(
  1041. onDismissRequest = { isThemeSheetOpen = false
  1042. },
  1043. sheetState = sheetState,
  1044. containerColor = Color.White,
  1045. ) {
  1046. Box(modifier = Modifier
  1047. .background(Color.Transparent)
  1048. .fillMaxWidth()
  1049. .height(250.dp)
  1050. .padding(start = 0.dp, top = 10.dp),
  1051. ) {
  1052. Log.d("test_theme", "systemTheme -> $systemTheme")
  1053. Column(
  1054. verticalArrangement = Arrangement.Top,
  1055. horizontalAlignment = Alignment.Start
  1056. ) {
  1057. AddTextSettings(
  1058. text = "Theme",
  1059. size = 18.sp,
  1060. color = MaterialTheme.colorScheme.inversePrimary,
  1061. bottomPadding = 20.dp,
  1062. startPadding = 16.dp,
  1063. style = MaterialTheme.typography.titleSmall
  1064. )
  1065. themesList.forEach { theme ->
  1066. Row(
  1067. modifier = Modifier
  1068. .fillMaxWidth()
  1069. .background(Color.Transparent)
  1070. .padding(start = 2.dp)
  1071. .selectable(
  1072. selected = theme == selectedtheme.value,
  1073. onClick = {
  1074. selectedtheme.value = theme
  1075. basePreferenceHelper.saveTheme(selectedtheme.value)
  1076. if (selectedtheme.value == themesList[0]) {
  1077. Log.d("test_theme", "true: -> $systemTheme")
  1078. isDarkTheme.value = systemTheme
  1079. } else {
  1080. Log.d("test_theme", "false: -> $systemTheme")
  1081. isDarkTheme.value = selectedtheme.value == themesList[2]
  1082. }
  1083. isThemeSheetOpen = false
  1084. },
  1085. )
  1086. // .indication(
  1087. // indication = null,
  1088. // interactionSource = remember {
  1089. // MutableInteractionSource()
  1090. // }
  1091. // )
  1092. ,
  1093. verticalAlignment = Alignment.CenterVertically
  1094. ) {
  1095. // val themeState = isSystemInDarkTheme()
  1096. // val isSystemInDarkTheme by remember { mutableStateOf(themeState) }
  1097. RadioButton(selected = theme == selectedtheme.value,
  1098. onClick = {
  1099. selectedtheme.value = theme
  1100. basePreferenceHelper.saveTheme(selectedtheme.value)
  1101. if (selectedtheme.value == themesList[0])
  1102. {
  1103. Log.d("test_theme", "true: -> $systemTheme")
  1104. isDarkTheme.value = systemTheme
  1105. }
  1106. else {
  1107. Log.d("test_theme", "false: -> $systemTheme")
  1108. isDarkTheme.value = selectedtheme.value == themesList[2]
  1109. }
  1110. isThemeSheetOpen = false
  1111. },
  1112. colors = RadioButtonDefaults.colors(
  1113. selectedColor = colorResource(id = R.color.radio_button_blue),
  1114. unselectedColor = colorResource(id = R.color.gray_icon),)
  1115. )
  1116. Text(text = theme,
  1117. modifier = Modifier.padding(start = 12.dp),
  1118. style = MaterialTheme.typography.bodySmall,
  1119. color = MaterialTheme.colorScheme.inversePrimary
  1120. )
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. }
  1127. }