HomeScreenTV.kt 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813
  1. package com.vpn.fastestvpnservice.screensTV
  2. //import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.act
  3. import android.content.Context
  4. import android.os.Build
  5. import android.os.Handler
  6. import android.util.Log
  7. import android.widget.Toast
  8. import androidx.activity.ComponentActivity
  9. import androidx.compose.animation.animateColorAsState
  10. import androidx.compose.foundation.BorderStroke
  11. import androidx.compose.foundation.Image
  12. import androidx.compose.foundation.background
  13. import androidx.compose.foundation.border
  14. import androidx.compose.foundation.clickable
  15. import androidx.compose.foundation.focusable
  16. import androidx.compose.foundation.interaction.MutableInteractionSource
  17. import androidx.compose.foundation.layout.Arrangement
  18. import androidx.compose.foundation.layout.Box
  19. import androidx.compose.foundation.layout.BoxScope
  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.RowScope
  24. import androidx.compose.foundation.layout.Spacer
  25. import androidx.compose.foundation.layout.aspectRatio
  26. import androidx.compose.foundation.layout.fillMaxHeight
  27. import androidx.compose.foundation.layout.fillMaxSize
  28. import androidx.compose.foundation.layout.fillMaxWidth
  29. import androidx.compose.foundation.layout.height
  30. import androidx.compose.foundation.layout.padding
  31. import androidx.compose.foundation.layout.size
  32. import androidx.compose.foundation.layout.wrapContentHeight
  33. import androidx.compose.foundation.layout.wrapContentSize
  34. import androidx.compose.foundation.shape.CircleShape
  35. import androidx.compose.foundation.shape.RoundedCornerShape
  36. import androidx.compose.foundation.text.ClickableText
  37. import androidx.compose.material.icons.Icons
  38. import androidx.compose.material.icons.outlined.ThumbDown
  39. import androidx.compose.material.icons.outlined.ThumbUp
  40. import androidx.compose.material.ripple.rememberRipple
  41. import androidx.compose.material3.AlertDialog
  42. import androidx.compose.material3.Button
  43. import androidx.compose.material3.ButtonDefaults
  44. import androidx.compose.material3.ExperimentalMaterial3Api
  45. import androidx.compose.material3.Icon
  46. import androidx.compose.material3.IconButton
  47. import androidx.compose.material3.MaterialTheme
  48. import androidx.compose.material3.Surface
  49. import androidx.compose.material3.Text
  50. import androidx.compose.runtime.Composable
  51. import androidx.compose.runtime.DisposableEffect
  52. import androidx.compose.runtime.LaunchedEffect
  53. import androidx.compose.runtime.MutableState
  54. import androidx.compose.runtime.getValue
  55. import androidx.compose.runtime.livedata.observeAsState
  56. import androidx.compose.runtime.mutableStateOf
  57. import androidx.compose.runtime.remember
  58. import androidx.compose.runtime.rememberCoroutineScope
  59. import androidx.compose.runtime.rememberUpdatedState
  60. import androidx.compose.runtime.saveable.rememberSaveable
  61. import androidx.compose.runtime.setValue
  62. import androidx.compose.ui.Alignment
  63. import androidx.compose.ui.Modifier
  64. import androidx.compose.ui.draw.alpha
  65. import androidx.compose.ui.draw.clip
  66. import androidx.compose.ui.draw.paint
  67. import androidx.compose.ui.focus.FocusRequester
  68. import androidx.compose.ui.focus.focusRequester
  69. import androidx.compose.ui.focus.onFocusChanged
  70. import androidx.compose.ui.graphics.Color
  71. import androidx.compose.ui.graphics.ColorFilter
  72. import androidx.compose.ui.graphics.painter.Painter
  73. import androidx.compose.ui.input.key.Key
  74. import androidx.compose.ui.input.key.KeyEventType
  75. import androidx.compose.ui.input.key.key
  76. import androidx.compose.ui.input.key.onKeyEvent
  77. import androidx.compose.ui.input.key.type
  78. import androidx.compose.ui.layout.ContentScale
  79. import androidx.compose.ui.platform.LocalContext
  80. import androidx.compose.ui.platform.LocalLifecycleOwner
  81. import androidx.compose.ui.res.colorResource
  82. import androidx.compose.ui.res.painterResource
  83. import androidx.compose.ui.text.AnnotatedString
  84. import androidx.compose.ui.text.TextStyle
  85. import androidx.compose.ui.unit.TextUnit
  86. import androidx.compose.ui.unit.dp
  87. import androidx.compose.ui.unit.sp
  88. import androidx.compose.ui.window.DialogProperties
  89. import androidx.constraintlayout.compose.ConstraintLayout
  90. import androidx.constraintlayout.compose.Dimension
  91. import androidx.lifecycle.Lifecycle
  92. import androidx.lifecycle.LifecycleEventObserver
  93. import androidx.lifecycle.LifecycleOwner
  94. import androidx.lifecycle.viewmodel.compose.viewModel
  95. import androidx.navigation.NavHostController
  96. import com.vpn.fastestvpnservice.MainActivity
  97. import com.vpn.fastestvpnservice.R
  98. import com.vpn.fastestvpnservice.beans.Protocol
  99. import com.vpn.fastestvpnservice.beans.Server
  100. import com.vpn.fastestvpnservice.beans.isDarkTheme
  101. import com.vpn.fastestvpnservice.beans.toChangeServer
  102. import com.vpn.fastestvpnservice.constants.AppEnum
  103. import com.vpn.fastestvpnservice.constants.smartConnect
  104. import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
  105. import com.vpn.fastestvpnservice.interfaces.NetworkSpeedCallback
  106. import com.vpn.fastestvpnservice.interfaces.ServerCallbacksTV
  107. import com.vpn.fastestvpnservice.navigation.isFirstItemFocused
  108. import com.vpn.fastestvpnservice.navigation.isFirstItemPressed
  109. import com.vpn.fastestvpnservice.navigation.isHomeScreenPressed
  110. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.StringDown
  111. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.StringDownUnit
  112. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.StringUp
  113. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.StringUpUnit
  114. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.isServerDialog
  115. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.navHostController1
  116. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.protocolObj
  117. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.serverObj
  118. import com.vpn.fastestvpnservice.screens.serverListViewModelSplash
  119. import com.vpn.fastestvpnservice.sealedClass.ScreenTV
  120. import com.vpn.fastestvpnservice.ui.theme.customTypography
  121. import com.vpn.fastestvpnservice.ui.theme.customTypography2
  122. import com.vpn.fastestvpnservice.utils.Utils
  123. import com.vpn.fastestvpnservice.utils.VPNConnectionsUtil
  124. import com.vpn.fastestvpnservice.utils.isTablet
  125. import com.vpn.fastestvpnservice.viewmodels.HomeViewModel
  126. import com.vpn.fastestvpnservice.viewmodels.ServerListViewModel
  127. import com.wireguard.android.backend.GoBackend
  128. import de.blinkt.openvpn.core.App
  129. import kotlinx.coroutines.delay
  130. import java.util.Locale
  131. var isProtocolDialog: MutableState<Boolean> = mutableStateOf(false)
  132. var isLocationsEnabled: MutableState<Boolean> = mutableStateOf(false)
  133. var isDedicatedIpEnabled: MutableState<Boolean> = mutableStateOf(false)
  134. var isStreamingEnabled: MutableState<Boolean> = mutableStateOf(false)
  135. var isDvpnEnabled: MutableState<Boolean> = mutableStateOf(false)
  136. var isP2pEnabled: MutableState<Boolean> = mutableStateOf(false)
  137. var locations: MutableList<Server> = ArrayList<Server>()
  138. var dedicatedIP: MutableList<Server> = ArrayList<Server>()
  139. var streaming: MutableList<Server> = ArrayList<Server>()
  140. var dvpn: MutableList<Server> = ArrayList<Server>()
  141. var p2p: MutableList<Server> = ArrayList<Server>()
  142. val onServerTV = object : ServerCallbacksTV {
  143. @Composable
  144. override fun onServerSelected(
  145. context: Context, homeViewModel: HomeViewModel,
  146. onClick: () -> Unit, isServerDialogShown: Boolean, server: Server
  147. ) {
  148. val vpnConnectionsUtil = VPNConnectionsUtil(context, activityGlobal, homeViewModel)
  149. val basePreferenceHelper = BasePreferenceHelper(context)
  150. // val serverListViewModel: ServerListViewModel = viewModel{
  151. // ServerListViewModel(context)
  152. // }
  153. Log.d("ServerCallbacks", "onServerSelected called! : ${server.server_name}")
  154. val lastServer = basePreferenceHelper.getConnectedServer()
  155. val connectState = basePreferenceHelper.getConnectState()
  156. if (isServerDialogShown) {
  157. Log.d("ServerCallbacks", "onServerSelected true!")
  158. if (connectState == 2) {
  159. Log.d("ServerCallbacks", "onServerSelected isVPNConnected!")
  160. if (lastServer?.id != server.id) {
  161. isServerDialog.value = true
  162. serverObj.value = server
  163. }
  164. else {
  165. basePreferenceHelper.setConnectedServer(server)
  166. basePreferenceHelper.setServerObject(server)
  167. }
  168. } else {
  169. serverListViewModelSplash.setRecentlyConnectedServer(server)
  170. basePreferenceHelper.setConnectedServer(server)
  171. basePreferenceHelper.setServerObject(server)
  172. vpnConnectionsUtil.startVpn()
  173. }
  174. }
  175. else {
  176. Log.d("ServerCallbacks", "onServerSelected else")
  177. vpnConnectionsUtil.startVpn()
  178. }
  179. MainActivity.isSelectedServersShown = true
  180. onClick()
  181. }
  182. override fun onChangeProtocol(
  183. protocol: Protocol,
  184. context: Context,
  185. serverListViewModel: ServerListViewModel
  186. ) {
  187. val prefHelper = BasePreferenceHelper(context)
  188. // val wg = VPNConnectionsUtil(context, act , homeViewModel1)
  189. protocolObj.value = protocol
  190. val connectState = prefHelper.getConnectState()
  191. if (getEnableProtocols(protocol.title, prefHelper)) {
  192. Log.d("OnChangeProtocol", "getEnableProtocols yes!")
  193. if (prefHelper.getProtocol().index != protocol.index) {
  194. if (connectState == 2) {
  195. navHostController1.popBackStack()
  196. isProtocolDialog.value = true
  197. }
  198. else {
  199. prefHelper.saveProtocol(protocol = protocol)
  200. val lastServer = prefHelper.getConnectedServer()
  201. val serverList = prefHelper.getServerData()
  202. // val serverList = serverListViewModelSplash.liveDataGetServersGlobal.value
  203. if (lastServer != null) {
  204. val serverProtocol = serverListViewModel.getFilteredServerByProtocolChanged(serverList, lastServer, protocol)
  205. if (serverProtocol.isFound) {
  206. prefHelper.setServerObject(serverProtocol.server)
  207. val lastServer1 = prefHelper.getServerObject()
  208. }
  209. }
  210. serverListViewModelSplash.setCountryDataTV()
  211. }
  212. }
  213. }
  214. else {
  215. // Screen.Subscription.isTrue = true
  216. // navHostController1.let {
  217. // it.navigate(Screen.Subscription.route)
  218. // }
  219. }
  220. }
  221. }
  222. val networkSpeedTV = object : NetworkSpeedCallback {
  223. override fun setNetworkSpeed(down: Double, up: Double, downUnit: String, upUnit: String) {
  224. StringDown.value = down
  225. StringUp.value = up
  226. StringDownUnit.value = downUnit
  227. StringUpUnit.value = upUnit
  228. Log.d("setNetworkSpeed_TV", "Down: ${StringDown.value} Up: ${StringUp.value}")
  229. }
  230. }
  231. lateinit var activityGlobal: ComponentActivity
  232. @Composable
  233. fun HomeTV(
  234. navHostController: NavHostController,
  235. settingsNavHostController: NavHostController,
  236. activity: ComponentActivity
  237. ) {
  238. activityGlobal = activity
  239. navHostController1 = navHostController
  240. val context = LocalContext.current
  241. val basePreferenceHelper = BasePreferenceHelper(context)
  242. val prefHelper = BasePreferenceHelper(context)
  243. val scope = rememberCoroutineScope()
  244. val homeViewModel: HomeViewModel = viewModel{
  245. HomeViewModel(context, scope)
  246. }
  247. var isConnect: Int? = homeViewModel.isConnect.observeAsState().value
  248. isConnect = basePreferenceHelper.getConnectState()
  249. val focusRequester1 = remember { FocusRequester() }
  250. val focusRequester2 = remember { FocusRequester() }
  251. val focusRequester3 = remember { FocusRequester() }
  252. var isButtonFocused by remember { mutableStateOf(false) }
  253. val vpnConnectionsUtil = VPNConnectionsUtil(context, activity, homeViewModel)
  254. OnLifecycleEvent { owner, event ->
  255. when (event) {
  256. Lifecycle.Event.ON_RESUME -> {
  257. Log.d("test_home_resume", "ON_RESUME: Home Screen!")
  258. navHostController1 = navHostController
  259. try {
  260. App.backend?.runningTunnelNames
  261. } catch (e: Exception) {
  262. val back = GoBackend(context)
  263. App.setBackend(back)
  264. App.backend = App.getBackend()
  265. }
  266. vpnConnectionsUtil.onResumeCallBack()
  267. homeViewModel.getIp()
  268. // var filterServerByConnectionCount = Server()
  269. // if (prefHelper.getServerObject() != null) {
  270. // prefHelper.getServerObject()?.let {
  271. // filterServerByConnectionCount = it
  272. // }
  273. // } else {
  274. // val smartServer = basePreferenceHelper.getSmartServerObject()
  275. // smartServer?.let {
  276. // filterServerByConnectionCount = it
  277. // }
  278. // }
  279. //
  280. // server = filterServerByConnectionCount
  281. //
  282. //// splashViewModel.serverDataApi()
  283. homeViewModel.validatePassword(
  284. prefHelper.getUser()?.userinfo?.email.toString(),
  285. prefHelper.getPassword().toString(),
  286. "TV",
  287. Build.VERSION.RELEASE
  288. )
  289. }
  290. Lifecycle.Event.ON_PAUSE -> {
  291. Log.d("test_home_resume", "ON_PAUSE: Home Screen!")
  292. vpnConnectionsUtil.onPauseCallBack()
  293. }
  294. Lifecycle.Event.ON_STOP -> {
  295. Log.d("test_home_resume", "ON_STOP: Home Screen!")
  296. vpnConnectionsUtil.onStopCallBack()
  297. }
  298. Lifecycle.Event.ON_DESTROY -> {
  299. Log.d("test_home_resume", "ON_DESTROY: Home Screen!")
  300. vpnConnectionsUtil.onPauseCallBack()
  301. }
  302. else -> {
  303. Log.d("test_home_resume", "else: Home Screen!")
  304. }
  305. }
  306. }
  307. val validateResponse = homeViewModel.liveDataValidate.observeAsState().value
  308. validateResponse?.let {
  309. Log.d("test_api_validate", "home => ${it.status} ${it.message}")
  310. if (!it.status) {
  311. basePreferenceHelper.setLoggedInState(false)
  312. basePreferenceHelper.clearAllData()
  313. settingsNavHostController.popBackStack()
  314. settingsNavHostController.navigate(ScreenTV.LoginTV.route)
  315. }
  316. homeViewModel._mutableLiveDataValidate.value = null
  317. }
  318. if (isHomeScreenPressed.value) {
  319. LaunchedEffect(key1 = Unit) {
  320. focusRequester1.requestFocus()
  321. }
  322. isHomeScreenPressed.value = false
  323. }
  324. var isLaunched by rememberSaveable { mutableStateOf(true) }
  325. if (isLaunched) {
  326. Log.d("test_launch","liveDataGetServersGlobal")
  327. val countries = serverListViewModelSplash.liveDataGetServersGlobal.value
  328. countries?.forEachIndexed { index, serverData ->
  329. Log.d("test_serverlist_tv","$index ${serverData?.name} ${serverData?.servers?.size}")
  330. if (serverData?.name?.equals("Servers") == true) {
  331. serverData.servers?.let { locations = it }
  332. if (locations.size > 0) isLocationsEnabled.value = true
  333. }
  334. else if (serverData?.name?.equals("Dedicated IP") == true) {
  335. serverData.servers?.let { dedicatedIP = it }
  336. if (dedicatedIP.size > 0) isDedicatedIpEnabled.value = true
  337. }
  338. else if (serverData?.name?.equals("Streaming") == true) {
  339. serverData.servers?.let { streaming = it }
  340. if (streaming.size > 0) isStreamingEnabled.value = true
  341. }
  342. else if (serverData?.name?.equals("D-VPN") == true) {
  343. serverData.servers?.let { dvpn = it }
  344. if (dvpn.size > 0) isDvpnEnabled.value = true
  345. }
  346. else if (serverData?.name?.equals("P2P") == true) {
  347. serverData.servers?.let { p2p = it }
  348. if (p2p.size > 0) isP2pEnabled.value = true
  349. }
  350. }
  351. isLaunched = false
  352. }
  353. // BackHandler {
  354. // Toast.makeText(
  355. // context, "BackHandler Home TV", Toast.LENGTH_SHORT
  356. // ).show()
  357. // }
  358. Column(
  359. modifier = Modifier
  360. .background(MaterialTheme.colorScheme.background)
  361. .fillMaxSize(),
  362. ) {
  363. if (isServerDialog.value) {
  364. ShowServerDialogTV(
  365. basePreferenceHelper,
  366. vpnConnectionsUtil
  367. )
  368. }
  369. if (isProtocolDialog.value) {
  370. isFirstItemPressed.value = true
  371. isFirstItemFocused.value = true
  372. ShowProtocolDialogTV(
  373. basePreferenceHelper,
  374. vpnConnectionsUtil,
  375. serverListViewModelSplash
  376. )
  377. }
  378. // 1st box
  379. ConstraintLayout(modifier = Modifier
  380. .fillMaxSize()
  381. .weight(0.6f)
  382. .background(Color.Transparent)
  383. )
  384. {
  385. val (firstComposable, secondComposable) = createRefs()
  386. val guideline = createGuidelineFromTop(0.7f)
  387. Box(
  388. modifier = Modifier
  389. .constrainAs(firstComposable) {
  390. top.linkTo(parent.top)
  391. bottom.linkTo(guideline)
  392. start.linkTo(parent.start)
  393. end.linkTo(parent.end)
  394. width = Dimension.fillToConstraints
  395. height = Dimension.fillToConstraints
  396. }
  397. .background(Color.Transparent)
  398. ) {
  399. Image(
  400. modifier = Modifier
  401. .fillMaxWidth()
  402. .fillMaxHeight()
  403. .padding(top = 0.dp),
  404. // painter = if (isConnect == App.CONNECTED) blueBackgroundTV() else pinkBackgroundTV(),
  405. painter = if (isConnect == App.CONNECTED) blueBackgroundTV()
  406. else pinkBackgroundTV(),
  407. contentDescription = "Background Color",
  408. contentScale = ContentScale.FillBounds,
  409. )
  410. Image(
  411. modifier = Modifier
  412. .fillMaxWidth()
  413. .fillMaxHeight()
  414. .padding(bottom = 0.dp)
  415. .alpha(if (isDarkTheme.value) 0.1F else 0.6F),
  416. // .alpha(0.6F),
  417. painter = painterResource(id = R.drawable.map_home3x),
  418. contentDescription = "Home Map",
  419. contentScale = ContentScale.FillWidth,
  420. )
  421. Column(
  422. modifier = Modifier
  423. .fillMaxWidth()
  424. .fillMaxHeight()
  425. .padding(bottom = 85.dp)
  426. // .offset(y = -(118).dp)
  427. .background(Color.Transparent),
  428. horizontalAlignment = Alignment.CenterHorizontally,
  429. verticalArrangement = Arrangement.Bottom
  430. ) {
  431. val serverObj = basePreferenceHelper.getConnectedServer()
  432. val serverDis = basePreferenceHelper.getIpinfo()
  433. var ipInfo = homeViewModel.mutableLiveDataIpInfo.observeAsState().value?.query
  434. ipInfo = if (isConnect == App.CONNECTED) serverObj?.ip.toString() else serverDis?.query
  435. AddText(
  436. text = "IP ${ipInfo ?: ""}",
  437. size = 18.sp,
  438. // color = MaterialTheme.colorScheme.primary,
  439. color = MaterialTheme.colorScheme.primary,
  440. style = MaterialTheme.typography.customTypography.headlineLarge.copy(
  441. fontSize = 18.sp
  442. )
  443. )
  444. Row(
  445. verticalAlignment = Alignment.CenterVertically,
  446. modifier = Modifier
  447. .background(Color.Transparent)
  448. .padding(top = 5.dp)
  449. ) {
  450. if (isConnect == App.CONNECTED) {
  451. val image = Utils.getDrawable(context, serverObj?.iso)
  452. if (image != 0) {
  453. Image(
  454. painter = painterResource(id = image),
  455. contentDescription = "Country",
  456. modifier = Modifier
  457. .padding(end = 6.dp)
  458. .size(15.dp)
  459. .clip(CircleShape)
  460. .paint(
  461. painter = painterResource(id = image),
  462. contentScale = ContentScale.FillBounds
  463. )
  464. )
  465. }
  466. AddText(
  467. text = "${serverObj?.server_name ?: ""}, ${serverObj?.country ?: ""}",
  468. size = 16.sp,
  469. color = MaterialTheme.colorScheme.primary,
  470. isTablet()
  471. )
  472. } else {
  473. val image = Utils.getDrawable(context, serverDis?.countryCode)
  474. Log.d("image_logo", "$image ${serverDis?.countryCode}")
  475. if (image != 0) {
  476. Image(
  477. painter = painterResource(id = image),
  478. contentDescription = "Server",
  479. modifier = Modifier
  480. .padding(end = 6.dp)
  481. .size(15.dp)
  482. .clip(CircleShape)
  483. .paint(
  484. painter = painterResource(id = image),
  485. contentScale = ContentScale.FillBounds
  486. )
  487. )
  488. }
  489. AddText(
  490. text = "${serverDis?.city ?: ""}, ${serverDis?.country ?: ""}",
  491. size = 16.sp,
  492. color = MaterialTheme.colorScheme.primary,
  493. isTablet()
  494. )
  495. }
  496. }
  497. when (isConnect) {
  498. App.CONNECTED -> {
  499. AddText(
  500. text = "Connected",
  501. size = 18.sp,
  502. color = MaterialTheme.colorScheme.surfaceContainerHigh,
  503. // color = colorResource(id = R.color.light_blue_2),
  504. style = MaterialTheme.typography.customTypography.displaySmall.copy(
  505. fontSize = 18.sp
  506. )
  507. )
  508. }
  509. App.DISCONNECTED -> {
  510. AddText(
  511. text = "Disconnected",
  512. size = 18.sp,
  513. color = MaterialTheme.colorScheme.surfaceTint,
  514. // color = colorResource(id = R.color.maroon_text),
  515. style = MaterialTheme.typography.customTypography.displaySmall.copy(
  516. fontSize = 18.sp
  517. )
  518. )
  519. }
  520. App.CONNECTING -> {
  521. AddText(
  522. text = "Connecting...",
  523. size = 18.sp,
  524. color = MaterialTheme.colorScheme.surfaceTint,
  525. // color = colorResource(id = R.color.maroon_text),
  526. style = MaterialTheme.typography.customTypography.displaySmall.copy(
  527. fontSize = 18.sp
  528. )
  529. )
  530. }
  531. }
  532. }
  533. }
  534. Box(
  535. modifier = Modifier
  536. .constrainAs(secondComposable) {
  537. top.linkTo(guideline)
  538. bottom.linkTo(firstComposable.bottom)
  539. start.linkTo(parent.start)
  540. end.linkTo(parent.end)
  541. width = Dimension.value(150.dp)
  542. height = Dimension.value(150.dp)
  543. }
  544. .background(Color.Transparent)
  545. ) {
  546. val color = if (isButtonFocused && isConnect == App.CONNECTED) colorResource(id = R.color.dark_blue_gray_text)
  547. else if (isButtonFocused) colorResource(id = R.color.maroon_text)
  548. else colorResource(id = R.color.transparent)
  549. IconButton(
  550. onClick = {},
  551. modifier = Modifier
  552. .padding(bottom = 0.dp)
  553. .size(150.dp)
  554. .onKeyEvent {
  555. when (it.key) {
  556. Key.DirectionDown -> {
  557. Log.d("test_settings_keys", "DirectionDown")
  558. if (it.type == KeyEventType.KeyDown) {
  559. focusRequester2.requestFocus()
  560. }
  561. true
  562. }
  563. else -> {
  564. true
  565. }
  566. }
  567. }
  568. .focusRequester(focusRequester1)
  569. .background(Color.Transparent)
  570. .onFocusChanged {
  571. isButtonFocused = it.isFocused
  572. }
  573. .clickable {
  574. val connectedServer = basePreferenceHelper.getConnectedServer()
  575. val serverObject = basePreferenceHelper.getServerObject()
  576. prefHelper.getProduct()?.identifier.let {
  577. val identifier = it
  578. if (identifier == AppEnum.FREE.key) {
  579. } else {
  580. Log.d("isConnect_State_vpn", "else connect button $isConnect")
  581. prefHelper
  582. .getServerObject()
  583. ?.let {
  584. Log.d(
  585. "isConnect_State_vpn",
  586. "getServerObject ${it.server_name}"
  587. )
  588. prefHelper.setConnectedServer(it)
  589. }
  590. if (isConnect == App.CONNECTED || isConnect == App.CONNECTING) {
  591. Log.d("isConnect_State_vpn", "stopVPN")
  592. vpnConnectionsUtil.stopVpn()
  593. homeViewModel.getIp()
  594. } else {
  595. Log.d("isConnect_State_vpn", "Disconnected")
  596. if (basePreferenceHelper.getServerObject() != null) {
  597. Log.d("isConnect_State_vpn", "startVpn")
  598. vpnConnectionsUtil.startVpn()
  599. } else {
  600. Log.d("isConnect_State_vpn", "else ServerListTV")
  601. toChangeServer.value = false
  602. navHostController.navigate(
  603. ScreenTV.ServerListTV.route
  604. )
  605. }
  606. }
  607. }
  608. }
  609. }
  610. .focusable(),
  611. )
  612. {
  613. if (isConnect == App.CONNECTED) {
  614. Image(
  615. painter = if (isDarkTheme.value) painterResource(id = R.drawable.iv_connect_dark2)
  616. else painterResource(id = R.drawable.iv_connect),
  617. // painter = painterResource(id = R.drawable.iv_connect),
  618. contentDescription = "iv_connect",
  619. contentScale = ContentScale.FillBounds,
  620. modifier = Modifier
  621. .size(150.dp)
  622. .border(
  623. BorderStroke(
  624. 2.dp, color
  625. ), shape = CircleShape
  626. )
  627. )
  628. }
  629. else {
  630. Image(
  631. painter = if (isDarkTheme.value) painterResource(id = R.drawable.iv_disconnect_dark)
  632. else painterResource(id = R.drawable.iv_disconnect),
  633. // painter = painterResource(id = R.drawable.iv_disconnect),
  634. contentDescription = "iv_disconnect",
  635. contentScale = ContentScale.FillBounds,
  636. modifier = Modifier
  637. .size(150.dp)
  638. .border(
  639. BorderStroke(
  640. 2.dp, color
  641. ), shape = CircleShape
  642. )
  643. )
  644. }
  645. }
  646. }
  647. }
  648. // 2nd box
  649. Box(
  650. modifier = Modifier
  651. .background(MaterialTheme.colorScheme.background)
  652. .fillMaxSize()
  653. .weight(0.4f)
  654. // .background(Color.Transparent),
  655. ) {
  656. Column(
  657. modifier = Modifier.fillMaxSize(),
  658. verticalArrangement = Arrangement.Center
  659. )
  660. {
  661. if (isConnect != App.CONNECTED) {
  662. Box(
  663. modifier = Modifier
  664. .fillMaxWidth(fraction = 0.4f)
  665. .padding(horizontal = 0.dp)
  666. .padding(vertical = 2.dp)
  667. .height(90.dp)
  668. .border(
  669. border = BorderStroke(2.dp, MaterialTheme.colorScheme.onBackground),
  670. shape = RoundedCornerShape(28.dp)
  671. )
  672. .background(
  673. shape = RoundedCornerShape(28.dp),
  674. color = MaterialTheme.colorScheme.onBackground
  675. )
  676. .align(Alignment.CenterHorizontally),
  677. ) {
  678. AddRowSmartTV(
  679. navHostController,
  680. basePreferenceHelper,
  681. context,
  682. isTablet(),
  683. focusRequester2,
  684. homeViewModel
  685. )
  686. var smartServer = basePreferenceHelper.getSmartServerObject()
  687. val recommended = basePreferenceHelper.getRecommendedServerObject()
  688. val selectedSmartList = basePreferenceHelper.getSmartList()
  689. var isSmartButtonFocused by remember { mutableStateOf(false) }
  690. when(selectedSmartList) {
  691. smartConnect[0] -> {
  692. smartServer = basePreferenceHelper.getRecommendedServerObject()
  693. }
  694. smartConnect[1] -> {
  695. smartServer = basePreferenceHelper.getSmartServerObject() ?: recommended
  696. }
  697. smartConnect[2] -> {
  698. smartServer = basePreferenceHelper.getSmartServerObject() ?: recommended
  699. }
  700. else -> {}
  701. }
  702. val color = if (isSmartButtonFocused && isConnect == App.CONNECTED) MaterialTheme.colorScheme.primary
  703. else if (isSmartButtonFocused) MaterialTheme.colorScheme.primary
  704. else colorResource(id = R.color.blue_text)
  705. Button(
  706. onClick = {},
  707. modifier = Modifier
  708. .padding(start = 14.dp, end = 14.dp, bottom = 6.dp, top = 12.dp)
  709. .align(Alignment.BottomCenter)
  710. .background(
  711. MaterialTheme.colorScheme.onBackground,
  712. RoundedCornerShape(16.dp)
  713. )
  714. .border(2.dp, color, RoundedCornerShape(16.dp))
  715. .onFocusChanged {
  716. isSmartButtonFocused = it.isFocused
  717. }
  718. .onKeyEvent {
  719. when (it.key) {
  720. Key.DirectionLeft -> { true }
  721. Key.DirectionRight -> { true }
  722. else -> false
  723. }
  724. }
  725. // .focusable()
  726. .clickable {
  727. Log.d(
  728. "test_button",
  729. "onClick Smart Connect ${smartServer?.server_name}"
  730. )
  731. basePreferenceHelper.setSmartServerObject(smartServer)
  732. if (isConnect == App.CONNECTED) {
  733. Log.d("isConnect_State_vpn", "stopVPN")
  734. val lastServer = basePreferenceHelper.getConnectedServer()
  735. Log.d(
  736. "test_conn_ser_obj",
  737. "smart => ${lastServer?.server_name} ${smartServer?.server_name}"
  738. )
  739. if (lastServer?.id != smartServer?.id) {
  740. isServerDialog.value = true
  741. if (smartServer != null) {
  742. serverObj.value = smartServer
  743. }
  744. } else {
  745. vpnConnectionsUtil.stopVpn()
  746. }
  747. // vpnConnectionsUtil.stopVpn()
  748. // Handler().postDelayed(Runnable {
  749. // vpnConnectionsUtil.startVpn()
  750. // }, 500)
  751. // homeViewModel.getIp()
  752. } else if (isConnect == App.CONNECTING) {
  753. vpnConnectionsUtil.stopVpn()
  754. } else if (isConnect == App.DISCONNECTED) {
  755. Log.d("isConnect_State_vpn", "startVPN")
  756. basePreferenceHelper.setConnectedServer(smartServer)
  757. if (smartServer != null) {
  758. serverListViewModelSplash.setRecentlyConnectedServer(
  759. smartServer
  760. )
  761. }
  762. vpnConnectionsUtil.startVpn()
  763. }
  764. }
  765. .fillMaxWidth()
  766. .height(35.dp),
  767. shape = RoundedCornerShape(16.dp),
  768. colors = ButtonDefaults.buttonColors(
  769. contentColor = colorResource(id = R.color.white),
  770. containerColor = colorResource(id = R.color.blue_text),
  771. ),
  772. ) {
  773. Text(
  774. text = "Smart Connect",
  775. style = MaterialTheme.typography.customTypography.labelLarge.copy(
  776. fontSize = 16.sp, lineHeight = 0.sp
  777. ),
  778. modifier = Modifier.background(Color.Transparent)
  779. )
  780. }
  781. }
  782. /* Select Server Box*/
  783. // if (isConnect != App.CONNECTED) { }
  784. // Spacer(modifier = Modifier.weight(1f))
  785. var isLayoutFocused by remember { mutableStateOf(false) }
  786. val color = if (isLayoutFocused && isConnect == App.CONNECTED) MaterialTheme.colorScheme.primary
  787. else if (isLayoutFocused) MaterialTheme.colorScheme.primary
  788. else MaterialTheme.colorScheme.onBackground
  789. Box(
  790. modifier = Modifier
  791. .fillMaxWidth(fraction = 0.4f)
  792. .padding(horizontal = 0.dp, vertical = 2.dp)
  793. .padding(top = 10.dp)
  794. .height(50.dp)
  795. .onKeyEvent {
  796. if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
  797. isFirstItemPressed.value = true
  798. true
  799. } else {
  800. false
  801. }
  802. }
  803. .onFocusChanged {
  804. isLayoutFocused = it.isFocused
  805. }
  806. .focusable()
  807. .clickable(
  808. indication = null,
  809. interactionSource = remember { MutableInteractionSource() }
  810. ) {
  811. toChangeServer.value = false
  812. navHostController.navigate(
  813. ScreenTV.ServerListTV.route
  814. )
  815. }
  816. .border(
  817. border = BorderStroke(2.dp, color),
  818. shape = RoundedCornerShape(28.dp)
  819. )
  820. .background(
  821. shape = RoundedCornerShape(28.dp),
  822. color = MaterialTheme.colorScheme.onBackground
  823. )
  824. .align(Alignment.CenterHorizontally),
  825. contentAlignment = Alignment.CenterStart,
  826. ) {
  827. AddRowSelectServerTV(navHostController, isTablet())
  828. }
  829. }
  830. else {
  831. var isFeedbackClicked by remember { mutableStateOf(prefHelper.getFeedbackState()) }
  832. var isDelayedFeedbackClicked by remember { mutableStateOf(isFeedbackClicked) }
  833. var isThumbUpClicked by remember { mutableStateOf(App.isThumbUpClicked) }
  834. var isThumbDownClicked by remember { mutableStateOf(App.isThumbDownClicked) }
  835. var isRipple = false
  836. var isThumbUpFocused by remember { mutableStateOf(false) }
  837. var isThumbDownFocused by remember { mutableStateOf(false) }
  838. Box(
  839. modifier = Modifier
  840. .fillMaxWidth(fraction = 0.4f)
  841. .padding(horizontal = 0.dp)
  842. .padding(vertical = 5.dp)
  843. .height(90.dp)
  844. .align(Alignment.CenterHorizontally)
  845. // .border(
  846. // border = BorderStroke(0.dp, Color.Blue),
  847. // shape = RoundedCornerShape(28.dp)
  848. // )
  849. .background(
  850. color = Color.Transparent
  851. ),
  852. ) {
  853. Row(
  854. modifier = Modifier
  855. .padding(0.dp)
  856. .background(Color.Transparent),
  857. horizontalArrangement = Arrangement.SpaceAround,
  858. verticalAlignment = Alignment.CenterVertically
  859. ) {
  860. Surface(
  861. modifier = Modifier
  862. .weight(1f)
  863. .fillMaxHeight()
  864. .padding(end = 5.dp)
  865. .border(
  866. width = 1.dp,
  867. color = MaterialTheme.colorScheme.onBackground,
  868. shape = RoundedCornerShape(24.dp)
  869. )
  870. .background(Color.Transparent),
  871. shape = RoundedCornerShape(24.dp)
  872. ) {
  873. Column(
  874. modifier = Modifier
  875. .background(MaterialTheme.colorScheme.onBackground)
  876. .border(
  877. width = 1.dp,
  878. color = MaterialTheme.colorScheme.onBackground,
  879. shape = RoundedCornerShape(24.dp)
  880. ),
  881. verticalArrangement = Arrangement.SpaceEvenly,
  882. horizontalAlignment = Alignment.CenterHorizontally,
  883. ) {
  884. Image(
  885. painter = painterResource(id = R.drawable.greenarrow3x),
  886. contentDescription = "Green Arrow",
  887. modifier = Modifier
  888. .size(30.dp)
  889. )
  890. Text(
  891. text = "Download",
  892. style = MaterialTheme.typography.customTypography.displayMedium.copy(
  893. color = MaterialTheme.colorScheme.onTertiary
  894. ),
  895. modifier = Modifier.alpha(0.6F)
  896. )
  897. Row(
  898. horizontalArrangement = Arrangement.SpaceAround,
  899. verticalAlignment = Alignment.CenterVertically
  900. ) {
  901. Text(
  902. text = String.format(Locale.US, "%.2f", StringDown.value),
  903. style = MaterialTheme.typography.customTypography.displayLarge.copy(
  904. color = MaterialTheme.colorScheme.primary
  905. )
  906. )
  907. Text(
  908. text = " ${StringDownUnit.value}",
  909. style = MaterialTheme.typography.customTypography2.labelSmall.copy(
  910. color = MaterialTheme.colorScheme.primary
  911. ),
  912. modifier = Modifier.alpha(0.5F)
  913. )
  914. }
  915. }
  916. }
  917. Surface(
  918. modifier = Modifier
  919. .weight(1f)
  920. .fillMaxHeight()
  921. .padding(start = 5.dp)
  922. .border(
  923. width = 1.dp,
  924. color = MaterialTheme.colorScheme.onBackground,
  925. shape = RoundedCornerShape(24.dp)
  926. )
  927. .background(Color.Transparent),
  928. shape = RoundedCornerShape(24.dp)
  929. ) {
  930. Column(
  931. modifier = Modifier
  932. .background(MaterialTheme.colorScheme.onBackground)
  933. .border(
  934. width = 1.dp,
  935. color = MaterialTheme.colorScheme.onBackground,
  936. shape = RoundedCornerShape(24.dp)
  937. ),
  938. verticalArrangement = Arrangement.SpaceEvenly,
  939. horizontalAlignment = Alignment.CenterHorizontally
  940. ) {
  941. Image(
  942. painter = painterResource(id = R.drawable.yellowarrow3x),
  943. contentDescription = "Yellow Arrow",
  944. modifier = Modifier
  945. .size(30.dp)
  946. )
  947. Text(
  948. text = "Upload",
  949. style = MaterialTheme.typography.customTypography.displayMedium.copy(
  950. color = MaterialTheme.colorScheme.onTertiary
  951. ),
  952. modifier = Modifier.alpha(0.6F)
  953. )
  954. Row(
  955. horizontalArrangement = Arrangement.SpaceAround,
  956. verticalAlignment = Alignment.CenterVertically
  957. ) {
  958. Text(
  959. text = String.format(Locale.US,"%.2f", StringUp.value),
  960. style = MaterialTheme.typography.customTypography.displayLarge.copy(
  961. color = MaterialTheme.colorScheme.primary
  962. )
  963. )
  964. Text(
  965. text = " ${StringUpUnit.value}",
  966. style = MaterialTheme.typography.customTypography2.labelSmall.copy(
  967. color = MaterialTheme.colorScheme.primary
  968. ),
  969. modifier = Modifier.alpha(0.5F)
  970. )
  971. }
  972. }
  973. }
  974. }
  975. }
  976. LaunchedEffect(key1 = isFeedbackClicked) {
  977. if (isFeedbackClicked) {
  978. delay(150)
  979. isDelayedFeedbackClicked = true
  980. }
  981. }
  982. val backgroundColor by animateColorAsState(
  983. targetValue = if (isDelayedFeedbackClicked) colorResource(id = R.color.yellow_feedback)
  984. else MaterialTheme.colorScheme.outlineVariant, label = "Color"
  985. )
  986. Box(
  987. modifier = Modifier
  988. .padding(top = 10.dp)
  989. .padding(vertical = 5.dp)
  990. .fillMaxWidth(fraction = 0.4f)
  991. .height(55.dp)
  992. .background(
  993. backgroundColor,
  994. shape = RoundedCornerShape(12.dp)
  995. )
  996. .border(
  997. width = 1.dp,
  998. color = Color.Transparent,
  999. shape = RoundedCornerShape(12.dp)
  1000. )
  1001. .align(Alignment.CenterHorizontally)
  1002. ) {
  1003. Row(
  1004. modifier = Modifier
  1005. .fillMaxSize()
  1006. .padding(16.dp),
  1007. horizontalArrangement = Arrangement.SpaceBetween,
  1008. verticalAlignment = Alignment.CenterVertically
  1009. ) {
  1010. Text(
  1011. text = "How's your connection?",
  1012. style = MaterialTheme.typography.customTypography.titleSmall.copy(
  1013. color = Color.White
  1014. )
  1015. )
  1016. Row(
  1017. modifier = Modifier
  1018. .background(Color.Transparent),
  1019. horizontalArrangement = Arrangement.Center,
  1020. verticalAlignment = Alignment.CenterVertically
  1021. ) {
  1022. Image(
  1023. imageVector = Icons.Outlined.ThumbUp,
  1024. contentDescription = "Thumb Up",
  1025. modifier = Modifier
  1026. .padding(end = 25.dp)
  1027. .size(24.dp)
  1028. .focusRequester(focusRequester2)
  1029. .onKeyEvent {
  1030. if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
  1031. isFirstItemPressed.value = true
  1032. true
  1033. }
  1034. else if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionLeft) {
  1035. true
  1036. }
  1037. else {
  1038. false
  1039. }
  1040. }
  1041. .onFocusChanged {
  1042. isThumbUpFocused = it.isFocused
  1043. }
  1044. .focusable()
  1045. .clickable(
  1046. indication = rememberRipple(
  1047. bounded = true,
  1048. color = colorResource(id = R.color.switch_green)
  1049. ),
  1050. interactionSource = remember { MutableInteractionSource() }
  1051. ) {
  1052. val connectedServer =
  1053. basePreferenceHelper.getConnectedServer()
  1054. val selectedProtocol =
  1055. basePreferenceHelper.getProtocol().full_name
  1056. if (!isFeedbackClicked) {
  1057. isFeedbackClicked = true
  1058. prefHelper.setFeedbackState(true)
  1059. isThumbUpClicked = true
  1060. App.isThumbUpClicked = true
  1061. isRipple = true
  1062. homeViewModel.feedback(
  1063. rating = 1,
  1064. server_id = connectedServer?.id,
  1065. server_ip = connectedServer?.ip.toString(),
  1066. protocol = selectedProtocol
  1067. )
  1068. }
  1069. }
  1070. ,
  1071. colorFilter = ColorFilter.tint(
  1072. if (isThumbUpFocused) colorResource(id = R.color.dark_blue_gray_text)
  1073. else if (isFeedbackClicked && isThumbUpClicked) colorResource(id = R.color.switch_green)
  1074. else colorResource(id = R.color.white)
  1075. )
  1076. )
  1077. Image(
  1078. imageVector = Icons.Outlined.ThumbDown,
  1079. contentDescription = "Thumb Down",
  1080. modifier = Modifier
  1081. .padding(end = 10.dp)
  1082. .size(24.dp)
  1083. .onFocusChanged {
  1084. isThumbDownFocused = it.isFocused
  1085. }
  1086. .onKeyEvent {
  1087. if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
  1088. isFirstItemPressed.value = true
  1089. true
  1090. }
  1091. else if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionRight) {
  1092. true
  1093. }
  1094. else {
  1095. false
  1096. }
  1097. }
  1098. .focusable()
  1099. .clickable(
  1100. indication = rememberRipple(
  1101. bounded = true,
  1102. color = colorResource(id = R.color.Red)
  1103. ),
  1104. interactionSource = remember { MutableInteractionSource() }
  1105. ) {
  1106. val connectedServer =
  1107. basePreferenceHelper.getConnectedServer()
  1108. val selectedProtocol =
  1109. basePreferenceHelper.getProtocol().full_name
  1110. if (!isFeedbackClicked) {
  1111. isFeedbackClicked = true
  1112. prefHelper.setFeedbackState(true)
  1113. isThumbDownClicked = true
  1114. App.isThumbDownClicked = true
  1115. homeViewModel.feedback(
  1116. rating = 0,
  1117. server_id = connectedServer?.id,
  1118. server_ip = connectedServer?.ip.toString(),
  1119. protocol = selectedProtocol
  1120. )
  1121. }
  1122. },
  1123. colorFilter = ColorFilter.tint(
  1124. if (isThumbDownFocused) colorResource(id = R.color.dark_blue_gray_text)
  1125. else if (isFeedbackClicked && isThumbDownClicked) colorResource(id = R.color.Red)
  1126. else colorResource(id = R.color.white)
  1127. )
  1128. )
  1129. }
  1130. }
  1131. }
  1132. }
  1133. }
  1134. }
  1135. }
  1136. }
  1137. @OptIn(ExperimentalMaterial3Api::class)
  1138. @Composable
  1139. fun ColumnScope.ShowProtocolDialogTV(
  1140. prefHelper: BasePreferenceHelper,
  1141. wg: VPNConnectionsUtil,
  1142. serverListViewModel: ServerListViewModel
  1143. ) {
  1144. var isButtonFocused1 by remember { mutableStateOf(false) }
  1145. var isButtonFocused2 by remember { mutableStateOf(false) }
  1146. AlertDialog(
  1147. onDismissRequest = { isProtocolDialog.value = false },
  1148. properties = DialogProperties(),
  1149. modifier = Modifier
  1150. .fillMaxWidth()
  1151. .wrapContentHeight()
  1152. ) {
  1153. val lastServer = prefHelper.getConnectedServer()
  1154. val selectedProtocol = prefHelper.getProtocol()
  1155. val oldProtocolTitle = if (selectedProtocol.index == 0) AppEnum.AUTO_PROTOCOL.key else selectedProtocol.title
  1156. val newProtocolTitle = if (protocolObj.value.index == 0) AppEnum.AUTO_PROTOCOL.key else protocolObj.value.title
  1157. val serverList = prefHelper.getServerData()
  1158. // val serverList = serverListViewModelSplash.liveDataGetServersGlobal.value
  1159. var desiredServer = Server()
  1160. var isServerFound: Boolean = false
  1161. if (lastServer != null) {
  1162. val serverProtocol = serverListViewModel.getFilteredServerByProtocolChanged(serverList, lastServer,
  1163. protocolObj.value)
  1164. if (serverProtocol.isFound) {
  1165. desiredServer = serverProtocol.server
  1166. isServerFound = true
  1167. }
  1168. }
  1169. // serverListViewModelSplash.setCountryData()
  1170. // Log.d("server_protocol", "Home: $isServerFound ${desiredServer.id} ${desiredServer.server_name} ${desiredServer.ip} ${desiredServer.protocol} ${desiredServer.remoteId}")
  1171. Surface(
  1172. color = colorResource(id = R.color.white),
  1173. modifier = Modifier
  1174. .background(Color.Transparent)
  1175. .fillMaxWidth()
  1176. ,
  1177. shape = RoundedCornerShape(18.dp)
  1178. ) {
  1179. Column(
  1180. verticalArrangement = Arrangement.Top,
  1181. horizontalAlignment = Alignment.CenterHorizontally,
  1182. modifier = Modifier
  1183. .background(colorResource(id = R.color.white))
  1184. ) {
  1185. Log.d("islogoutClicked", "AlertDialog")
  1186. Text(text = "Confirm",
  1187. color = colorResource(id = R.color.dark_blue_gray_text),
  1188. style = MaterialTheme.typography.bodyMedium,
  1189. modifier = Modifier.padding(top = 45.dp)
  1190. )
  1191. Text(text = "Are you sure to switch from $oldProtocolTitle to $newProtocolTitle?",
  1192. color = colorResource(id = R.color.dark_blue_gray_text),
  1193. style = MaterialTheme.typography.labelSmall,
  1194. maxLines = 2,
  1195. modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 26.dp)
  1196. )
  1197. Row (
  1198. modifier = Modifier
  1199. .padding(top = 34.dp, bottom = 20.dp),
  1200. horizontalArrangement = Arrangement.SpaceBetween,
  1201. verticalAlignment = Alignment.Bottom
  1202. ) {
  1203. Button(
  1204. onClick = {
  1205. Log.d("ServerCallbacks", "No")
  1206. isProtocolDialog.value = false
  1207. },
  1208. modifier = Modifier
  1209. .padding(
  1210. start = 15.dp, end = 5.dp,
  1211. bottom = 0.dp, top = 0.dp
  1212. )
  1213. .onFocusChanged {
  1214. isButtonFocused1 = it.isFocused
  1215. }
  1216. .background(colorResource(id = R.color.transparent))
  1217. .weight(1F)
  1218. .height(52.dp),
  1219. shape = RoundedCornerShape(15.dp),
  1220. colors = ButtonDefaults.buttonColors(
  1221. contentColor = if (isButtonFocused1) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.white),
  1222. containerColor = colorResource(id = R.color.light_blue),
  1223. ),
  1224. border = BorderStroke(2.dp, if (isButtonFocused1) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.light_blue))
  1225. )
  1226. {
  1227. Text(text = "No",
  1228. style = MaterialTheme.typography.labelLarge)
  1229. Log.d("test_button", "RowScope")
  1230. }
  1231. Button(
  1232. onClick = {
  1233. Log.d("ServerCallbacks", "Yes")
  1234. val server = if (isServerFound) desiredServer else prefHelper.getConnectedServer()
  1235. prefHelper.setServerObject(server)
  1236. prefHelper.setConnectedServer(server)
  1237. prefHelper.saveProtocol(protocol = protocolObj.value)
  1238. wg.stopVpn()
  1239. Handler().postDelayed(Runnable {
  1240. wg.startVpn()
  1241. }, 500)
  1242. Log.d("ServerCallbacks", "Yes click => ${isProtocolDialog.value}")
  1243. isProtocolDialog.value = false
  1244. serverListViewModelSplash.setCountryDataTV()
  1245. },
  1246. modifier = Modifier
  1247. .padding(
  1248. start = 5.dp, end = 15.dp,
  1249. bottom = 0.dp, top = 0.dp
  1250. )
  1251. .onFocusChanged {
  1252. isButtonFocused2 = it.isFocused
  1253. }
  1254. .background(colorResource(id = R.color.transparent))
  1255. .weight(1F)
  1256. .height(52.dp),
  1257. shape = RoundedCornerShape(15.dp),
  1258. colors = ButtonDefaults.buttonColors(
  1259. contentColor = if (isButtonFocused2) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.white),
  1260. containerColor = colorResource(id = R.color.red),
  1261. ),
  1262. border = BorderStroke(2.dp, if (isButtonFocused2) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.red))
  1263. // border = BorderStroke(2.dp,
  1264. // colorResource(id = R.color.gray_icon))
  1265. )
  1266. {
  1267. Text(text = "Yes",
  1268. style = MaterialTheme.typography.labelLarge)
  1269. Log.d("test_button", "RowScope")
  1270. // val logoutResponse = accountViewModel.liveDataLogout.observeAsState().value
  1271. // if (logoutResponse == true) {
  1272. // accountViewModel.setLogoutStatus(false)
  1273. // Log.d("test_api_response","Logout live: $logoutResponse")
  1274. // basePreferenceHelper.setLoggedInState(false)
  1275. // settingsNavHostController.popBackStack()
  1276. // settingsNavHostController.navigate(Screen.Started.route)
  1277. // }
  1278. // else {
  1279. //// accountViewModel.setLogoutStatus(false)
  1280. //// onCancel()
  1281. // }
  1282. }
  1283. }
  1284. }
  1285. }
  1286. }
  1287. }
  1288. @OptIn(ExperimentalMaterial3Api::class)
  1289. @Composable
  1290. fun ColumnScope.ShowServerDialogTV(
  1291. prefHelper: BasePreferenceHelper,
  1292. wg: VPNConnectionsUtil
  1293. ) {
  1294. var isButtonFocused1 by remember { mutableStateOf(false) }
  1295. var isButtonFocused2 by remember { mutableStateOf(false) }
  1296. AlertDialog(
  1297. onDismissRequest = { isServerDialog.value = false },
  1298. properties = DialogProperties(),
  1299. modifier = Modifier
  1300. .fillMaxWidth()
  1301. .wrapContentHeight()
  1302. ) {
  1303. val lastServer = prefHelper.getConnectedServer()
  1304. val context = LocalContext.current
  1305. // val serverListViewModel: ServerListViewModel = viewModel {
  1306. // ServerListViewModel(context)
  1307. // }
  1308. Surface(
  1309. color = colorResource(id = R.color.white),
  1310. modifier = Modifier
  1311. .background(Color.Transparent)
  1312. .fillMaxWidth()
  1313. ,
  1314. shape = RoundedCornerShape(18.dp)
  1315. ) {
  1316. Column(
  1317. verticalArrangement = Arrangement.Top,
  1318. horizontalAlignment = Alignment.CenterHorizontally,
  1319. modifier = Modifier
  1320. .background(colorResource(id = R.color.white))
  1321. ) {
  1322. Log.d("islogoutClicked", "AlertDialog")
  1323. Text(text = "Confirm",
  1324. color = colorResource(id = R.color.dark_blue_gray_text),
  1325. style = MaterialTheme.typography.bodyMedium,
  1326. modifier = Modifier.padding(top = 45.dp)
  1327. )
  1328. Text(text = "Are you sure to switch from ${lastServer?.server_name} to ${serverObj.value.server_name}?",
  1329. color = colorResource(id = R.color.dark_blue_gray_text),
  1330. style = MaterialTheme.typography.labelSmall,
  1331. maxLines = 2,
  1332. modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 26.dp)
  1333. )
  1334. Row (
  1335. modifier = Modifier
  1336. .padding(top = 34.dp, bottom = 20.dp),
  1337. horizontalArrangement = Arrangement.SpaceBetween,
  1338. verticalAlignment = Alignment.Bottom
  1339. ) {
  1340. Button(
  1341. onClick = {
  1342. Log.d("test_button", "No")
  1343. isServerDialog.value = false
  1344. },
  1345. modifier = Modifier
  1346. .padding(
  1347. start = 15.dp, end = 5.dp,
  1348. bottom = 0.dp, top = 0.dp
  1349. )
  1350. .onFocusChanged {
  1351. isButtonFocused1 = it.isFocused
  1352. }
  1353. .background(colorResource(id = R.color.transparent))
  1354. .weight(1F)
  1355. .height(52.dp),
  1356. shape = RoundedCornerShape(15.dp),
  1357. colors = ButtonDefaults.buttonColors(
  1358. contentColor = if (isButtonFocused1) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.white),
  1359. containerColor = colorResource(id = R.color.light_blue),
  1360. ),
  1361. border = BorderStroke(2.dp, if (isButtonFocused1) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.light_blue))
  1362. )
  1363. {
  1364. Text(text = "No",
  1365. style = MaterialTheme.typography.labelLarge)
  1366. Log.d("test_button", "RowScope")
  1367. }
  1368. Button(
  1369. onClick = {
  1370. Log.d("test_button", "Yes")
  1371. isServerDialog.value = false
  1372. prefHelper.setServerObject(serverObj.value)
  1373. prefHelper.setConnectedServer(serverObj.value)
  1374. serverListViewModelSplash.setRecentlyConnectedServer(serverObj.value)
  1375. wg.stopVpn()
  1376. Handler().postDelayed(Runnable {
  1377. wg.startVpn()
  1378. }, 500)
  1379. Log.d("ServerCallbacks", "Yes click => ${isServerDialog.value}")
  1380. },
  1381. modifier = Modifier
  1382. .padding(
  1383. start = 5.dp, end = 15.dp,
  1384. bottom = 0.dp, top = 0.dp
  1385. )
  1386. .onFocusChanged {
  1387. isButtonFocused2 = it.isFocused
  1388. }
  1389. .background(colorResource(id = R.color.transparent))
  1390. .weight(1F)
  1391. .height(52.dp),
  1392. shape = RoundedCornerShape(15.dp),
  1393. colors = ButtonDefaults.buttonColors(
  1394. contentColor = if (isButtonFocused2) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.white),
  1395. containerColor = colorResource(id = R.color.red),
  1396. ),
  1397. border = BorderStroke(2.dp, if (isButtonFocused2) colorResource(id = R.color.dark_blue_gray_text) else colorResource(id = R.color.red))
  1398. )
  1399. {
  1400. Text(text = "Yes",
  1401. style = MaterialTheme.typography.labelLarge)
  1402. Log.d("test_button", "RowScope")
  1403. // val logoutResponse = accountViewModel.liveDataLogout.observeAsState().value
  1404. // if (logoutResponse == true) {
  1405. // accountViewModel.setLogoutStatus(false)
  1406. // Log.d("test_api_response","Logout live: $logoutResponse")
  1407. // basePreferenceHelper.setLoggedInState(false)
  1408. // settingsNavHostController.popBackStack()
  1409. // settingsNavHostController.navigate(Screen.Started.route)
  1410. // }
  1411. // else {
  1412. //// accountViewModel.setLogoutStatus(false)
  1413. //// onCancel()
  1414. // }
  1415. }
  1416. }
  1417. }
  1418. }
  1419. }
  1420. }
  1421. @Composable
  1422. fun BoxScope.AddRowSmartTV(
  1423. navHostController: NavHostController,
  1424. basePreferenceHelper: BasePreferenceHelper,
  1425. context: Context,
  1426. isTablet: Boolean,
  1427. focusRequester2: FocusRequester,
  1428. homeViewModel: HomeViewModel
  1429. ) {
  1430. val smart = basePreferenceHelper.getSmartServerObject()
  1431. val recommended = basePreferenceHelper.getRecommendedServerObject()
  1432. val recently = basePreferenceHelper.getConnectedServer()
  1433. val anySpecific = basePreferenceHelper.getSmartServerObject()
  1434. val ipInfo = basePreferenceHelper.getIpinfo()
  1435. val selectedSmartList = basePreferenceHelper.getSmartList()
  1436. var selectedServer = basePreferenceHelper.getRecommendedServerObject()
  1437. var selectedSmartServer = basePreferenceHelper.getSmartServerObject()
  1438. var isButtonFocused by remember { mutableStateOf(false) }
  1439. Log.d("smartLocationList", "Home:: server = ${selectedServer?.server_name}")
  1440. var icon = Utils.getDrawable(context, selectedServer?.iso)
  1441. when(selectedSmartList) {
  1442. smartConnect[0] -> {
  1443. icon = Utils.getDrawable(context, recommended?.iso)
  1444. selectedServer = recommended
  1445. selectedSmartServer = recommended
  1446. }
  1447. smartConnect[1] -> {
  1448. icon = Utils.getDrawable(context, recently?.iso ?: recommended?.iso)
  1449. selectedServer = recently ?: recommended
  1450. selectedSmartServer = recently
  1451. }
  1452. smartConnect[2] -> {
  1453. icon = Utils.getDrawable(context, anySpecific?.iso ?: recommended?.iso)
  1454. selectedServer = anySpecific ?: recommended
  1455. selectedSmartServer = anySpecific
  1456. }
  1457. else -> {}
  1458. }
  1459. Row(
  1460. modifier = Modifier
  1461. .fillMaxWidth()
  1462. .padding(horizontal = 15.dp, vertical = 5.dp)
  1463. .background(Color.Transparent),
  1464. horizontalArrangement = Arrangement.Start,
  1465. verticalAlignment = Alignment.CenterVertically
  1466. ) {
  1467. Surface(
  1468. modifier = Modifier.padding(start = 0.dp),
  1469. color = Color.Transparent
  1470. ) {
  1471. if (icon != 0) {
  1472. Icon(
  1473. painter = painterResource(id = icon),
  1474. contentDescription = "Country Logo",
  1475. tint = Color.Unspecified,
  1476. modifier = Modifier
  1477. .padding(start = 0.dp)
  1478. .size(30.dp)
  1479. .weight(1f)
  1480. .clip(CircleShape)
  1481. .border(1.dp, colorResource(id = R.color.gray_opac_04), CircleShape)
  1482. .paint(
  1483. painter = painterResource(id = icon),
  1484. contentScale = ContentScale.FillBounds
  1485. )
  1486. )
  1487. }
  1488. }
  1489. Column(
  1490. modifier = Modifier
  1491. .padding(start = 12.dp)
  1492. ) {
  1493. ColumnText(
  1494. text = selectedSmartList,
  1495. color = MaterialTheme.colorScheme.surfaceContainerLow,
  1496. // color = colorResource(id = R.color.blue_text),
  1497. size = 12.sp,
  1498. style = MaterialTheme.typography.customTypography.headlineSmall.copy(
  1499. fontSize = 16.sp
  1500. )
  1501. )
  1502. ColumnText(
  1503. text = "${selectedServer?.server_name}",
  1504. color = MaterialTheme.colorScheme.primary,
  1505. // color = colorResource(id = R.color.dark_blue_gray_text),
  1506. size = 16.sp,
  1507. style = MaterialTheme.typography.labelMedium.copy(
  1508. fontSize = 16.sp
  1509. )
  1510. )
  1511. }
  1512. Spacer(modifier = Modifier.weight(1F))
  1513. Surface(
  1514. modifier = Modifier
  1515. .padding(start = 15.dp),
  1516. color = Color.Transparent
  1517. ) {
  1518. var isConnect: Int? = homeViewModel.isConnect.observeAsState().value
  1519. isConnect = basePreferenceHelper.getConnectState()
  1520. val color = if (isButtonFocused && isConnect == App.CONNECTED) MaterialTheme.colorScheme.primary
  1521. else if (isButtonFocused) MaterialTheme.colorScheme.primary
  1522. else MaterialTheme.colorScheme.surfaceContainerLow
  1523. ClickableText(
  1524. modifier = Modifier
  1525. .onKeyEvent {
  1526. when (it.key) {
  1527. Key.DirectionLeft -> {
  1528. true
  1529. }
  1530. Key.DirectionRight -> {
  1531. true
  1532. }
  1533. else -> {
  1534. false
  1535. }
  1536. }
  1537. }
  1538. .focusRequester(focusRequester2)
  1539. .onFocusChanged {
  1540. isButtonFocused = it.isFocused
  1541. }
  1542. .clickable {
  1543. toChangeServer.value = true
  1544. navHostController.navigate(
  1545. ScreenTV.ServerListTV.route
  1546. )
  1547. }
  1548. .focusable(),
  1549. text = AnnotatedString("Change"),
  1550. style = MaterialTheme.typography.customTypography.headlineMedium.copy(
  1551. // color = MaterialTheme.colorScheme.surfaceContainerLow,
  1552. color = color,
  1553. fontSize = 18.sp
  1554. ),
  1555. onClick = {},
  1556. )
  1557. }
  1558. }
  1559. }
  1560. @Composable
  1561. fun BoxScope.AddRowSelectServerTV(navHostController: NavHostController, isTablet: Boolean) {
  1562. val context = LocalContext.current
  1563. Row(
  1564. modifier = Modifier
  1565. .fillMaxWidth()
  1566. .padding(horizontal = 15.dp)
  1567. .background(Color.Transparent)
  1568. // .pointerInput(Unit) {
  1569. // detectTapGestures {
  1570. // toChangeServer.value = false
  1571. // navHostController.navigate(
  1572. // Screen.ServerList.route
  1573. // )
  1574. // Screen.ServerList.isTrue = true
  1575. // Log.d("button_click_change", "Pressed")
  1576. // }
  1577. // }
  1578. ,
  1579. horizontalArrangement = Arrangement.Start,
  1580. verticalAlignment = Alignment.CenterVertically
  1581. ) {
  1582. Surface(
  1583. modifier = Modifier.padding(start = 0.dp),
  1584. color = Color.Transparent
  1585. ) {
  1586. Image(
  1587. painter = painterResource(id = R.drawable.worldmap3x),
  1588. contentDescription = "World",
  1589. modifier = Modifier
  1590. .padding(start = 0.dp)
  1591. .size(30.dp)
  1592. .weight(1f)
  1593. )
  1594. }
  1595. Surface(
  1596. modifier = Modifier.padding(start = 0.dp),
  1597. color = Color.Transparent
  1598. ) {
  1599. Text(text = "See All Locations",
  1600. style = MaterialTheme.typography.labelMedium.copy(
  1601. fontSize = if (isTablet()) 20.sp else 16.sp
  1602. ),
  1603. color = MaterialTheme.colorScheme.primary,
  1604. // color = colorResource(id = R.color.dark_blue_gray_text),
  1605. maxLines = 2,
  1606. modifier = Modifier
  1607. .padding(start = 12.dp, end = 0.dp)
  1608. .weight(1f)
  1609. )
  1610. }
  1611. Spacer(modifier = Modifier.weight(1F))
  1612. Surface(
  1613. modifier = Modifier.padding(start = 15.dp),
  1614. color = Color.Transparent
  1615. ) {
  1616. Image(
  1617. painter = painterResource(id = R.drawable.frontarrow3x),
  1618. contentDescription = "Front_Arrow",
  1619. colorFilter = ColorFilter.tint(colorResource(id = R.color.dark_blue_gray_text)),
  1620. modifier = Modifier
  1621. .padding(start = 0.dp, end = 5.dp)
  1622. .size(10.dp, 18.dp)
  1623. .weight(1f)
  1624. )
  1625. }
  1626. }
  1627. }
  1628. @Composable
  1629. fun ColumnScope.AddText(
  1630. text: String,
  1631. size: TextUnit,
  1632. color: Color,
  1633. style: TextStyle
  1634. ) {
  1635. Text(
  1636. text = text,
  1637. style = style,
  1638. color = color,
  1639. modifier = Modifier.padding(top = 5.dp)
  1640. )
  1641. }
  1642. @Composable
  1643. fun ColumnScope.ColumnText(
  1644. text: String,
  1645. color: Color,
  1646. size: TextUnit,
  1647. style: TextStyle
  1648. ) {
  1649. Surface(
  1650. modifier = Modifier.padding(start = 0.dp),
  1651. color = Color.Transparent
  1652. ) {
  1653. Text(text = text,
  1654. style = style,
  1655. color = color,
  1656. maxLines = 1,
  1657. modifier = Modifier
  1658. .padding(start = 0.dp, end = 0.dp)
  1659. .weight(1f)
  1660. )
  1661. }
  1662. }
  1663. @Composable
  1664. fun RowScope.AddText(
  1665. text: String,
  1666. size: TextUnit,
  1667. color: Color,
  1668. isTablet: Boolean
  1669. ) {
  1670. Text(
  1671. text = text,
  1672. style = MaterialTheme.typography.labelMedium.copy(
  1673. fontSize = 18.sp
  1674. ),
  1675. color = color,
  1676. modifier = Modifier.padding(top = 0.dp)
  1677. )
  1678. }
  1679. @Composable
  1680. fun OnLifecycleEvent(onEvent: (
  1681. owner: LifecycleOwner,
  1682. event: Lifecycle.Event
  1683. ) -> Unit) {
  1684. val eventHandler = rememberUpdatedState(onEvent)
  1685. val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
  1686. DisposableEffect(lifecycleOwner.value) {
  1687. val lifecycle = lifecycleOwner.value.lifecycle
  1688. val observer = LifecycleEventObserver { owner, event ->
  1689. eventHandler.value(owner, event)
  1690. }
  1691. lifecycle.addObserver(observer)
  1692. onDispose {
  1693. lifecycle.removeObserver(observer)
  1694. }
  1695. }
  1696. }
  1697. private fun getEnableProtocols(protocol_name: String, prefHelper: BasePreferenceHelper): Boolean {
  1698. prefHelper.getEnabledProtocols().let {
  1699. if (it.contains(protocol_name)) {
  1700. return true
  1701. }
  1702. }
  1703. return false
  1704. }
  1705. @Composable
  1706. fun pinkBackgroundTV(): Painter {
  1707. return if (isDarkTheme.value) painterResource(id = R.drawable.darkpinkbackground)
  1708. else painterResource(id = R.drawable.pinkbackground3x)
  1709. }
  1710. @Composable
  1711. fun blueBackgroundTV(): Painter {
  1712. return if (isDarkTheme.value) painterResource(id = R.drawable.darkbluebackground)
  1713. else painterResource(id = R.drawable.bluebackground3x)
  1714. }