ServerItem.kt 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. package com.vpn.fastestvpnservice.customItems
  2. import android.content.res.Configuration
  3. import android.os.Looper
  4. import android.util.Log
  5. import android.widget.Toast
  6. import androidx.compose.foundation.BorderStroke
  7. import androidx.compose.foundation.Image
  8. import androidx.compose.foundation.background
  9. import androidx.compose.foundation.border
  10. import androidx.compose.foundation.clickable
  11. import androidx.compose.foundation.interaction.MutableInteractionSource
  12. import androidx.compose.foundation.layout.Arrangement
  13. import androidx.compose.foundation.layout.Box
  14. import androidx.compose.foundation.layout.Row
  15. import androidx.compose.foundation.layout.Spacer
  16. import androidx.compose.foundation.layout.fillMaxSize
  17. import androidx.compose.foundation.layout.fillMaxWidth
  18. import androidx.compose.foundation.layout.height
  19. import androidx.compose.foundation.layout.padding
  20. import androidx.compose.foundation.layout.size
  21. import androidx.compose.foundation.layout.wrapContentHeight
  22. import androidx.compose.foundation.layout.wrapContentWidth
  23. import androidx.compose.foundation.shape.CircleShape
  24. import androidx.compose.foundation.shape.RoundedCornerShape
  25. import androidx.compose.material3.Icon
  26. import androidx.compose.material3.IconButton
  27. import androidx.compose.material3.MaterialTheme
  28. import androidx.compose.material3.Surface
  29. import androidx.compose.material3.Text
  30. import androidx.compose.runtime.Composable
  31. import androidx.compose.runtime.getValue
  32. import androidx.compose.runtime.livedata.observeAsState
  33. import androidx.compose.runtime.mutableIntStateOf
  34. import androidx.compose.runtime.mutableStateOf
  35. import androidx.compose.runtime.remember
  36. import androidx.compose.runtime.rememberCoroutineScope
  37. import androidx.compose.runtime.saveable.rememberSaveable
  38. import androidx.compose.runtime.setValue
  39. import androidx.compose.ui.Alignment
  40. import androidx.compose.ui.Modifier
  41. import androidx.compose.ui.draw.alpha
  42. import androidx.compose.ui.draw.clip
  43. import androidx.compose.ui.draw.paint
  44. import androidx.compose.ui.draw.scale
  45. import androidx.compose.ui.graphics.Brush
  46. import androidx.compose.ui.graphics.Color
  47. import androidx.compose.ui.graphics.Shape
  48. import androidx.compose.ui.layout.ContentScale
  49. import androidx.compose.ui.platform.LocalContext
  50. import androidx.compose.ui.res.colorResource
  51. import androidx.compose.ui.res.painterResource
  52. import androidx.compose.ui.text.TextStyle
  53. import androidx.compose.ui.tooling.preview.Preview
  54. import androidx.compose.ui.unit.dp
  55. import androidx.compose.ui.unit.sp
  56. import androidx.lifecycle.viewmodel.compose.viewModel
  57. import androidx.navigation.NavHostController
  58. import androidx.navigation.compose.rememberNavController
  59. import com.stealthcopter.networktools.Ping
  60. import com.stealthcopter.networktools.ping.PingResult
  61. import com.stealthcopter.networktools.ping.PingStats
  62. import com.vpn.fastestvpnservice.MainActivity
  63. import com.vpn.fastestvpnservice.R
  64. import com.vpn.fastestvpnservice.beans.Server
  65. import com.vpn.fastestvpnservice.beans.ServerList
  66. import com.vpn.fastestvpnservice.beans.favList
  67. import com.vpn.fastestvpnservice.beans.favListServer
  68. import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
  69. import com.vpn.fastestvpnservice.helpers.UIHelper
  70. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.onServer
  71. import com.vpn.fastestvpnservice.sealedClass.BottomBarScreen
  72. import com.vpn.fastestvpnservice.sealedClass.Screen
  73. import com.vpn.fastestvpnservice.utils.Utils
  74. import com.vpn.fastestvpnservice.viewmodels.HomeViewModel
  75. import com.vpn.fastestvpnservice.viewmodels.SearchListViewModel
  76. import com.vpn.fastestvpnservice.viewmodels.ServerListViewModel
  77. import com.vpn.fastestvpnservice.viewmodels.SplashViewModel
  78. import java.lang.Exception
  79. @Composable
  80. fun ServerItem(server: Server, navHostController: NavHostController, serverPing: Int = 0) {
  81. val context = LocalContext.current
  82. val scope = rememberCoroutineScope()
  83. var isServerClicked by remember { mutableStateOf(false) }
  84. val homeViewModel: HomeViewModel = viewModel{ HomeViewModel(context, scope) }
  85. val basePreferenceHelper = BasePreferenceHelper(context)
  86. var isFavorite by remember { mutableStateOf(server.isFavourited) }
  87. val isServerFavourited: Boolean = server.isFavourited == true
  88. Log.d("test-server_fav_d", "$isFavorite")
  89. Box(
  90. modifier = Modifier
  91. .fillMaxWidth()
  92. .background(color = MaterialTheme.colorScheme.background)
  93. .padding(bottom = 1.dp)
  94. ) {
  95. val serverListViewModel: ServerListViewModel = viewModel{
  96. ServerListViewModel(context)
  97. }
  98. val splashViewModel: SplashViewModel = viewModel{
  99. SplashViewModel(context)
  100. }
  101. if (isServerClicked) {
  102. Log.d("ServerCallbacks", "isServerClicked $isServerClicked")
  103. onServer.onServerSelected(
  104. context,
  105. homeViewModel,
  106. onClick = { isServerClicked = false },
  107. false,
  108. server
  109. )
  110. navHostController.popBackStack()
  111. }
  112. Row(
  113. verticalAlignment = Alignment.Top,
  114. horizontalArrangement = Arrangement.Start,
  115. modifier = Modifier
  116. .fillMaxWidth()
  117. .padding(start = 12.dp, end = 7.dp, top = 12.dp)
  118. .clickable(
  119. indication = null,
  120. interactionSource = remember { MutableInteractionSource() }
  121. ) {
  122. if (server.enable == 1) {
  123. basePreferenceHelper.setServerObject(server)
  124. isServerClicked = true
  125. } else {
  126. navHostController.navigate(
  127. Screen.Subscription.route
  128. )
  129. }
  130. }
  131. ) {
  132. var ping by remember { mutableIntStateOf(0) }
  133. // Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  134. // object : Ping.PingListener{
  135. // override fun onResult(pingResult: PingResult?) {
  136. // android.os.Handler(Looper.getMainLooper()).post {
  137. // ping = pingResult?.timeTaken?.toInt()!!
  138. // }
  139. // }
  140. //
  141. // override fun onError(e: Exception?) {}
  142. // override fun onFinished(pingStats: PingStats?) {}
  143. // }
  144. // )
  145. val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  146. else Utils.getDrawableGray(context, server.iso)
  147. Icon(
  148. painter = painterResource(id = icon),
  149. contentDescription = "Server Logo",
  150. tint = Color.Unspecified,
  151. modifier = Modifier
  152. .padding(bottom = 16.dp)
  153. .size(24.dp)
  154. .clip(CircleShape)
  155. .paint(
  156. painter = painterResource(id = icon),
  157. contentScale = ContentScale.FillHeight
  158. )
  159. )
  160. Text(text = server.server_name!!,
  161. style = MaterialTheme.typography.labelMedium,
  162. color = MaterialTheme.colorScheme.primary,
  163. modifier = Modifier
  164. .padding(start = 16.dp, bottom = 18.dp)
  165. .align(Alignment.CenterVertically)
  166. )
  167. Spacer(modifier = Modifier.weight(1F))
  168. Text(text = "$serverPing ms",
  169. style = MaterialTheme.typography.displayMedium,
  170. color = colorResource(id = R.color.blue_text),
  171. modifier = Modifier
  172. .padding(end = 30.dp, bottom = 18.dp)
  173. .align(Alignment.CenterVertically)
  174. )
  175. // Spacer(modifier = Modifier.weight(1F))
  176. IconButton(
  177. modifier = Modifier
  178. .padding(bottom = 18.dp, end = 8.dp)
  179. .size(25.dp),
  180. onClick = {
  181. isFavorite = !isFavorite!!
  182. serverListViewModel.favAndUnFav(server)
  183. }
  184. ) {
  185. Icon(
  186. painter = if (isServerFavourited) painterResource(
  187. id = R.drawable.fav_server3x) else painterResource(
  188. id = R.drawable.unfav_server3x),
  189. contentDescription = "Server Logo",
  190. tint = Color.Unspecified,
  191. modifier = Modifier.size(22.dp, 21.dp)
  192. )
  193. }
  194. }
  195. Surface(
  196. modifier = Modifier
  197. .padding(start = 0.dp, end = 0.dp)
  198. .height(1.dp)
  199. .fillMaxWidth()
  200. .alpha(0.6F)
  201. .align(Alignment.BottomCenter),
  202. color = colorResource(id = R.color.gray_icon)
  203. ) {}
  204. }
  205. }
  206. @Composable
  207. fun FavoriteServerItem(server: Server, navHostController: NavHostController) {
  208. val context = LocalContext.current
  209. val basePreferenceHelper = BasePreferenceHelper(context)
  210. var serverListViewModel: ServerListViewModel = viewModel {
  211. ServerListViewModel(context = context)
  212. }
  213. val splashViewModel: SplashViewModel = viewModel{
  214. SplashViewModel(context)
  215. }
  216. val scope = rememberCoroutineScope()
  217. val homeViewModel: HomeViewModel = viewModel {
  218. HomeViewModel(context, scope)
  219. }
  220. var isFavorite by remember { mutableStateOf(server.isFavourited) }
  221. val isServerFavourited: Boolean = server.isFavourited == true
  222. Log.d("test-server_fav_d", "$isFavorite")
  223. var isFavServerClicked by remember { mutableStateOf(false) }
  224. if (isFavServerClicked) {
  225. Log.d("ServerCallbacks", "isServerClicked $isFavServerClicked")
  226. onServer.onServerSelected(
  227. context,
  228. homeViewModel,
  229. onClick = { isFavServerClicked = false },
  230. true,
  231. server
  232. )
  233. navHostController.popBackStack(BottomBarScreen.Home.route, false)
  234. }
  235. Box(
  236. modifier = Modifier
  237. .fillMaxWidth()
  238. .background(MaterialTheme.colorScheme.background)
  239. .padding(bottom = 1.dp)
  240. ) {
  241. Row(
  242. verticalAlignment = Alignment.Top,
  243. horizontalArrangement = Arrangement.Start,
  244. modifier = Modifier
  245. .fillMaxWidth()
  246. .padding(start = 12.dp, end = 7.dp, top = 12.dp)
  247. .clickable(
  248. indication = null,
  249. interactionSource = remember { MutableInteractionSource() }
  250. ) {
  251. if (server.enable == 1) {
  252. isFavServerClicked = true
  253. } else {
  254. navHostController.navigate(
  255. Screen.Subscription.route
  256. )
  257. }
  258. }
  259. ) {
  260. var ping by remember { mutableIntStateOf(0) }
  261. // Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  262. // object : Ping.PingListener{
  263. // override fun onResult(pingResult: PingResult?) {
  264. // android.os.Handler(Looper.getMainLooper()).post {
  265. // ping = pingResult?.timeTaken?.toInt()!!
  266. // }
  267. // }
  268. //
  269. // override fun onError(e: Exception?) {}
  270. // override fun onFinished(pingStats: PingStats?) {}
  271. // }
  272. // )
  273. val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  274. else Utils.getDrawableGray(context, server.iso)
  275. Icon(
  276. painter = painterResource(id = icon),
  277. contentDescription = "Server Logo",
  278. tint = Color.Unspecified,
  279. modifier = Modifier
  280. .padding(bottom = 16.dp)
  281. .size(24.dp)
  282. .clip(CircleShape)
  283. .paint(
  284. painter = painterResource(id = icon),
  285. contentScale = ContentScale.FillHeight
  286. )
  287. )
  288. Text(text = server.server_name!!,
  289. color = MaterialTheme.colorScheme.primary,
  290. style = MaterialTheme.typography.labelMedium,
  291. modifier = Modifier
  292. .padding(start = 16.dp, bottom = 18.dp)
  293. .align(Alignment.CenterVertically)
  294. )
  295. Spacer(modifier = Modifier.weight(1F))
  296. Text(text = "${server.ping} ms",
  297. color = colorResource(id = R.color.blue_text),
  298. style = MaterialTheme.typography.displayMedium,
  299. modifier = Modifier
  300. .padding(end = 30.dp, bottom = 18.dp)
  301. .align(Alignment.CenterVertically)
  302. )
  303. // Spacer(modifier = Modifier.weight(1F))
  304. IconButton(
  305. onClick = {
  306. isFavorite = !isFavorite!!
  307. serverListViewModel.favAndUnFav(server)
  308. },
  309. modifier = Modifier
  310. .padding(bottom = 18.dp, end = 0.dp)
  311. .size(25.dp)
  312. // .clickable(
  313. // indication = null,
  314. // interactionSource = remember { MutableInteractionSource() }
  315. // ) { },
  316. ) {
  317. Icon(
  318. painter = if (isServerFavourited) painterResource(
  319. id = R.drawable.fav_server3x) else painterResource(
  320. id = R.drawable.unfav_server3x),
  321. contentDescription = "Server Logo",
  322. tint = Color.Unspecified,
  323. modifier = Modifier.size(22.dp, 21.dp)
  324. )
  325. }
  326. }
  327. Surface(
  328. modifier = Modifier
  329. .padding(start = 0.dp, end = 0.dp)
  330. .height(1.dp)
  331. .fillMaxWidth()
  332. .alpha(0.6F)
  333. .align(Alignment.BottomCenter)
  334. ,
  335. color = colorResource(id = R.color.gray_icon)
  336. ) {}
  337. }
  338. }
  339. @Composable
  340. fun ServerSearchItem(
  341. server: Server,
  342. navHostController: NavHostController,
  343. bgColor: Color = Color.White,
  344. textColor: Color = MaterialTheme.colorScheme.primary,
  345. isServerCallbackShown: Boolean = true,
  346. onServerDisable: () -> Unit
  347. ) {
  348. val context = LocalContext.current
  349. val scope = rememberCoroutineScope()
  350. val basePreferenceHelper = BasePreferenceHelper(context)
  351. val serverListViewModel: ServerListViewModel = viewModel {
  352. ServerListViewModel(context = context)
  353. }
  354. val splashViewModel: SplashViewModel = viewModel{
  355. SplashViewModel(context)
  356. }
  357. val searchListViewModel: SearchListViewModel = viewModel{
  358. SearchListViewModel(context, serverListViewModel, splashViewModel)
  359. }
  360. val homeViewModel: HomeViewModel = viewModel{
  361. HomeViewModel(context, scope)
  362. }
  363. var isSearchServerClicked by remember {
  364. mutableStateOf(false)
  365. }
  366. var isFavorite by remember { mutableStateOf(server.isFavourited) }
  367. val isServerFavourited: Boolean = server.isFavourited == true
  368. Log.d("test-server_fav_d", "$isFavorite")
  369. if (isSearchServerClicked) {
  370. Log.d("ServerCallbacks", "isServerClicked $isSearchServerClicked")
  371. onServer.onServerSelected(
  372. context,
  373. homeViewModel,
  374. onClick = { isSearchServerClicked = false },
  375. false,
  376. server
  377. )
  378. navHostController.popBackStack()
  379. }
  380. Box(
  381. modifier = Modifier
  382. .fillMaxWidth()
  383. .background(color = MaterialTheme.colorScheme.onBackground)
  384. .padding(bottom = 1.dp)
  385. ) {
  386. Row(
  387. verticalAlignment = Alignment.Top,
  388. horizontalArrangement = Arrangement.Start,
  389. modifier = Modifier
  390. .fillMaxWidth()
  391. .padding(start = 12.dp, end = 7.dp, top = 12.dp)
  392. .clickable(
  393. indication = null,
  394. interactionSource = remember { MutableInteractionSource() }
  395. ) {
  396. if (server.enable == 1) {
  397. basePreferenceHelper.setServerObject(server)
  398. isSearchServerClicked = isServerCallbackShown
  399. if (!isServerCallbackShown) {
  400. onServerDisable()
  401. }
  402. }
  403. else {
  404. navHostController.navigate(
  405. Screen.Subscription.route
  406. )
  407. }
  408. }
  409. ) {
  410. var ping by remember { mutableIntStateOf(0) }
  411. // Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  412. // object : Ping.PingListener{
  413. // override fun onResult(pingResult: PingResult?) {
  414. // android.os.Handler(Looper.getMainLooper()).post {
  415. // ping = pingResult?.timeTaken?.toInt()!!
  416. // }
  417. // }
  418. //
  419. // override fun onError(e: Exception?) {}
  420. // override fun onFinished(pingStats: PingStats?) {}
  421. // }
  422. // )
  423. val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  424. else Utils.getDrawableGray(context, server.iso)
  425. Icon(
  426. painter = painterResource(id = icon),
  427. contentDescription = "Server Logo",
  428. tint = Color.Unspecified,
  429. modifier = Modifier
  430. .padding(bottom = 16.dp)
  431. .size(24.dp)
  432. .clip(CircleShape)
  433. .paint(
  434. painter = painterResource(id = icon),
  435. contentScale = ContentScale.FillHeight
  436. )
  437. )
  438. Text(text = server.server_name!!,
  439. color = textColor,
  440. style = MaterialTheme.typography.labelMedium,
  441. modifier = Modifier
  442. .padding(start = 16.dp, bottom = 18.dp)
  443. .align(Alignment.CenterVertically)
  444. )
  445. Spacer(modifier = Modifier.weight(1F))
  446. Text(text = "${server.ping} ms",
  447. color = colorResource(id = R.color.blue_text),
  448. style = MaterialTheme.typography.displayMedium,
  449. modifier = Modifier
  450. .padding(end = 30.dp, bottom = 18.dp)
  451. .align(Alignment.CenterVertically)
  452. )
  453. IconButton(
  454. modifier = Modifier
  455. .padding(bottom = 18.dp, end = 8.dp)
  456. .size(25.dp),
  457. onClick = {
  458. isFavorite = !isFavorite!!
  459. serverListViewModel.favAndUnFav(server)
  460. }) {
  461. Icon(
  462. painter = if (isServerFavourited) painterResource(
  463. id = R.drawable.fav_server3x) else painterResource(
  464. id = R.drawable.unfav_server3x),
  465. contentDescription = "Server Logo",
  466. tint = Color.Unspecified,
  467. modifier = Modifier.size(22.dp, 21.dp),
  468. )
  469. }
  470. }
  471. Surface(
  472. modifier = Modifier
  473. .padding(start = 0.dp, end = 0.dp)
  474. .height(1.dp)
  475. .fillMaxWidth()
  476. .alpha(0.6F)
  477. .align(Alignment.BottomCenter),
  478. color = colorResource(id = R.color.gray_icon)
  479. ) {}
  480. }
  481. }
  482. @Composable
  483. fun ServerSpecificItem(
  484. server: Server,
  485. navHostController: NavHostController,
  486. onServerDisable: () -> Unit
  487. ) {
  488. val context = LocalContext.current
  489. val scope = rememberCoroutineScope()
  490. val basePreferenceHelper = BasePreferenceHelper(context)
  491. val serverListViewModel: ServerListViewModel = viewModel {
  492. ServerListViewModel(context = context)
  493. }
  494. val splashViewModel: SplashViewModel = viewModel{
  495. SplashViewModel(context)
  496. }
  497. val searchListViewModel: SearchListViewModel = viewModel{
  498. SearchListViewModel(context, serverListViewModel, splashViewModel)
  499. }
  500. val homeViewModel: HomeViewModel = viewModel{
  501. HomeViewModel(context, scope)
  502. }
  503. var isSearchServerClicked by remember {
  504. mutableStateOf(false)
  505. }
  506. Box(
  507. modifier = Modifier
  508. .fillMaxWidth()
  509. .background(color = MaterialTheme.colorScheme.background)
  510. .padding(bottom = 1.dp)
  511. ) {
  512. Row(
  513. verticalAlignment = Alignment.Top,
  514. horizontalArrangement = Arrangement.Start,
  515. modifier = Modifier
  516. .fillMaxWidth()
  517. .padding(start = 12.dp, end = 7.dp, top = 12.dp)
  518. .clickable(
  519. indication = null,
  520. interactionSource = remember { MutableInteractionSource() }
  521. ) {
  522. if (server.enable == 1) {
  523. MainActivity.isSelectedServersShown = true
  524. basePreferenceHelper.setServerObject(server)
  525. basePreferenceHelper.setSmartServerObject(server)
  526. onServerDisable()
  527. } else {
  528. navHostController.navigate(
  529. Screen.Subscription.route
  530. )
  531. }
  532. }
  533. ) {
  534. val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  535. else Utils.getDrawableGray(context, server.iso)
  536. Icon(
  537. painter = painterResource(id = icon),
  538. contentDescription = "Server Logo",
  539. tint = Color.Unspecified,
  540. modifier = Modifier
  541. .padding(bottom = 16.dp)
  542. .size(24.dp)
  543. .clip(CircleShape)
  544. .paint(
  545. painter = painterResource(id = icon),
  546. contentScale = ContentScale.FillHeight
  547. )
  548. )
  549. Text(text = server.server_name!!,
  550. color = MaterialTheme.colorScheme.primary,
  551. style = MaterialTheme.typography.labelMedium,
  552. modifier = Modifier
  553. .padding(start = 16.dp, bottom = 18.dp)
  554. .align(Alignment.CenterVertically)
  555. )
  556. }
  557. Surface(
  558. modifier = Modifier
  559. .padding(start = 0.dp, end = 0.dp)
  560. .height(1.dp)
  561. .fillMaxWidth()
  562. .alpha(0.6F)
  563. .align(Alignment.BottomCenter)
  564. ,
  565. color = colorResource(id = R.color.gray_icon)
  566. ) {}
  567. }
  568. }
  569. @Preview
  570. @Composable
  571. fun ServerItemPreview() {
  572. ServerItem(server = favListServer[0], rememberNavController())
  573. }
  574. @Preview
  575. @Composable
  576. fun FavoriteServerItemPreview() {
  577. FavoriteServerItem(server = favListServer[0], rememberNavController())
  578. }
  579. @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
  580. @Composable
  581. fun FavoriteServerItemPreviewDark() {
  582. FavoriteServerItem(server = favListServer[0], rememberNavController())
  583. }
  584. @Preview
  585. @Composable
  586. fun ServerSearchItemPreview() {
  587. ServerSearchItem(server = favListServer[0], rememberNavController()) {}
  588. }