CountryItem.kt 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package com.vpn.fastestvpnservice.customItems
  2. import android.os.Looper
  3. import android.util.Log
  4. import android.widget.Toast
  5. import androidx.compose.foundation.background
  6. import androidx.compose.foundation.clickable
  7. import androidx.compose.foundation.gestures.detectTapGestures
  8. import androidx.compose.foundation.interaction.MutableInteractionSource
  9. import androidx.compose.foundation.layout.Arrangement
  10. import androidx.compose.foundation.layout.Box
  11. import androidx.compose.foundation.layout.Column
  12. import androidx.compose.foundation.layout.ColumnScope
  13. import androidx.compose.foundation.layout.Row
  14. import androidx.compose.foundation.layout.Spacer
  15. import androidx.compose.foundation.layout.fillMaxSize
  16. import androidx.compose.foundation.layout.fillMaxWidth
  17. import androidx.compose.foundation.layout.height
  18. import androidx.compose.foundation.layout.padding
  19. import androidx.compose.foundation.layout.size
  20. import androidx.compose.foundation.lazy.LazyColumn
  21. import androidx.compose.foundation.lazy.items
  22. import androidx.compose.foundation.shape.CircleShape
  23. import androidx.compose.material3.Icon
  24. import androidx.compose.material3.IconButton
  25. import androidx.compose.material3.MaterialTheme
  26. import androidx.compose.material3.Surface
  27. import androidx.compose.material3.Text
  28. import androidx.compose.runtime.Composable
  29. import androidx.compose.runtime.LaunchedEffect
  30. import androidx.compose.runtime.MutableState
  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.graphics.Color
  45. import androidx.compose.ui.input.pointer.pointerInput
  46. import androidx.compose.ui.layout.ContentScale
  47. import androidx.compose.ui.platform.LocalContext
  48. import androidx.compose.ui.res.colorResource
  49. import androidx.compose.ui.res.painterResource
  50. import androidx.compose.ui.text.TextStyle
  51. import androidx.compose.ui.text.style.TextAlign
  52. import androidx.compose.ui.tooling.preview.Preview
  53. import androidx.compose.ui.unit.dp
  54. import androidx.compose.ui.unit.sp
  55. import androidx.lifecycle.viewmodel.compose.viewModel
  56. import androidx.navigation.NavHostController
  57. import androidx.navigation.compose.rememberNavController
  58. import com.vpn.fastestvpnservice.R
  59. import com.vpn.fastestvpnservice.beans.CountryServerList
  60. import com.vpn.fastestvpnservice.beans.Server
  61. import com.vpn.fastestvpnservice.beans.allLocationsList
  62. import com.vpn.fastestvpnservice.beans.favList
  63. import com.vpn.fastestvpnservice.beans.favListServer
  64. import com.vpn.fastestvpnservice.utils.Utils
  65. import com.stealthcopter.networktools.Ping
  66. import com.stealthcopter.networktools.ping.PingResult
  67. import com.stealthcopter.networktools.ping.PingStats
  68. import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
  69. import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.onServer
  70. import com.vpn.fastestvpnservice.sealedClass.BottomBarScreen
  71. import com.vpn.fastestvpnservice.sealedClass.Screen
  72. import com.vpn.fastestvpnservice.viewmodels.HomeViewModel
  73. import com.vpn.fastestvpnservice.viewmodels.ServerListViewModel
  74. import com.vpn.fastestvpnservice.viewmodels.SplashViewModel
  75. import java.lang.Exception
  76. import java.util.logging.Handler
  77. var serverInfoObj: MutableState<Server> = mutableStateOf(Server())
  78. @Composable
  79. fun CountryItem(
  80. server: Server,
  81. category: String,
  82. countryTotalServers: Int,
  83. navHostController: NavHostController
  84. ) {
  85. Log.d("test_countrySize", "CountryItem Called ${server.server_name} ${server.totalServers}")
  86. Box(
  87. modifier = Modifier
  88. .fillMaxWidth()
  89. .background(
  90. color = MaterialTheme.colorScheme.background
  91. )
  92. .padding(bottom = 1.dp)
  93. ) {
  94. val context = LocalContext.current
  95. val basePreferenceHelper = BasePreferenceHelper(context)
  96. val countrySize by rememberSaveable { mutableStateOf(server.totalServers) }
  97. var isServerExpanded by rememberSaveable { mutableStateOf(false) }
  98. val serverListViewModel: ServerListViewModel = viewModel{
  99. ServerListViewModel(context)
  100. }
  101. val splashViewModel: SplashViewModel = viewModel{
  102. SplashViewModel(context)
  103. }
  104. val scope = rememberCoroutineScope()
  105. val homeViewModel: HomeViewModel = viewModel {
  106. HomeViewModel(context, scope)
  107. }
  108. var isCountryServerClicked by remember { mutableStateOf(false) }
  109. if (isCountryServerClicked) {
  110. Log.d("ServerCallbacks", "isServerClicked $isCountryServerClicked")
  111. onServer.onServerSelected(context, homeViewModel,
  112. onClick = { isCountryServerClicked = false },
  113. true,
  114. server
  115. )
  116. navHostController.popBackStack()
  117. }
  118. var isServerServerClicked by remember { mutableStateOf(false) }
  119. if (isServerServerClicked) {
  120. Log.d("ServerCallbacks", "isServerClicked $isServerServerClicked")
  121. onServer.onServerSelected(
  122. context,
  123. homeViewModel,
  124. onClick = { isServerServerClicked = false },
  125. true,
  126. server
  127. )
  128. navHostController.popBackStack()
  129. }
  130. countrySize.let { size ->
  131. // var locationsSize: Int = 0
  132. // val countriesServersData = basePreferenceHelper.getServerData().get(0).servers
  133. // countriesServersData?.let {
  134. // val serversGroup = serverListViewModel.getServerGroupList(server, it)
  135. // locationsSize = serversGroup.size
  136. // }
  137. Column {
  138. /* Country Location's Row */
  139. Row(
  140. verticalAlignment = Alignment.Top,
  141. horizontalArrangement = Arrangement.Start,
  142. modifier = Modifier
  143. .fillMaxWidth()
  144. .padding(
  145. start = 16.dp, end = 12.dp, top = 12.dp
  146. )
  147. .clickable(
  148. indication = null,
  149. interactionSource = remember { MutableInteractionSource() }
  150. ) {
  151. if (server.enable == 1) {
  152. // basePreferenceHelper.setServerObject(server)
  153. isCountryServerClicked = true
  154. } else {
  155. navHostController.navigate(
  156. Screen.Subscription.route
  157. )
  158. }
  159. }
  160. ) {
  161. val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  162. else Utils.getDrawableGray(context, server.iso)
  163. Icon(
  164. painter = painterResource(id = icon),
  165. contentDescription = "Server Logo",
  166. tint = Color.Unspecified,
  167. modifier = Modifier
  168. .padding(bottom = 16.dp)
  169. .size(24.dp)
  170. .clip(CircleShape)
  171. .paint(
  172. painter = painterResource(id = icon),
  173. contentScale = ContentScale.FillHeight
  174. )
  175. )
  176. Text(text = server.country!!,
  177. style = MaterialTheme.typography.labelMedium,
  178. color = MaterialTheme.colorScheme.primary,
  179. modifier = Modifier
  180. .padding(start = 16.dp, bottom = 18.dp)
  181. .align(Alignment.CenterVertically)
  182. )
  183. Spacer(modifier = Modifier.weight(1F))
  184. Text(text = "$countryTotalServers locations",
  185. style = MaterialTheme.typography.bodySmall,
  186. color = colorResource(id = R.color.dark_blue_gray_text),
  187. modifier = Modifier
  188. .padding(end = 30.dp, bottom = 18.dp)
  189. .align(Alignment.CenterVertically)
  190. .alpha(0.4F)
  191. )
  192. // Spacer(modifier = Modifier.weight(1F))
  193. Icon(
  194. modifier = Modifier
  195. .padding(bottom = 18.dp, end = 0.dp)
  196. .size(12.dp, 7.dp)
  197. .align(Alignment.CenterVertically)
  198. .clickable(
  199. indication = null,
  200. interactionSource = remember { MutableInteractionSource() }
  201. ) { isServerExpanded = !isServerExpanded },
  202. painter = if (isServerExpanded) painterResource(
  203. id = R.drawable.dragarrow3x) else painterResource(
  204. id = R.drawable.downarrow3x),
  205. contentDescription = "Server Logo",
  206. tint = MaterialTheme.colorScheme.primary,
  207. )
  208. }
  209. /* Country Expandable's Row */
  210. if (isServerExpanded) {
  211. val countriesServersData1 = basePreferenceHelper.getServerData().get(0).servers
  212. countriesServersData1?.let {
  213. val serversGroup = serverListViewModel.getServerGroupList(server, it)
  214. ExpandableRow(server = serversGroup, navHostController)
  215. }
  216. }
  217. }
  218. Surface(
  219. modifier = Modifier
  220. .padding(start = 0.dp, end = 0.dp)
  221. .height(1.dp)
  222. .fillMaxWidth()
  223. .alpha(0.6F)
  224. .align(Alignment.BottomCenter),
  225. color = colorResource(id = R.color.gray_icon)
  226. ) {}
  227. // else {
  228. // Log.d("test_return_ping","C[1]=> " + server.server_name + server.ping)
  229. // Row(
  230. // verticalAlignment = Alignment.Top,
  231. // horizontalArrangement = Arrangement.Start,
  232. // modifier = Modifier
  233. // .fillMaxWidth()
  234. // .padding(start = 16.dp, end = 7.dp, top = 12.dp)
  235. // .clickable(
  236. // indication = null,
  237. // interactionSource = remember { MutableInteractionSource() }
  238. // ) {
  239. // basePreferenceHelper.setServerObject(server)
  240. // isServerServerClicked = true
  241. //// navHostController.popBackStack()
  242. // }
  243. // ) {
  244. // val icon = if (server.enable == 1) Utils.getDrawable(context, server.iso)
  245. // else Utils.getDrawableGray(context, server.iso)
  246. //
  247. // Icon(
  248. // painter = painterResource(id = icon),
  249. // contentDescription = "Server Logo",
  250. // tint = Color.Unspecified,
  251. // modifier = Modifier
  252. // .padding(bottom = 16.dp)
  253. // .size(24.dp)
  254. // .clip(CircleShape)
  255. // .paint(
  256. // painter = painterResource(id = icon),
  257. // contentScale = ContentScale.FillHeight
  258. // )
  259. // )
  260. // val serverTitle = if (category.lowercase().toString() == "servers") server.country else server.server_name
  261. // Text(text = serverTitle!!,
  262. // style = MaterialTheme.typography.labelMedium,
  263. // color = MaterialTheme.colorScheme.primary,
  264. // modifier = Modifier
  265. // .padding(start = 16.dp, bottom = 18.dp)
  266. // .align(Alignment.CenterVertically)
  267. // )
  268. // Spacer(modifier = Modifier.weight(1F))
  269. // val pings = server.ping
  270. // Text(
  271. // text = "${server.ping} ms",
  272. // style = MaterialTheme.typography.displayMedium,
  273. // color = colorResource(id = R.color.blue_text),
  274. // modifier = Modifier
  275. // .padding(end = 30.dp, bottom = 18.dp)
  276. // .align(Alignment.CenterVertically)
  277. // )
  278. // var isFavorite by rememberSaveable { mutableStateOf(server.isFavourited) }
  279. //
  280. // IconButton(
  281. // modifier = Modifier
  282. // .padding(bottom = 18.dp, end = 8.dp)
  283. // .size(21.dp, 20.dp)
  284. // .align(Alignment.CenterVertically),
  285. // onClick = {
  286. // isFavorite = !isFavorite!!
  287. // serverListViewModel.favAndUnFav(server)
  288. // }
  289. // )
  290. // {
  291. //// val favResponse = serverListViewModel.mutableLiveDataFavUnFav.observeAsState().value
  292. //// favResponse?.let {
  293. //// Log.d("test_fav_response", it.message.toString())
  294. //// splashViewModel.serverDataApi()
  295. //// serverListViewModel.mutableLiveDataFavUnFav.value = null
  296. //// }
  297. //
  298. // Icon(
  299. //// .clickable(
  300. //// indication = null,
  301. //// interactionSource = remember { MutableInteractionSource() }
  302. //// ) { },
  303. //
  304. // painter = if (isFavorite == true) painterResource(
  305. // id = R.drawable.fav_server3x) else painterResource(
  306. // id = R.drawable.unfav_server3x),
  307. //
  308. // contentDescription = "Server Logo",
  309. // tint = Color.Unspecified,
  310. // )
  311. // }
  312. // }
  313. // Log.d("test_servers_count", "${server.server_name} ${server.countryServers?.size}")
  314. /* Country Location's Row -> 1 Location() */
  315. // var ping by remember { mutableIntStateOf(0) }
  316. // Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  317. // object : Ping.PingListener{
  318. // override fun onResult(pingResult: PingResult?) {
  319. // android.os.Handler(Looper.getMainLooper()).post {
  320. // val ping = pingResult?.timeTaken?.toInt()!!
  321. // server.ping = ping
  322. // Log.d("test_ping", "ping = $ping")
  323. // }
  324. // }
  325. //
  326. // override fun onError(e: Exception?) {}
  327. // override fun onFinished(pingStats: PingStats?) {}
  328. // }
  329. // )
  330. }
  331. }
  332. }
  333. @Composable
  334. fun ColumnScope.ExpandableRow(server: ArrayList<Server>, navHostController: NavHostController) {
  335. val context = LocalContext.current
  336. val basePreferenceHelper = BasePreferenceHelper(context)
  337. val serverListViewModel: ServerListViewModel = viewModel{
  338. ServerListViewModel(context)
  339. }
  340. val splashViewModel: SplashViewModel = viewModel{ SplashViewModel(context) }
  341. val scope = rememberCoroutineScope()
  342. val homeViewModel: HomeViewModel = viewModel { HomeViewModel(context, scope) }
  343. var isExpServerClicked by remember { mutableStateOf(false) }
  344. Column(
  345. modifier = Modifier
  346. .padding(
  347. start = 40.dp, end = 26.dp,
  348. top = 2.dp, bottom = 28.dp
  349. )
  350. .background(Color.Transparent)
  351. ) {
  352. // Expandable Row
  353. server.let { serverData ->
  354. serverData.forEachIndexed { index, serverInfo ->
  355. Log.d("serverInfo_ping", "serverInfo ${serverInfo.server_name} :: ${serverInfo.ping}")
  356. var isFavorite by rememberSaveable { mutableStateOf(serverInfo.isFavourited) }
  357. val isServerFavourited: Boolean = serverInfo.isFavourited == true
  358. Log.d("test-server_fav_d", "$isFavorite")
  359. if (isExpServerClicked) {
  360. onServer.onServerSelected(
  361. context,
  362. homeViewModel,
  363. onClick = {isExpServerClicked = false},
  364. true,
  365. serverInfoObj.value
  366. )
  367. navHostController.popBackStack()
  368. }
  369. Row(
  370. verticalAlignment = Alignment.CenterVertically,
  371. horizontalArrangement = Arrangement.Start,
  372. modifier = Modifier
  373. .fillMaxWidth()
  374. .padding(
  375. vertical = 15.dp
  376. )
  377. .background(Color.Transparent)
  378. .clickable(
  379. indication = null,
  380. interactionSource = remember { MutableInteractionSource() }
  381. ) {
  382. if (serverInfo.enable == 1) {
  383. serverInfoObj.value = serverInfo
  384. // basePreferenceHelper.setServerObject(serverInfo)
  385. isExpServerClicked = true
  386. } else {
  387. navHostController.navigate(
  388. Screen.Subscription.route
  389. )
  390. }
  391. }
  392. ) {
  393. Text(text = serverInfo.server_name!!,
  394. style = MaterialTheme.typography.labelMedium,
  395. color = MaterialTheme.colorScheme.onSecondary,
  396. modifier = Modifier
  397. .padding(start = 16.dp, bottom = 0.dp)
  398. .align(Alignment.CenterVertically)
  399. .alpha(0.4F)
  400. )
  401. Spacer(modifier = Modifier.weight(1F))
  402. Text(text = "${serverInfo.ping} ms",
  403. style = MaterialTheme.typography.displayMedium,
  404. color = colorResource(id = R.color.blue_text),
  405. modifier = Modifier
  406. .padding(start = 0.dp, end = 30.dp)
  407. .align(Alignment.CenterVertically)
  408. )
  409. IconButton(
  410. modifier = Modifier
  411. .padding(bottom = 0.dp, end = 16.dp)
  412. .size(25.dp)
  413. .align(Alignment.CenterVertically),
  414. onClick = {
  415. isFavorite = !isFavorite!!
  416. serverListViewModel.favAndUnFav(serverInfo)
  417. }
  418. )
  419. {
  420. Icon(
  421. // .clickable(
  422. // indication = null,
  423. // interactionSource = remember { MutableInteractionSource() }
  424. // ) { },
  425. painter = if (isServerFavourited) painterResource(
  426. id = R.drawable.fav_server3x) else painterResource(
  427. id = R.drawable.unfav_server3x),
  428. contentDescription = "Server Logo",
  429. tint = Color.Unspecified,
  430. modifier = Modifier.size(22.dp, 21.dp)
  431. )
  432. }
  433. }
  434. Surface(
  435. modifier = Modifier
  436. .padding(top = 0.dp, end = 0.dp)
  437. .height(1.dp)
  438. .fillMaxWidth()
  439. .alpha(0.6F)
  440. ,
  441. color = colorResource(id = R.color.gray_icon)
  442. ) {}
  443. }
  444. }
  445. }
  446. }
  447. fun calculatePing(server: Server, onPingResult: (Int) -> Unit) {
  448. Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  449. object : Ping.PingListener{
  450. override fun onResult(pingResult: PingResult?) {
  451. android.os.Handler(Looper.getMainLooper()).post {
  452. val ping = pingResult?.timeTaken?.toInt()!!
  453. onPingResult(ping)
  454. Log.d("test_ping", "ping[0] = $ping")
  455. }
  456. }
  457. override fun onError(e: java.lang.Exception?) {}
  458. override fun onFinished(pingStats: PingStats?) {}
  459. }
  460. )
  461. }
  462. @Preview
  463. @Composable
  464. fun CountryItemPreview() {
  465. CountryItem(server = favListServer[0], "servers", 1, rememberNavController())
  466. }