CountryItem.kt 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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.interaction.MutableInteractionSource
  8. import androidx.compose.foundation.layout.Arrangement
  9. import androidx.compose.foundation.layout.Box
  10. import androidx.compose.foundation.layout.Column
  11. import androidx.compose.foundation.layout.ColumnScope
  12. import androidx.compose.foundation.layout.Row
  13. import androidx.compose.foundation.layout.Spacer
  14. import androidx.compose.foundation.layout.fillMaxSize
  15. import androidx.compose.foundation.layout.fillMaxWidth
  16. import androidx.compose.foundation.layout.height
  17. import androidx.compose.foundation.layout.padding
  18. import androidx.compose.foundation.layout.size
  19. import androidx.compose.foundation.lazy.LazyColumn
  20. import androidx.compose.foundation.lazy.items
  21. import androidx.compose.material3.Icon
  22. import androidx.compose.material3.IconButton
  23. import androidx.compose.material3.MaterialTheme
  24. import androidx.compose.material3.Surface
  25. import androidx.compose.material3.Text
  26. import androidx.compose.runtime.Composable
  27. import androidx.compose.runtime.LaunchedEffect
  28. import androidx.compose.runtime.MutableState
  29. import androidx.compose.runtime.getValue
  30. import androidx.compose.runtime.livedata.observeAsState
  31. import androidx.compose.runtime.mutableIntStateOf
  32. import androidx.compose.runtime.mutableStateOf
  33. import androidx.compose.runtime.remember
  34. import androidx.compose.runtime.saveable.rememberSaveable
  35. import androidx.compose.runtime.setValue
  36. import androidx.compose.ui.Alignment
  37. import androidx.compose.ui.Modifier
  38. import androidx.compose.ui.draw.alpha
  39. import androidx.compose.ui.graphics.Color
  40. import androidx.compose.ui.platform.LocalContext
  41. import androidx.compose.ui.res.colorResource
  42. import androidx.compose.ui.res.painterResource
  43. import androidx.compose.ui.text.TextStyle
  44. import androidx.compose.ui.text.style.TextAlign
  45. import androidx.compose.ui.tooling.preview.Preview
  46. import androidx.compose.ui.unit.dp
  47. import androidx.compose.ui.unit.sp
  48. import androidx.lifecycle.viewmodel.compose.viewModel
  49. import com.vpn.fastestvpnservice.R
  50. import com.vpn.fastestvpnservice.beans.CountryServerList
  51. import com.vpn.fastestvpnservice.beans.Server
  52. import com.vpn.fastestvpnservice.beans.allLocationsList
  53. import com.vpn.fastestvpnservice.beans.favList
  54. import com.vpn.fastestvpnservice.beans.favListServer
  55. import com.vpn.fastestvpnservice.utils.Utils
  56. import com.stealthcopter.networktools.Ping
  57. import com.stealthcopter.networktools.ping.PingResult
  58. import com.stealthcopter.networktools.ping.PingStats
  59. import com.vpn.fastestvpnservice.viewmodels.ServerListViewModel
  60. import com.vpn.fastestvpnservice.viewmodels.SplashViewModel
  61. import java.lang.Exception
  62. import java.util.logging.Handler
  63. @Composable
  64. fun CountryItem(server: Server, category: String) {
  65. Log.d("test_countrySize", "CountryItem Called")
  66. Box(
  67. modifier = Modifier
  68. .fillMaxWidth()
  69. .background(
  70. color = MaterialTheme.colorScheme.background
  71. )
  72. .padding(bottom = 1.dp)
  73. ) {
  74. val context = LocalContext.current
  75. var countrySize by rememberSaveable { mutableStateOf(server.countryServers) }
  76. var isServerExpanded by rememberSaveable { mutableStateOf(false) }
  77. val serverListViewModel: ServerListViewModel = viewModel{
  78. ServerListViewModel(context)
  79. }
  80. val splashViewModel: SplashViewModel = viewModel{
  81. SplashViewModel(context)
  82. }
  83. // var countrySize: Int = 0
  84. Log.d("test_countrySize", "countrySize $countrySize")
  85. // LaunchedEffect(key1 = Unit) {
  86. // Log.d("test_countrySize", "countrySize LE() $countrySize")
  87. // if (countrySize == 0) {
  88. // Log.d("test_countrySize", "countrySize==0 $countrySize")
  89. // countrySize = server.totalServers
  90. // }
  91. // }
  92. if (countrySize != null){
  93. countrySize.let { size ->
  94. if (size?.size!! > 1) {
  95. Column {
  96. /* Country Location's Row */
  97. Row(
  98. verticalAlignment = Alignment.Top,
  99. horizontalArrangement = Arrangement.Start,
  100. modifier = Modifier
  101. .fillMaxWidth()
  102. .padding(
  103. start = 16.dp, end = 12.dp, top = 12.dp
  104. )
  105. .clickable(
  106. indication = null,
  107. interactionSource = remember { MutableInteractionSource() }
  108. ) {
  109. }
  110. ) {
  111. val icon = Utils.getDrawable(context, server.iso)
  112. Icon(
  113. painter = painterResource(id = icon),
  114. contentDescription = "Server Logo",
  115. tint = Color.Unspecified,
  116. modifier = Modifier
  117. .padding(bottom = 16.dp)
  118. .size(24.dp)
  119. )
  120. Text(text = server.country!!,
  121. style = TextStyle(
  122. fontSize = 16.sp,
  123. color = MaterialTheme.colorScheme.primary
  124. ),
  125. modifier = Modifier
  126. .padding(start = 16.dp, bottom = 18.dp)
  127. .align(Alignment.CenterVertically)
  128. )
  129. Spacer(modifier = Modifier.weight(1F))
  130. Text(text = "${countrySize?.size} locations",
  131. style = TextStyle(
  132. fontSize = 16.sp,
  133. color = colorResource(id = R.color.blue_text)
  134. ),
  135. modifier = Modifier
  136. .padding(end = 30.dp, bottom = 18.dp)
  137. .align(Alignment.CenterVertically)
  138. )
  139. // Spacer(modifier = Modifier.weight(1F))
  140. Icon(
  141. modifier = Modifier
  142. .padding(bottom = 18.dp, end = 0.dp)
  143. .size(12.dp, 7.dp)
  144. .align(Alignment.CenterVertically)
  145. .clickable(
  146. indication = null,
  147. interactionSource = remember { MutableInteractionSource() }
  148. ) { isServerExpanded = !isServerExpanded },
  149. painter = if (isServerExpanded) painterResource(
  150. id = R.drawable.dragarrow3x) else painterResource(
  151. id = R.drawable.downarrow3x),
  152. contentDescription = "Server Logo",
  153. tint = MaterialTheme.colorScheme.primary,
  154. )
  155. }
  156. /* Country Expandable's Row */
  157. if (isServerExpanded) {
  158. ExpandableRow(server = server)
  159. }
  160. }
  161. }
  162. else {
  163. Log.d("test_return_ping","C[1]=> " + server.server_name + server.ping)
  164. // Log.d("test_servers_count", "${server.server_name} ${server.countryServers?.size}")
  165. /* Country Location's Row -> 1 Location() */
  166. // var ping by remember { mutableIntStateOf(0) }
  167. Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  168. object : Ping.PingListener{
  169. override fun onResult(pingResult: PingResult?) {
  170. android.os.Handler(Looper.getMainLooper()).post {
  171. val ping = pingResult?.timeTaken?.toInt()!!
  172. server.ping = ping
  173. Log.d("test_ping", "ping = $ping")
  174. }
  175. }
  176. override fun onError(e: Exception?) {}
  177. override fun onFinished(pingStats: PingStats?) {}
  178. }
  179. )
  180. Row(
  181. verticalAlignment = Alignment.Top,
  182. horizontalArrangement = Arrangement.Start,
  183. modifier = Modifier
  184. .fillMaxWidth()
  185. .padding(start = 16.dp, end = 7.dp, top = 12.dp)
  186. .clickable(
  187. indication = null,
  188. interactionSource = remember { MutableInteractionSource() }
  189. ) {
  190. }
  191. ) {
  192. val icon = Utils.getDrawable(context, server.iso)
  193. Icon(
  194. painter = painterResource(id = icon),
  195. contentDescription = "Server Logo",
  196. tint = Color.Unspecified,
  197. modifier = Modifier
  198. .padding(bottom = 16.dp)
  199. .size(24.dp)
  200. )
  201. val serverTitle = if (category.lowercase().toString() == "servers") server.country else server.server_name
  202. Text(text = serverTitle!!,
  203. style = TextStyle(
  204. fontSize = 16.sp,
  205. color = MaterialTheme.colorScheme.primary
  206. ),
  207. modifier = Modifier
  208. .padding(start = 16.dp, bottom = 18.dp)
  209. .align(Alignment.CenterVertically)
  210. )
  211. Spacer(modifier = Modifier.weight(1F))
  212. val pings = server.ping
  213. Text(
  214. text = "${server.ping} ms",
  215. style = TextStyle(
  216. fontSize = 16.sp,
  217. color = colorResource(id = R.color.blue_text)
  218. ),
  219. modifier = Modifier
  220. .padding(end = 30.dp, bottom = 18.dp)
  221. .align(Alignment.CenterVertically)
  222. )
  223. var isFavorite by rememberSaveable { mutableStateOf(server.isFavourited) }
  224. IconButton(
  225. modifier = Modifier
  226. .padding(bottom = 18.dp, end = 8.dp)
  227. .size(21.dp, 20.dp)
  228. .align(Alignment.CenterVertically),
  229. onClick = {
  230. isFavorite = !isFavorite!!
  231. serverListViewModel.favAndUnFav(server)
  232. }
  233. )
  234. {
  235. val favResponse = serverListViewModel.mutableLiveDataFavUnFav.observeAsState().value
  236. favResponse?.let {
  237. Log.d("test_fav_response", it.message.toString())
  238. splashViewModel.serverDataApi()
  239. serverListViewModel.mutableLiveDataFavUnFav.value = null
  240. }
  241. Icon(
  242. // .clickable(
  243. // indication = null,
  244. // interactionSource = remember { MutableInteractionSource() }
  245. // ) { },
  246. painter = if (isFavorite == true) painterResource(
  247. id = R.drawable.fav_server3x) else painterResource(
  248. id = R.drawable.unfav_server3x),
  249. contentDescription = "Server Logo",
  250. tint = Color.Unspecified,
  251. )
  252. }
  253. }
  254. }
  255. }
  256. }
  257. Surface(
  258. modifier = Modifier
  259. .padding(start = 0.dp, end = 0.dp)
  260. .height(1.dp)
  261. .fillMaxWidth()
  262. .alpha(0.6F)
  263. .align(Alignment.BottomCenter)
  264. ,
  265. color = colorResource(id = R.color.gray_icon)
  266. ) {}
  267. }
  268. }
  269. @Composable
  270. fun ColumnScope.ExpandableRow(server: Server) {
  271. val context = LocalContext.current
  272. val serverListViewModel: ServerListViewModel = viewModel{
  273. ServerListViewModel(context)
  274. }
  275. val splashViewModel: SplashViewModel = viewModel{
  276. SplashViewModel(context)
  277. }
  278. Column(
  279. modifier = Modifier
  280. .padding(
  281. start = 40.dp, end = 26.dp,
  282. top = 2.dp, bottom = 28.dp
  283. )
  284. .background(Color.Transparent)
  285. ) {
  286. // var ping: Int = 0
  287. // Expandable Row
  288. server.countryServers?.let { serverData ->
  289. serverData.forEachIndexed { index, serverInfo ->
  290. Row(
  291. verticalAlignment = Alignment.CenterVertically,
  292. horizontalArrangement = Arrangement.Start,
  293. modifier = Modifier
  294. .fillMaxWidth()
  295. .padding(
  296. vertical = 15.dp
  297. )
  298. .background(Color.Transparent)
  299. .clickable(
  300. indication = null,
  301. interactionSource = remember { MutableInteractionSource() }
  302. ) {
  303. }
  304. ) {
  305. Text(text = serverInfo.server_name!!,
  306. style = TextStyle(
  307. fontSize = 16.sp,
  308. color = MaterialTheme.colorScheme.onSecondary
  309. ),
  310. modifier = Modifier
  311. .padding(start = 16.dp, bottom = 0.dp)
  312. .align(Alignment.CenterVertically)
  313. .alpha(0.4F)
  314. )
  315. Spacer(modifier = Modifier.weight(1F))
  316. // serverListViewModel.calculatePing(server)
  317. Text(text = "${serverInfo.ping} ms",
  318. style = TextStyle(
  319. fontSize = 16.sp,
  320. color = colorResource(id = R.color.blue_text),
  321. lineHeight = 30.sp,
  322. textAlign = TextAlign.Right
  323. ),
  324. modifier = Modifier
  325. .padding(start = 0.dp, end = 30.dp)
  326. .align(Alignment.CenterVertically)
  327. )
  328. var isFavorite by rememberSaveable {
  329. mutableStateOf(serverInfo.isFavourited)
  330. }
  331. IconButton(
  332. modifier = Modifier
  333. .padding(bottom = 0.dp, end = 16.dp)
  334. .size(21.dp, 20.dp)
  335. .align(Alignment.CenterVertically),
  336. onClick = {
  337. isFavorite = !isFavorite!!
  338. serverListViewModel.favAndUnFav(serverInfo)
  339. }
  340. )
  341. {
  342. val favResponse = serverListViewModel.mutableLiveDataFavUnFav.observeAsState().value
  343. favResponse?.let {
  344. Log.d("test_fav_response", it.message.toString())
  345. splashViewModel.serverDataApi()
  346. serverListViewModel.mutableLiveDataFavUnFav.value = null
  347. }
  348. Icon(
  349. // .clickable(
  350. // indication = null,
  351. // interactionSource = remember { MutableInteractionSource() }
  352. // ) { },
  353. painter = if (isFavorite == true) painterResource(
  354. id = R.drawable.fav_server3x) else painterResource(
  355. id = R.drawable.unfav_server3x),
  356. contentDescription = "Server Logo",
  357. tint = Color.Unspecified,
  358. )
  359. }
  360. }
  361. Surface(
  362. modifier = Modifier
  363. .padding(top = 0.dp, end = 0.dp)
  364. .height(1.dp)
  365. .fillMaxWidth()
  366. .alpha(0.6F)
  367. ,
  368. color = colorResource(id = R.color.gray_icon)
  369. ) {}
  370. }
  371. }
  372. }
  373. }
  374. fun calculatePing(server: Server, onPingResult: (Int) -> Unit) {
  375. Ping.onAddress(server.ip as String).setTimeOutMillis(1000).doPing(
  376. object : Ping.PingListener{
  377. override fun onResult(pingResult: PingResult?) {
  378. android.os.Handler(Looper.getMainLooper()).post {
  379. val ping = pingResult?.timeTaken?.toInt()!!
  380. onPingResult(ping)
  381. Log.d("test_ping", "ping[0] = $ping")
  382. }
  383. }
  384. override fun onError(e: java.lang.Exception?) {}
  385. override fun onFinished(pingStats: PingStats?) {}
  386. }
  387. )
  388. }
  389. @Preview
  390. @Composable
  391. fun CountryItemPreview() {
  392. CountryItem(server = favListServer[0], "servers")
  393. }