@@ -1,21 +1,33 @@
 
		
	
		
			
				package  ru.vendetti.bitcoin_summarizer  
		
	
		
			
				 
		
	
		
			
				import  android.annotation.SuppressLint  
		
	
		
			
				import  android.content.Context  
		
	
		
			
				import  android.content.pm.PackageManager  
		
	
		
			
				import  android.os.Bundle  
		
	
		
			
				import  android.util.Log  
		
	
		
			
				import  android.view.LayoutInflater  
		
	
		
			
				import  android.view.View  
		
	
		
			
				import  android.view.ViewGroup  
		
	
		
			
				import  androidx.activity.compose.rememberLauncherForActivityResult  
		
	
		
			
				import  androidx.activity.result.contract.ActivityResultContracts  
		
	
		
			
				import  androidx.compose.foundation.background  
		
	
		
			
				import  androidx.compose.foundation.layout.Box  
		
	
		
			
				import  androidx.compose.foundation.layout.Column  
		
	
		
			
				import  androidx.compose.foundation.layout.Spacer  
		
	
		
			
				import  androidx.compose.foundation.layout.fillMaxSize  
		
	
		
			
				import  androidx.compose.foundation.layout.fillMaxWidth  
		
	
		
			
				import  androidx.compose.foundation.layout.height  
		
	
		
			
				import  androidx.compose.foundation.layout.padding  
		
	
		
			
				import  androidx.compose.foundation.layout.wrapContentSize  
		
	
		
			
				import  androidx.compose.foundation.rememberScrollState  
		
	
		
			
				import  androidx.compose.foundation.shape.RoundedCornerShape  
		
	
		
			
				import  androidx.compose.foundation.verticalScroll  
		
	
		
			
				import  androidx.compose.material.icons.Icons  
		
	
		
			
				import  androidx.compose.material.icons.filled.Menu  
		
	
		
			
				import  androidx.compose.material.icons.filled.MoreVert   
		
	
		
			
				import  androidx.compose.material3.AlertDialog   
		
	
		
			
				import  androidx.compose.material3.ButtonColors  
		
	
		
			
				import  androidx.compose.material3.ButtonDefaults  
		
	
		
			
				import  androidx.compose.material3.Card  
		
	
		
			
				import  androidx.compose.material3.CenterAlignedTopAppBar  
		
	
		
			
				import  androidx.compose.material3.DrawerValue  
		
	
		
			
				import  androidx.compose.material3.ExperimentalMaterial3Api  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -23,11 +35,10 @@ import androidx.compose.material3.HorizontalDivider
 
		
	
		
			
				import  androidx.compose.material3.Icon  
		
	
		
			
				import  androidx.compose.material3.IconButton  
		
	
		
			
				import  androidx.compose.material3.MaterialTheme  
		
	
		
			
				import  androidx.compose.material3.MediumTopAppBar  
		
	
		
			
				import  androidx.compose.material3.ModalDrawerSheet  
		
	
		
			
				import  androidx.compose.material3.ModalNavigationDrawer  
		
	
		
			
				import  androidx.compose.material3.Scaffold  
		
	
		
			
				import  androidx.compose.material3.Text  
		
	
		
			
				import  androidx.compose.material3.TextButton  
		
	
		
			
				import  androidx.compose.material3.TopAppBarDefaults  
		
	
		
			
				import  androidx.compose.material3.rememberDrawerState  
		
	
		
			
				import  androidx.compose.material3.rememberTopAppBarState  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -42,13 +53,19 @@ import androidx.compose.runtime.setValue
 
		
	
		
			
				import  androidx.compose.ui.Alignment  
		
	
		
			
				import  androidx.compose.ui.Modifier  
		
	
		
			
				import  androidx.compose.ui.graphics.Color  
		
	
		
			
				import  androidx.compose.ui.graphics.vector.ImageVector  
		
	
		
			
				import  androidx.compose.ui.input.nestedscroll.nestedScroll  
		
	
		
			
				import  androidx.compose.ui.platform.ComposeView  
		
	
		
			
				import  androidx.compose.ui.platform.LocalContext  
		
	
		
			
				import  androidx.compose.ui.text.style.TextAlign  
		
	
		
			
				import  androidx.compose.ui.text.style.TextOverflow  
		
	
		
			
				import  androidx.compose.ui.tooling.preview.Preview  
		
	
		
			
				import  androidx.compose.ui.unit.dp  
		
	
		
			
				import  androidx.compose.ui.unit.sp  
		
	
		
			
				import  androidx.compose.ui.window.Dialog  
		
	
		
			
				import  androidx.core.content.ContextCompat  
		
	
		
			
				import  androidx.fragment.app.Fragment  
		
	
		
			
				import  com.google.gson.Gson  
		
	
		
			
				import  com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost  
		
	
		
			
				import  com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent  
		
	
		
			
				import  com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLineComponent  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -80,6 +97,9 @@ import kotlinx.coroutines.launch
 
		
	
		
			
				import  ru.vendetti.bitcoin_summarizer.ui.theme.BitcoinSummarizerTheme  
		
	
		
			
				import  ru.vendetti.bitcoin_summarizer.ui.theme.Flame  
		
	
		
			
				import  ru.vendetti.bitcoin_summarizer.ui.theme.Green2  
		
	
		
			
				import  java.io.FileInputStream  
		
	
		
			
				import  java.io.FileOutputStream  
		
	
		
			
				import  java.lang.StringBuilder  
		
	
		
			
				import  java.text.DecimalFormat  
		
	
		
			
				import  java.time.Instant  
		
	
		
			
				import  java.time.format.DateTimeFormatter  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -102,11 +122,51 @@ class CryptoFragment: Fragment() {
 
		
	
		
			
				    } 
 
		
	
		
			
				}  
		
	
		
			
				 
		
	
		
			
				@Composable  
		
	
		
			
				fun  ShowAlertDialog (  
		
	
		
			
				    onDismissRequest :  ( )  ->  Unit , 
 
		
	
		
			
				    onConfirmation :  ( )  ->  Unit , 
 
		
	
		
			
				    dialogTitle :  String , 
 
		
	
		
			
				    dialogText :  String , 
 
		
	
		
			
				)  {  
		
	
		
			
				    AlertDialog ( 
 
		
	
		
			
				        icon  =  { } , 
 
		
	
		
			
				        title  =  { 
 
		
	
		
			
				            Text ( text  =  dialogTitle ) 
 
		
	
		
			
				        } , 
 
		
	
		
			
				        text  =  { 
 
		
	
		
			
				            Text ( text  =  dialogText ) 
 
		
	
		
			
				        } , 
 
		
	
		
			
				        onDismissRequest  =  { 
 
		
	
		
			
				            onDismissRequest ( ) 
 
		
	
		
			
				        } , 
 
		
	
		
			
				        confirmButton  =  { } , 
 
		
	
		
			
				        dismissButton  =  { 
 
		
	
		
			
				            TextButton ( 
 
		
	
		
			
				                onClick  =  { 
 
		
	
		
			
				                    onDismissRequest ( ) 
 
		
	
		
			
				                } 
 
		
	
		
			
				            )  { 
 
		
	
		
			
				                Text ( 
 
		
	
		
			
				                    text  =  " Окей " , 
 
		
	
		
			
				                    color  =  MaterialTheme . colorScheme . onPrimary 
 
		
	
		
			
				                ) 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } , 
 
		
	
		
			
				        containerColor  =  MaterialTheme . colorScheme . primary , 
 
		
	
		
			
				        titleContentColor  =  MaterialTheme . colorScheme . onPrimary , 
 
		
	
		
			
				        textContentColor  =  MaterialTheme . colorScheme . onPrimary , 
 
		
	
		
			
				    ) 
 
		
	
		
			
				}  
		
	
		
			
				 
		
	
		
			
				@SuppressLint ( " MutableCollectionMutableState " ,  " SimpleDateFormat " )  
		
	
		
			
				@OptIn ( ExperimentalMaterial3Api :: class )  
		
	
		
			
				@Preview  
		
	
		
			
				@Composable  
		
	
		
			
				fun  CryptoComposable ( )  {  
		
	
		
			
				    val  openAlertDialog1  =  remember  {  mutableStateOf ( false )  } 
 
		
	
		
			
				    val  openAlertDialog2  =  remember  {  mutableStateOf ( false )  } 
 
		
	
		
			
				 
		
	
		
			
				    // Создаем репозиторий для работы с  
 
		
	
		
			
				val  cryptoRepository  =  remember  {  CryptoRepository ( RetrofitClient . apiService )  }  
		
	
		
			
				    // Состояния для хранения результатов запросов 
 
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -116,8 +176,36 @@ fun CryptoComposable() {
 
		
	
		
			
				 
		
	
		
			
				    var  fearGreedIndexDaysCount  by  remember  {  mutableIntStateOf ( 30 )  } 
 
		
	
		
			
				 
		
	
		
			
				    val  gson  =  Gson ( ) 
 
		
	
		
			
				 
		
	
		
			
				    val  context  =  LocalContext . current 
 
		
	
		
			
				 
		
	
		
			
				    when  { 
 
		
	
		
			
				        openAlertDialog1 . value  ->  { 
 
		
	
		
			
				            ShowAlertDialog ( 
 
		
	
		
			
				                onDismissRequest  =  { openAlertDialog1 . value  =  false } , 
 
		
	
		
			
				                onConfirmation  =  { } , 
 
		
	
		
			
				                dialogTitle  =  " Внимание! " , 
 
		
	
		
			
				                dialogText  =  " Отсутствует интернет-подключение, загружаю сохраненные данные.  "  + 
 
		
	
		
			
				                        " "  + 
 
		
	
		
			
				                        " Обратите внимание, что данные могут быть неактуальными. " , 
 
		
	
		
			
				            ) 
 
		
	
		
			
				        } 
 
		
	
		
			
				        openAlertDialog2 . value  ->  { 
 
		
	
		
			
				            ShowAlertDialog ( 
 
		
	
		
			
				                onDismissRequest  =  { 
 
		
	
		
			
				                    openAlertDialog2 . value  =  false 
 
		
	
		
			
				                    App . INSTANCE . router . exit ( ) 
 
		
	
		
			
				                                   } , 
 
		
	
		
			
				                onConfirmation  =  { } , 
 
		
	
		
			
				                dialogTitle  =  " Внимание! " , 
 
		
	
		
			
				                dialogText  =  " При первом подключении необходимо подключение к интернету! " , 
 
		
	
		
			
				            ) 
 
		
	
		
			
				        } 
 
		
	
		
			
				    } 
 
		
	
		
			
				 
		
	
		
			
				    // Запускаем корутину для выполнения сетевых запросов 
 
		
	
		
			
				LaunchedEffect ( fearGreedIndexDaysCount )  {  
		
	
		
			
				LaunchedEffect ( fearGreedIndexDaysCount ,  context {  
		
	
		
			
				        try  { 
 
		
	
		
			
				            // Запрос Bitcoin Ticker 
 
		
	
		
			
				val  tickerResponse  =  cryptoRepository . fetchBitcoinTicker ( )  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -131,31 +219,53 @@ fun CryptoComposable() {
 
		
	
		
			
				val  fearResponse  =  cryptoRepository . fetchFearAndGreedData ( fearGreedIndexDaysCount )  
		
	
		
			
				            fearGreedDataList  =  fearResponse ?. dataList  as  ArrayList < FearAndGreedData > 
 
		
	
		
			
				            fearGreedDataList . reverse ( ) 
 
		
	
		
			
				        } catch  ( e :  Exception )  { 
 
		
	
		
			
				            bitcoinTicker  =  TickerData ( 
 
		
	
		
			
				                id  =  " " ,  
 
		
	
		
			
				                name  =  " "  , 
 
		
	
		
			
				                symbol  =  " " , 
 
		
	
		
			
				                rank  =  " " , 
 
		
	
		
			
				                priceUsd  =  " " , 
 
		
	
		
			
				                priceBtc  =  " " , 
 
		
	
		
			
				                volume24hUsd  =  " " , 
 
		
	
		
			
				                marketCapUsd  =  " " , 
 
		
	
		
			
				                availableSupply  =  " " , 
 
		
	
		
			
				                totalSupply  =  " " , 
 
		
	
		
			
				                maxSupply  =  " " , 
 
		
	
		
			
				                percentChange1h  =  " " , 
 
		
	
		
			
				                percentChange24h  =  " " , 
 
		
	
		
			
				                percentChange7d  =  " " , 
 
		
	
		
			
				                lastUpdated  =  " " 
 
		
	
		
			
				 
		
	
		
			
				            // *** Сохраняем на диск *** 
 
		
	
		
			
				// 1) С б о р   
		
	
		
			
				val  fullStatistics  =  StatisticsFull (  
		
	
		
			
				                FGI _list  =  fearGreedDataList , 
 
		
	
		
			
				                TickerData  =  bitcoinTicker , 
 
		
	
		
			
				                GlobalData  =  globalData , 
 
		
	
		
			
				            ) 
 
		
	
		
			
				            globalData  =  GlobalResponse ( 
 
		
	
		
			
				                activeCryptocurrencies  =  " " ,  
 
		
	
		
			
				                totalMarketCapUsd  =  " "  , 
 
		
	
		
			
				                total24hVolumeUsd  =  " " , 
 
		
	
		
			
				                bitcoinPercentageOfMarketCap  =  " "  
 
		
	
		
			
				            ) 
 
		
	
		
			
				            fearGreedDataList  =  ArrayList < FearAndGreedData > ( ) 
 
		
	
		
			
				 
		
	
		
			
				            // 2) Перевод класса в json-строку 
 
		
	
		
			
				val  statisticsJsonString  =  gson . toJson ( fullStatistics )  
		
	
		
			
				 
		
	
		
			
				            // 3) Сохранение в файл во внутреннем хранилище 
 
		
	
		
			
				val  fos :  FileOutputStream  =  
		
	
		
			
				                context . openFileOutput ( " statistics.txt " ,  Context . MODE _PRIVATE  ) 
 
		
	
		
			
				            fos . write ( statisticsJsonString . toByteArray ( ) ) 
 
		
	
		
			
				            fos . flush ( ) 
 
		
	
		
			
				            fos . close ( ) 
 
		
	
		
			
				        } 
 
		
	
		
			
				        catch  ( e :  Exception )  { 
 
		
	
		
			
				            try  { 
 
		
	
		
			
				                // *** Загрузка данных из файла *** 
 
		
	
		
			
				// 1) Получение строки из файла  
		
	
		
			
				val  fis :  FileInputStream  =  
		
	
		
			
				                    context . openFileInput ( " statistics.txt " ) 
 
		
	
		
			
				                var  a :  Int 
 
		
	
		
			
				                val  temp  =  StringBuilder ( ) 
 
		
	
		
			
				                while  ( fis . read ( ) . also  {  a  =  it  }  !=  - 1 )  { 
 
		
	
		
			
				                    temp . append ( a . toChar ( ) ) 
 
		
	
		
			
				                } 
 
		
	
		
			
				 
		
	
		
			
				                // Показ предупреждения. 
 
		
	
		
			
				openAlertDialog1 . value  =  true  
		
	
		
			
				 
		
	
		
			
				                val  statisticsJsonString  =  temp . toString ( ) 
 
		
	
		
			
				 
		
	
		
			
				                // 2) Перевод строки в класс 
 
		
	
		
			
				val  statisticsFull  =  gson . fromJson ( statisticsJsonString ,  StatisticsFull :: class . java )  
		
	
		
			
				 
		
	
		
			
				                // 3) Распределение данных по переменным 
 
		
	
		
			
				bitcoinTicker  =  statisticsFull . TickerData  
		
	
		
			
				                globalData  =  statisticsFull . GlobalData 
 
		
	
		
			
				                fearGreedDataList  =  statisticsFull . FGI _list 
 
		
	
		
			
				            } 
 
		
	
		
			
				            catch  ( e :  Exception )  { 
 
		
	
		
			
				                openAlertDialog2 . value  =  true 
 
		
	
		
			
				            } 
 
		
	
		
			
				        } 
 
		
	
		
			
				    }