SettingsScreenTV.kt 49 KB

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