// MainActivity.java
package com.example.myapplication;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.github.mikephil.charting.charts.LineChart; // Импортируем LineChart
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry; // Для данных графика
import com.github.mikephil.charting.data.LineData; // Для данных графика
import com.github.mikephil.charting.data.LineDataSet; // Для данных графика
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.ColorTemplate;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    private Spinner spinnerFrom;
    private Spinner spinnerTo;
    private EditText inputFrom;
    private EditText inputTo;
    private ProgressBar loadingIndicator;
    private CurrencyRepository repository;
    private boolean isRatesLoaded = false;

    private LineChart lineChart; // Добавляем линейный график

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        repository = new CurrencyRepository(this);
        spinnerFrom = findViewById(R.id.spinner_from);
        spinnerTo = findViewById(R.id.spinner_to);
        inputFrom = findViewById(R.id.input_from);
        inputTo = findViewById(R.id.input_to);
        loadingIndicator = findViewById(R.id.loading_indicator);
        lineChart = findViewById(R.id.line_chart); // Инициализируем график

        new LoadCurrenciesTask().execute();

        inputFrom.addTextChangedListener(new TextWatcher() {
            // ... (как и ранее)
        });

        AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (isRatesLoaded) {
                    performConversion();
                    loadChartData(); // Загрузить данные для графика при изменении выбора
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        };

        spinnerFrom.setOnItemSelectedListener(spinnerListener);
        spinnerTo.setOnItemSelectedListener(spinnerListener);
    }

    // ...

    private void loadChartData() {
        String fromCurrency = spinnerFrom.getSelectedItem().toString();
        String toCurrency = spinnerTo.getSelectedItem().toString();

        new LoadChartDataTask(fromCurrency, toCurrency).execute();
    }

    private class LoadChartDataTask extends AsyncTask<Void, Void, LineData> {
        private final String fromCurrency;
        private final String toCurrency;

        public LoadChartDataTask(String fromCurrency, String toCurrency) {
            this.fromCurrency = fromCurrency;
            this.toCurrency = toCurrency;
        }

        @Override
        protected LineData doInBackground(Void... voids) {
            List<CurrencyRateHistory> historyList = repository.getCurrencyRateHistory(fromCurrency, toCurrency);
            if (historyList == null || historyList.isEmpty()) {
                return null;
            }

            // Создаем список точек для графика
            List<Entry> entries = new java.util.ArrayList<>();

            for (int i = 0; i < historyList.size(); i++) {
                CurrencyRateHistory history = historyList.get(i);
                // Используем индекс как x-координату, а курс как y-координату
                entries.add(new Entry(i, (float) history.rate));
            }

            LineDataSet dataSet = new LineDataSet(entries, "Курс "+fromCurrency + "/" + toCurrency);
            dataSet.setColor(ColorTemplate.getHoloBlue());
            dataSet.setCircleColor(ColorTemplate.getHoloBlue());
            dataSet.setLineWidth(1.5f);
            dataSet.setCircleRadius(3f);
            dataSet.setDrawCircleHole(false);
            dataSet.setValueTextSize(9f);
            dataSet.setDrawFilled(true);
            dataSet.setFillColor(ColorTemplate.getHoloBlue());

            return new LineData(dataSet);
        }

        @Override
        protected void onPostExecute(LineData lineData) {
            if (lineData != null) {
                lineChart.setData(lineData);

                // Настраиваем ось X для отображения дат
                XAxis xAxis = lineChart.getXAxis();
                xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
                xAxis.setGranularity(1f);
                xAxis.setValueFormatter(new ValueFormatter() {
                    @Override
                    public String getFormattedValue(float value) {
                        int index = (int) value;
                        List<CurrencyRateHistory> historyList = repository.getCurrencyRateHistory(fromCurrency, toCurrency);
                        if (index >= 0 && index < historyList.size()) {
                            Date date = historyList.get(index).date;
                            return new SimpleDateFormat("dd.MM", Locale.getDefault()).format(date);
                        } else {
                            return "";
                        }
                    }
                });

                lineChart.invalidate(); // обновляем график
            } else {
                lineChart.clear();
                lineChart.invalidate();
                showToast("Нет данных для отображения графика");
            }
        }
    }

    // Остальной код как и ранее...
}  package com.example.myapplication;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.LineData;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private Spinner spinnerFrom;
    private Spinner spinnerTo;
    private EditText inputFrom;
    private EditText inputTo;
    private ProgressBar loadingIndicator;
    private CurrencyRepository repository;
    private boolean isRatesLoaded = false;

    private LineChart lineChart; // Добавляем линейный график

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        repository = new CurrencyRepository(this);
        spinnerFrom = findViewById(R.id.spinner_from);
        spinnerTo = findViewById(R.id.spinner_to);
        inputFrom = findViewById(R.id.input_from);
        inputTo = findViewById(R.id.input_to);
        loadingIndicator = findViewById(R.id.loading_indicator);
        lineChart = findViewById(R.id.line_chart); // Инициализируем график

        new LoadChartDataTask.LoadCurrenciesTask().execute();

        inputFrom.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

            @Override
            public void afterTextChanged(Editable s) {
                if (isRatesLoaded) {
                    performConversion();
                } else {
                    showToast("Подождите, пока загрузятся курсы валют.");
                }
            }
        });

        AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (isRatesLoaded) {
                    performConversion();
                    loadChartData(); // Загрузить данные для графика при изменении выбора
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {}
        };

        spinnerFrom.setOnItemSelectedListener(spinnerListener);
        spinnerTo.setOnItemSelectedListener(spinnerListener);
    }

        spinnerFrom.setOnItemSelectedListener(spinnerListener);
        spinnerTo.setOnItemSelectedListener(spinnerListener);
    }

    private void loadChartData() {
        String fromCurrency = spinnerFrom.getSelectedItem().toString();
        String toCurrency = spinnerTo.getSelectedItem().toString();

        new LoadChartDataTask(fromCurrency, toCurrency).execute();
    }

    private class LoadChartDataTask extends AsyncTask<Void, Void, LineData> {
        private final String fromCurrency;
        private final String toCurrency;

        public LoadChartDataTask(String fromCurrency, String toCurrency) {
            this.fromCurrency = fromCurrency;
            this.toCurrency = toCurrency;
        }

        @Override
        protected LineData doInBackground(Void... voids) {
            return null;
        }

        private class LoadCurrenciesTask extends AsyncTask<Void, Void, List<String>> {
        @Override
        protected void onPreExecute() {
            loadingIndicator.setVisibility(View.VISIBLE);
        }

        @Override
        protected LineData doInBackground(Void... voids) {
            List<CurrencyRateHistory> historyList = repository.getCurrencyRateHistory(fromCurrency, toCurrency);
            if (historyList == null || historyList.isEmpty()) {
                return null;
            }

            // Создаем список точек для графика
            List<Entry> entries = new java.util.ArrayList<>();

            for (int i = 0; i < historyList.size(); i++) {
                CurrencyRateHistory history = historyList.get(i);
                // Используем индекс как x-координату, а курс как y-координату
                entries.add(new Entry(i, (float) history.rate));
            }

            LineDataSet dataSet = new LineDataSet(entries, "Курс "+fromCurrency + "/" + toCurrency);
            dataSet.setColor(ColorTemplate.getHoloBlue());
            dataSet.setCircleColor(ColorTemplate.getHoloBlue());
            dataSet.setLineWidth(1.5f);
            dataSet.setCircleRadius(3f);
            dataSet.setDrawCircleHole(false);
            dataSet.setValueTextSize(9f);
            dataSet.setDrawFilled(true);
            dataSet.setFillColor(ColorTemplate.getHoloBlue());

            return new LineData(dataSet);
        }

        @Override
        protected void onPostExecute(LineData lineData) {
            if (lineData != null) {
                lineChart.setData(lineData);

                // Настраиваем ось X для отображения дат
                XAxis xAxis = lineChart.getXAxis();
                xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
                xAxis.setGranularity(1f);
                xAxis.setValueFormatter(new ValueFormatter() {
                    @Override
                    public String getFormattedValue(float value) {
                        int index = (int) value;
                        List<CurrencyRateHistory> historyList = repository.getCurrencyRateHistory(fromCurrency, toCurrency);
                        if (index >= 0 && index < historyList.size()) {
                            Date date = historyList.get(index).date;
                            return new SimpleDateFormat("dd.MM", Locale.getDefault()).format(date);
                        } else {
                            return "";
                        }
                    }
                });

                lineChart.invalidate(); // обновляем график
            } else {
                lineChart.clear();
                lineChart.invalidate();
                showToast("Нет данных для отображения графика");
            }
        }
    }

    private void performConversion() {
        String fromCurrency = spinnerFrom.getSelectedItem().toString();
        String toCurrency = spinnerTo.getSelectedItem().toString();
        String amountStr = inputFrom.getText().toString();

        if (amountStr.isEmpty()) {
            inputTo.setText("");
            return;
        }

        if (fromCurrency.equals(toCurrency)) {
            inputTo.setText(amountStr);
            return;
        }

        try {
            double amount = Double.parseDouble(amountStr);

            // Perform conversion
            new ConvertCurrencyTask(fromCurrency, toCurrency, amount, repository, result -> {
                if (result != null) {
                    inputTo.setText(String.format("%.2f", result));
                } else {
                    showToast("Ошибка при конвертации валюты: Курс не найден");
                    inputTo.setText("");
                }
            }).execute();
        } catch (NumberFormatException e) {
            inputTo.setText("");
        }
    }

    private void showToast(String message) {
        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
    }
}
 скинь полный код исправленный