diff --git a/app/src/main/java/com/example/trippe/MainActivity.java b/app/src/main/java/com/example/trippe/MainActivity.java index 65f9d58..38fde85 100644 --- a/app/src/main/java/com/example/trippe/MainActivity.java +++ b/app/src/main/java/com/example/trippe/MainActivity.java @@ -7,7 +7,8 @@ import android.os.Bundle; import android.os.StrictMode; import android.util.Log; - +import com.example.trippe.dao.CurrencyDao; +import com.example.trippe.ui.currency.AsyncRateRequest; import com.example.trippe.util.Utility; import com.google.android.material.bottomnavigation.BottomNavigationView; import androidx.appcompat.app.AppCompatActivity; @@ -30,10 +31,6 @@ public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //TODO Remove this and implement a threaded query for web stuff - StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(policy); - if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { // No permissions lets request them @@ -90,5 +87,8 @@ protected void onCreate(Bundle savedInstanceState) { finally { trippeDatabase.close(); } + CurrencyDao currencyDao = new CurrencyDao(); + currencyDao.makeTableRates(true); + new AsyncRateRequest().execute(); // execute rate updates via asynchronous web api request } } diff --git a/app/src/main/java/com/example/trippe/dao/CurrencyDao.java b/app/src/main/java/com/example/trippe/dao/CurrencyDao.java new file mode 100644 index 0000000..e49a2fd --- /dev/null +++ b/app/src/main/java/com/example/trippe/dao/CurrencyDao.java @@ -0,0 +1,278 @@ +package com.example.trippe.dao; + +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; + +import com.example.trippe.model.TrippeCurrency; +import com.example.trippe.ui.currency.WebAPIRequest; +import com.example.trippe.util.Utility; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + + +public class CurrencyDao { + private final String dbPath = "/data/data/com.example.trippe/databases/TrippeDatabase"; + public CurrencyDao() { + } + + public TrippeCurrency getCurrencyHistory(String startDate, String endDate, String currency) { + /* query db for all entries between start and end date for both currencies unless one is usd + store results in array of TrippeCurrency + count number of entries + figure out missing dates + get request api for missing dates, if failure, fill with empty data + */ + SQLiteDatabase db = null; + TrippeCurrency _currency = new TrippeCurrency(currency); + Date date; + + + try { + db = SQLiteDatabase.openDatabase(this.dbPath, null, 0); + + try { + Cursor cursor = db.rawQuery("SELECT * FROM tbl_daily_rate WHERE tbl_daily_rate.currency_abbrev = '" + + currency + + "' AND tbl_daily_rate.date BETWEEN '" + + startDate + + "' AND '" + + endDate + "' ORDER BY tbl_daily_rate.date ASC;", null); + Log.i("getCurrencyHistory", "Got " + cursor.getCount() + " entries for " + currency); + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + Log.i("getCurrencyHistory:", cursor.getString(cursor.getColumnIndex("date")) + " | " + + cursor.getString(cursor.getColumnIndex("currency_abbrev")) + " | " + + cursor.getString(cursor.getColumnIndex("exchange_rate"))); + // Now to do the actual work: + date = this.getDateFromString(cursor.getString(cursor.getColumnIndex("date"))); + _currency.addRate(date, cursor.getDouble(cursor.getColumnIndex("exchange_rate"))); + cursor.moveToNext(); + } + } catch (Exception e) { + Log.e("getCurrencyHistory sql query", e.toString(), e); + if (db.isOpen()) { // probably redundant + db.close(); + } + } finally { + db.close(); + } + return _currency; + } catch (Exception e) { + Log.e("getCurrencyHistory openDatabase", e.toString(), e); + + } + return _currency; + } + + /*public double convertCurrency(String fromCurrency, String toCurrency) { + /query db for all entries between start and end date for both currencies unless one is usd + store results in array of TrippeCurrency + count number of entries + figure out missing dates + get request api for missing dates, if failure, fill with empty data + + SQLiteDatabase db = null; + TrippeCurrency _currency = new TrippeCurrency(currency); + Date date; + + + try { + db = SQLiteDatabase.openDatabase(this.dbPath, null, 0); + + try { + Cursor cursor = db.rawQuery("SELECT * FROM tbl_daily_rate WHERE tbl_daily_rate.currency_abbrev = '" + + currency + + "' AND tbl_daily_rate.date = " + + WebAPIRequest.getTodaysDate() + + ";", null); + Log.i("getCurrencyHistory", "Got " + cursor.getCount() + " entries for " + currency); + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + Log.i("getCurrencyHistory:", cursor.getString(cursor.getColumnIndex("date")) + " | " + + cursor.getString(cursor.getColumnIndex("currency_abbrev")) + " | " + + cursor.getString(cursor.getColumnIndex("exchange_rate"))); + // Now to do the actual work: + date = this.getDateFromString(cursor.getString(cursor.getColumnIndex("date"))); + _currency.addRate(date, cursor.getDouble(cursor.getColumnIndex("exchange_rate"))); + cursor.moveToNext(); + } + } catch (Exception e) { + Log.e("getCurrencyHistory sql query", e.toString(), e); + if (db.isOpen()) { // probably redundant + db.close(); + } + } finally { + db.close(); + } + return _currency; + } catch (Exception e) { + Log.e("getCurrencyHistory openDatabase", e.toString(), e); + + } + return _currency; + } +*/ + public double selectCurrencyRate(String date, String currency){ + SQLiteDatabase db = null; + double rate = 0.0; + int daysAgo = 0; + int maxAge = 5; + try { + db = SQLiteDatabase.openDatabase(this.dbPath, null, 0); + if (WebAPIRequest.invalidDate(date)) { + date = Utility.getTodaysDate(); } + + while (rate == 0 && daysAgo < maxAge) { + String query = "SELECT * FROM tbl_daily_rate WHERE tbl_daily_rate.currency_abbrev = '" + + currency + + "' AND tbl_daily_rate.date = '" + + date + + "';"; + try { + Log.i("selectCurrencyRate", "Query: " + query); + Cursor cursor = db.rawQuery(query, null); + Log.i("selectCurrencyRate", "Got " + cursor.getCount() + " entries for " + currency); + cursor.moveToFirst(); + while (!cursor.isAfterLast()) { + Log.i("selectCurrencyRate", cursor.getString(cursor.getColumnIndex("date")) + " | " + + cursor.getString(cursor.getColumnIndex("currency_abbrev")) + " | " + + cursor.getString(cursor.getColumnIndex("exchange_rate"))); + // now do the actual work: + rate = cursor.getDouble(cursor.getColumnIndex("exchange_rate")); + cursor.moveToNext(); + } + } catch (Exception e) { + Log.e("selectCurrencyRate", e.toString(), e); + if (db.isOpen()) { // probably redundant + db.close(); + } + } + daysAgo++; + date = Utility.getDateAgo(daysAgo); + } + if (db.isOpen()) { + db.close(); + } + Log.i("selectCurrencyRate", "days Ago: " + (daysAgo - 1)); + return rate; + } catch (Exception e) { + Log.e("selectCurrencyRate", e.toString(), e); + + } + return rate; + } + + + public void insertRate(String currency, double rate, String date) { + SQLiteDatabase db = null; + long rowId = 0; + ContentValues tblRow = new ContentValues(); + tblRow.put("currency_abbrev", currency); + tblRow.put("exchange_rate", rate); + tblRow.put("date", date); + + try { + db = SQLiteDatabase.openDatabase(this.dbPath, null, 0); + + try { + rowId = db.insert("tbl_daily_rate", "", tblRow); + Log.i("insertRate", "Inserted tblRow into tbl_daily_rate"); + } catch (Exception e) { + Log.e("insertRate", e.toString(), e); + } finally { + Log.i("insertRate", "Row ID: " + String.valueOf(rowId)); + db.close(); + } + } catch (Exception e) { + Log.e("insertRate", e.toString(), e); + + } + } + //String get currency abbrev by country name (string country name) + + public void updateHistory(int daysAgo) { + /* check latest db dates + compare to now + get missing days + insert missing days + fill in days with no data + update previous missing days + */ + WebAPIRequest request = new WebAPIRequest(); + request.setUrl("USD", Utility.getDateAgo(daysAgo), Utility.getTodaysDate()); + Log.i("updateHistory", "Calling getHistoryAsMap"); + Map currencyMap; + currencyMap = request.getHistoryAsMap(); + for (String currency : currencyMap.keySet()) { + Map rates = currencyMap.get(currency).getRates(); + for (Date date : rates.keySet()){ + Log.i("updateHistory", "Inserting: " + currency + " " + rates.get(date) + " " + this.getStringFromDate(date)); + this.insertRate(currency, rates.get(date), this.getStringFromDate(date)); + } + } + } + + public void makeTableRates(boolean overwrite) { + // delete and recreate currency table + SQLiteDatabase db = null; + + // create tbl_daily_rate + try { + db = SQLiteDatabase.openDatabase(this.dbPath, null, 0); + try { + if (overwrite) { + db.execSQL("DROP TABLE IF EXISTS tbl_daily_rate"); + Log.i("makeTableRates", "Deleting old table"); + } + db.execSQL("CREATE TABLE IF NOT EXISTS " + "tbl_daily_rate (" + + "date VARCHAR(11) NOT NULL," + + "currency_abbrev VARCHAR(3) NOT NULL," + + "exchange_rate REAL NOT NULL," + + "PRIMARY KEY (date, currency_abbrev));"); + Log.i("makeTableRates", "Creating new table"); + } catch (Exception e) { + Log.e("makeTableRates", e.toString(), e); + } finally { + db.close(); + } + } + catch(Exception e){ + Log.e("makeTableRates", e.getMessage(), e); + db = null; + } + finally { + if (db != null) { + db.close(); + } + } + } + public void replaceEntry(){ + + } + + public Date getDateFromString(String inDate) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + Date date; + try { + date = df.parse(inDate); + return date; + } catch (ParseException e) { + Log.w("getDateFromString", "Date: " + inDate + " is invalid"); + date = new Date(); + return date; + } + } + + public String getStringFromDate(Date date) { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + String strDate; + strDate = df.format(date); + return strDate; + } +} diff --git a/app/src/main/java/com/example/trippe/ui/currency/TrippeCurrency.java b/app/src/main/java/com/example/trippe/model/TrippeCurrency.java similarity index 62% rename from app/src/main/java/com/example/trippe/ui/currency/TrippeCurrency.java rename to app/src/main/java/com/example/trippe/model/TrippeCurrency.java index 8287931..626e912 100644 --- a/app/src/main/java/com/example/trippe/ui/currency/TrippeCurrency.java +++ b/app/src/main/java/com/example/trippe/model/TrippeCurrency.java @@ -1,6 +1,8 @@ -package com.example.trippe.ui.currency; +package com.example.trippe.model; import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; public class TrippeCurrency { @@ -11,19 +13,19 @@ public class TrippeCurrency { private String country; public TrippeCurrency() { - + this.rates = new HashMap(); } public TrippeCurrency(String abbreviation ) { this.abbreviation = abbreviation; + this.rates = new HashMap(); + } public TrippeCurrency(String abbreviation, String name) { this.abbreviation = abbreviation; this.name = name; - } - - public void sortDates() { + this.rates = new HashMap(); } @@ -39,6 +41,22 @@ public String getCountry() { return this.country; } + public Iterator keys() { + return this.rates.keySet().iterator(); + } + + public double getRate(Date date) { + double rate = 0; + if (rates.containsKey(date)) { + return rates.get(date); + } + return rate; + } + + public Integer getSize() { + return this.rates.size(); + } + public long getFlagResourceId(){ return this.flagResourceid; } @@ -47,7 +65,13 @@ public void addRate(Date date, Double rate) { this.rates.put(date, rate); } + public Map getRates() { + return rates; + } + public void setAbbreviation(String abbrev){ this.abbreviation = abbrev; } + + } diff --git a/app/src/main/java/com/example/trippe/ui/currency/AsyncRateRequest.java b/app/src/main/java/com/example/trippe/ui/currency/AsyncRateRequest.java new file mode 100644 index 0000000..94afed0 --- /dev/null +++ b/app/src/main/java/com/example/trippe/ui/currency/AsyncRateRequest.java @@ -0,0 +1,22 @@ +package com.example.trippe.ui.currency; + +import android.content.Context; +import android.os.AsyncTask; +import android.text.PrecomputedText; +import android.util.Log; +import android.widget.Toast; + +import com.example.trippe.dao.CurrencyDao; + +import androidx.appcompat.app.AppCompatActivity; + +public class AsyncRateRequest extends AsyncTask { + @Override + protected Void doInBackground(Void... voids) { + CurrencyDao currencyDao = new CurrencyDao(); + Log.i("AsyncRateRequest", "Starting async task"); + currencyDao.updateHistory(10); + Log.i("AsyncRateRequest", "Finished async task"); + return null; + } +} diff --git a/app/src/main/java/com/example/trippe/ui/currency/CurrencyDAO.java b/app/src/main/java/com/example/trippe/ui/currency/CurrencyDAO.java deleted file mode 100644 index cbcc15f..0000000 --- a/app/src/main/java/com/example/trippe/ui/currency/CurrencyDAO.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.trippe.ui.currency; - -public class CurrencyDAO { - -} diff --git a/app/src/main/java/com/example/trippe/ui/currency/CurrencyFragment.java b/app/src/main/java/com/example/trippe/ui/currency/CurrencyFragment.java index a424d34..9afc8e4 100644 --- a/app/src/main/java/com/example/trippe/ui/currency/CurrencyFragment.java +++ b/app/src/main/java/com/example/trippe/ui/currency/CurrencyFragment.java @@ -1,6 +1,5 @@ package com.example.trippe.ui.currency; -import android.graphics.Color; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -18,13 +17,13 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProviders; import com.example.trippe.R; +import com.example.trippe.dao.CurrencyDao; import com.example.trippe.util.Utility; import com.jjoe64.graphview.GraphView; +import com.jjoe64.graphview.LegendRenderer; import com.jjoe64.graphview.series.DataPoint; import com.jjoe64.graphview.series.LineGraphSeries; -import java.lang.reflect.Field; import java.text.DecimalFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -40,14 +39,7 @@ public class CurrencyFragment extends Fragment implements Spinner.OnItemSelected private TextView txtResult; private ImageView imgFromFlag; private ImageView imgToFlag; - private long now; - private long ago; - // How many milliseconds in 1 day - private final long DAY_IN_MILLIS = 86400000; - private SimpleDateFormat formatter; private GraphView currencyGraph; - private LineGraphSeries series; - private final TextWatcher txtFromAmountWatcher = new TextWatcher() { @Override @@ -90,9 +82,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, this.dropToCurrency.setOnItemSelectedListener(this); this.txtFromAmount.addTextChangedListener(txtFromAmountWatcher); - //Format needed for web api query - this.formatter = new SimpleDateFormat("yyyy-MM-dd"); - //------------------------------------------ // The following block sets up our list of items to populate into the dropdown menus //------------------------------------------ @@ -107,6 +96,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, options.add(this.currencyOptions[i]); } + // update our rates in the database + // TODO make this a little smarter maybe? + new AsyncRateRequest().execute(); + + + // Creating adapter for spinner ArrayAdapter currencyAdapter = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_item, options); @@ -126,23 +121,10 @@ public View onCreateView(@NonNull LayoutInflater inflater, //------------------------------------------- // Testing a graph of currency histories //------------------------------------------- + // populate our data this.currencyGraph = (GraphView) view.findViewById(R.id.currencyGraph); this.currencyGraph.setTitle("10 Day History"); - this.series = new LineGraphSeries();/*new DataPoint[] { - new DataPoint(-10, 0), - new DataPoint(-9, 0), - new DataPoint(-8, 0), - new DataPoint(-7, 0), - new DataPoint(-6, 0), - new DataPoint(-5, 0), - new DataPoint(-4, 0), - new DataPoint(-3, 0), - new DataPoint(-2, 0), - new DataPoint(-1, 0), - new DataPoint(0, 0) - });*/ - - this.currencyGraph.addSeries(series); + return view; } @@ -163,6 +145,58 @@ private void setFlag(ImageView imgView, String currency) { } + private void setCurrencyGraph() { + CurrencyDao currencyDao = new CurrencyDao(); + int entries = 11; + // our data to be returned to graph + LineGraphSeries rateSeries = new LineGraphSeries(); + rateSeries.setDrawDataPoints(true); + String from = this.getDropdownValue(this.dropFromCurrency); + String to = this.getDropdownValue(this.dropToCurrency); + rateSeries.setTitle(from + " -> " + to); + + // local variables for conversions + Double fromRate[] = new Double[entries]; + Double toRate[] = new Double[entries]; + Date dates[] = new Date[entries]; + double calculatedRate = 0; + + // Generate dates: + int y = 0; + for (int x = entries - 1; x >= 0; x--) { + dates[y] = Utility.getDateAgoAsDate(x); + Log.i("Dates", "Date: " + y + " " + dates[y]); + y++; + } + + if (from.equals(to)) { + for (int x = 0; x < entries; x++) { + rateSeries.appendData(new DataPoint(x, 1.0), true, entries); + } + } else { + // get rates for to and from currencies for a given day + for (int x = 0; x < entries; x++) { + fromRate[x] = currencyDao.selectCurrencyRate(currencyDao.getStringFromDate(dates[x]), from); + toRate[x] = currencyDao.selectCurrencyRate(currencyDao.getStringFromDate(dates[x]), to); + calculatedRate = (1/fromRate[x]) * toRate[x]; + Log.i("Rates", "Day: " + x + " From: " + from + " To: " + to + " = " + calculatedRate); + rateSeries.appendData(new DataPoint(x, calculatedRate), true, entries); + } + } + this.currencyGraph.removeAllSeries(); + this.currencyGraph.getLegendRenderer().setVisible(true); + this.currencyGraph.getLegendRenderer().setAlign(LegendRenderer.LegendAlign.TOP); + this.currencyGraph.getGridLabelRenderer().setHorizontalAxisTitle("Days Ago"); + this.currencyGraph.getViewport().setXAxisBoundsManual(true); + this.currencyGraph.getViewport().setMinX(1); + this.currencyGraph.getViewport().setMaxX(entries - 1); + this.currencyGraph.addSeries(rateSeries); + } + + private String getDropdownValue(Spinner dropdown){ + return dropdown.getSelectedItem().toString().substring(0, 3); + } + private void processFormInput() { // set our containers to hold ui element data String fromCurrency = ""; @@ -171,12 +205,13 @@ private void processFormInput() { String strFromAmount = this.txtFromAmount.getText().toString(); Log.w("processFormInput", String.valueOf(strFromAmount.length())); DecimalFormat decimalFormat = new DecimalFormat(); - decimalFormat.setMaximumFractionDigits(2); + decimalFormat.setMaximumFractionDigits(4); + CurrencyDao currencyDao = new CurrencyDao(); try { - fromCurrency = this.dropFromCurrency.getSelectedItem().toString().substring(0, 3); // needed to parse out just the currency abbreviation + fromCurrency = this.getDropdownValue(this.dropFromCurrency); setFlag(this.imgFromFlag, fromCurrency); // change our flag icon - toCurrency = this.dropToCurrency.getSelectedItem().toString().substring(0, 3); // same here as above + toCurrency = this.getDropdownValue(this.dropToCurrency); setFlag(this.imgToFlag, toCurrency); } catch (Exception e) { Log.e("processFormInput", e.toString(), e); @@ -194,34 +229,15 @@ private void processFormInput() { } else if (fromCurrency.equals(toCurrency)) { // make sure the source and destination arent the same this.txtResult.setText(decimalFormat.format(fromAmount)); } else { - this.now = System.currentTimeMillis(); // current time in ms - this.ago = now - 10 * DAY_IN_MILLIS; // 10 days ago - - String strNow = this.formatter.format(new Date(this.now)); - String strAgo = this.formatter.format(new Date(this.ago)); - - Log.w("Current Date", strNow); - Log.w("10 days ago", strAgo); - - WebAPIRequest apiRequest = new WebAPIRequest(); - apiRequest.setUrl(fromCurrency, toCurrency); - //TrippeCurrency currency = apiRequest.getLatestAsTrippeCurrency(); - double rate = apiRequest.getLatestRate(); - - //TODO WEB API REQUEST/DB QUERY - /* - CurrencyQuery currencyQuery = new CurrencyQuery(getContext(), toCurrency, fromCurrency); - currencyQuery.setSourceAmount(fromAmount); - currencyQuery.getRequestLatest();*/ - - this.txtResult.setText(decimalFormat.format(rate * fromAmount)); - - //LineGraphSeries updateSeries = new LineGraphSeries((DataPoint[]) currencyQuery.getRequestHistory(strAgo, strNow)); - //this.currencyGraph.addSeries(updateSeries); - //this.series.appendData - //this.series.appendData(currencyQuery.getRequestHistory(strAgo, strNow)); - - // this.series.resetData( (DataPoint[]) currencyQuery.getRequestHistory(strAgo, strNow)); + double fromRate = currencyDao.selectCurrencyRate("", fromCurrency); + double toRate = currencyDao.selectCurrencyRate("", toCurrency); + Log.i("processFormInput", "to:" + toRate + " from:" + fromRate); + if (toRate > 0) { + double rate = fromAmount * (1/fromRate) * toRate; + this.txtResult.setText(decimalFormat.format(rate)); + } else { + this.txtResult.setText(""); + } } } catch (Exception e) { @@ -233,7 +249,8 @@ private void processFormInput() { @Override public void onItemSelected(AdapterView aView, View v, int selectedInt, long selectedLong) { - processFormInput(); + this.setCurrencyGraph(); + this.processFormInput(); } diff --git a/app/src/main/java/com/example/trippe/ui/currency/CurrencyQuery.java b/app/src/main/java/com/example/trippe/ui/currency/CurrencyQuery.java deleted file mode 100644 index 958a663..0000000 --- a/app/src/main/java/com/example/trippe/ui/currency/CurrencyQuery.java +++ /dev/null @@ -1,256 +0,0 @@ -package com.example.trippe.ui.currency; - -import android.content.Context; -import android.util.Log; -import android.view.Gravity; -import android.widget.Toast; - -import com.example.trippe.R; -import com.jjoe64.graphview.series.DataPoint; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; - - - -public class CurrencyQuery { - // TODO add a history variable (likely a dictionary of tuples or something) - private String sourceCurrency = ""; - private String destCurrency = ""; - private double sourceAmount = 0; - private double destAmount = 0; - - // We will query all source and destination currencies against USD as our base so we store - // the exchange rates of each relative to USD for later conversion - private double destExchangeRate = 0; - private double sourceExchangeRate = 0; - private Context context; - - public CurrencyQuery(Context context) { - this.context = context; - } - public CurrencyQuery(Context context, String dest) { - this.context = context; - setDestCurrency(dest); - } - - public CurrencyQuery(Context context, String dest, String source) { - this.context = context; - setDestCurrency(dest); - setSourceCurrency(source); - } - - public CurrencyQuery(Context context, String dest, double amount) { - this.context = context; - setDestCurrency(dest); - setSourceAmount(amount); - } - - public CurrencyQuery(Context context, String dest, String source, double amount) { - this.context = context; - setDestCurrency(dest); - setSourceCurrency(source); - setSourceAmount(amount); - } - - public String getSourceCurrency() { return this.sourceCurrency; } - public String getDestCurrency() { return this.destCurrency; } - public double getSourceAmount() { return this.sourceAmount; } - public double getDestAmount() { return this.destAmount; } - - public void setSourceCurrency(String source) { // set our local sourceCurrency if its a valid entry - if (validCurrency(source) && !source.equals(this.destCurrency)) { - this.sourceCurrency = source; - Log.w("setSourceCurrency", "Set source currency to: " + this.sourceCurrency); - } - } - - public void setDestCurrency(String dest) { - if (validCurrency(dest) && !dest.equals(this.sourceCurrency)) { - this.destCurrency = dest; - Log.w("setDestCurrency", "Set dest currency to: " + this.destCurrency); - } - } - - public void setSourceAmount(double amount) { // standard setter, ensures amount is > 0 - if (amount > 0 ) { - this.sourceAmount = amount; - } - } - - // TODO make sure results are ordered and reflect the difference in rate from the source and dest currency - public DataPoint[] getRequestHistory(String startDate, String endDate) { - // symbols in the api are the currency abbreviations we are using for each currency : EX EUR is the symbol for Euros - String symbols = "&symbols=" + - this.destCurrency; - - String strUrl = "https://api.exchangeratesapi.io/history?base=" + - this.sourceCurrency + - "&start_at=" + - startDate + - "&end_at=" + - endDate + - symbols; - Log.w("URL REQUEST:", strUrl); - - try { - URL url = new URL(strUrl); - HttpURLConnection request = (HttpURLConnection) url.openConnection(); - request.setRequestMethod("GET"); // GET request is needed for this api - InputStream inputStream = request.getInputStream(); // connect and get a stream of data - - // build our stream readers in typical stupid java fashion to read a simple text response - InputStreamReader inputStreamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - String httpGetRequestData = bufferedReader.readLine(); - request.disconnect(); // make sure our connection closes - - // Convert to JSON - Log.w("GET RESULT", httpGetRequestData); // log some shit - - JSONObject reader = new JSONObject(httpGetRequestData); // convert our string into a JSONObject - JSONObject rates = reader.getJSONObject("rates"); // neck down the data to the rates fields - JSONArray keys = rates.names(); - - DataPoint points[] = new DataPoint[10]; - DataPoint point; - - int x; - Log.w("Names", rates.names().toString()); - JSONObject rate; - Log.w("Result Length", String.valueOf(keys.length())); - /*int length = 9; // TODO this is a bad bandaid solution to not getting enough results - for (x = length; x >=0; x--) { - /*Log.w("LOOP History", "Key: " + - keys.getString(x) + - " Value: " + - rates.getString(keys.getString(x)));*/ - for (x = 0; x < 10; x++) { - try { - rate = rates.getJSONObject(keys.getString(x)); - Log.w("Loop", String.valueOf(x) + ", " + rate.getString(this.destCurrency)); - point = new DataPoint(x, rate.getDouble(this.destCurrency)); - points[x] = point; - } catch (Exception e) { - Log.w("Loop:", String.valueOf(x) + ", 0"); - // Log.e("API Error", e.toString(), e); - point = new DataPoint(x, 0); - points[x] = point; - } - - } - - //LineGraphSeries series = new LineGraphSeries(points); - - //return series; - return points; - //this.destExchangeRate = Double.parseDouble(rates.getString(this.destCurrency)); // pull out our dest rate from json - //this.sourceExchangeRate = Double.parseDouble(rates.getString(this.sourceCurrency)); // pull out or source rage from json - - // FINALLY WE GET TO CONVERT STUFF - //this.destAmount = this.sourceAmount / this.sourceExchangeRate * this.destExchangeRate; - // TODO Actually use this data and then save to db. Parse out relevant fields - } catch (Exception e) { - Log.e("CurrencyQuery", e.toString(), e); - Toast toast = Toast.makeText(context.getApplicationContext(), "Woops, Something broke!", Toast.LENGTH_SHORT); - toast.setGravity(Gravity.CENTER, 0, 0); - toast.show(); - } - //LineGraphSeries series = new LineGraphSeries(new DataPoint[] { - DataPoint points[] = new DataPoint[] { - new DataPoint(-9, 1), - new DataPoint(-8, 1), - new DataPoint(-7, 1), - new DataPoint(-6, 1), - new DataPoint(-5, 1), - new DataPoint(-4, 1), - new DataPoint(-3, 1), - new DataPoint(-2, 1), - new DataPoint(-1, 1), - new DataPoint(0, 1) - }; - return points; - //return series; - } - - public void getRequestLatest() { // TODO Change from void to something else - /* For API information visit: - https://exchangeratesapi.io/ - - Query results are via HTTP Get method and return a JSON String that looks something like: - { - "base": "EUR", - "date": "2018-04-08", - "rates": { - "CAD": 1.565, - "CHF": 1.1798, - "GBP": 0.87295, - "SEK": 10.2983, - "EUR": 1.092, - "USD": 1.2234, - ... - } - } - We mostly care about the relevant entries under "rates" and "date" */ - - // symbols in the api are the currency abbreviations we are using for each currency : EX EUR is the symbol for Euros - String symbols = "&symbols=" + this.sourceCurrency + "," + this.destCurrency; - - // Set up our URL - String strUrl = "https://api.exchangeratesapi.io/latest?base=USD" + symbols; - - strUrl += symbols; // append our symbols - - try { - URL url = new URL(strUrl); - HttpURLConnection request = (HttpURLConnection) url.openConnection(); - request.setRequestMethod("GET"); // GET request is needed for this api - InputStream inputStream = request.getInputStream(); // connect and get a stream of data - - // build our stream readers in typical stupid java fashion to read a simple text response - InputStreamReader inputStreamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - String httpGetRequestData = bufferedReader.readLine(); - request.disconnect(); // make sure our connection closes - - // Convert to JSON - Log.w("GET RESULT", httpGetRequestData); // log some shit - - JSONObject reader = new JSONObject(httpGetRequestData); // convert our string into a JSONObject - JSONObject rates = reader.getJSONObject("rates"); // neck down the data to the rates fields - this.destExchangeRate = Double.parseDouble(rates.getString(this.destCurrency)); // pull out our dest rate from json - this.sourceExchangeRate = Double.parseDouble(rates.getString(this.sourceCurrency)); // pull out or source rage from json - - // FINALLY WE GET TO CONVERT STUFF - this.destAmount = this.sourceAmount / this.sourceExchangeRate * this.destExchangeRate; - // TODO Actually use this data and then save to db. Parse out relevant fields - } catch (Exception e) { - Log.e("CurrencyQuery", e.toString(), e); - Toast toast = Toast.makeText(context.getApplicationContext(), "Woops, Something broke!", Toast.LENGTH_SHORT); - toast.setGravity(Gravity.CENTER, 0, 0); - toast.show(); - } - } - - private boolean validCurrency(String currency) { - if (currency.length() != 3) { - return false; - } - - String currencyOptions[]; // will store the values of our resource string array in strings.xml - currencyOptions = context.getResources().getStringArray(R.array.currency_array); - // iterate through our currency list to see if we passed a valid currency - for (String currencyEntry : currencyOptions) { - if (currencyEntry.substring(0, 3).equals(currency)) { - return true; - } - } - return false; - } -} diff --git a/app/src/main/java/com/example/trippe/ui/currency/WebAPIRequest.java b/app/src/main/java/com/example/trippe/ui/currency/WebAPIRequest.java index 9299ced..c3a2148 100644 --- a/app/src/main/java/com/example/trippe/ui/currency/WebAPIRequest.java +++ b/app/src/main/java/com/example/trippe/ui/currency/WebAPIRequest.java @@ -1,8 +1,9 @@ package com.example.trippe.ui.currency; +import android.os.AsyncTask; import android.util.Log; -import com.jjoe64.graphview.series.DataPoint; +import com.example.trippe.model.TrippeCurrency; import org.json.JSONArray; import org.json.JSONException; @@ -20,9 +21,12 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; -public class WebAPIRequest { + +public class WebAPIRequest { private String strUrl; public WebAPIRequest() { @@ -103,7 +107,7 @@ public String getStrUrl() { } // check that a currency is a valid format and privided in our api - public boolean invalidCurrency(String currency) { + public static boolean invalidCurrency(String currency) { // TODO access database for list of currencies String currencies[] = { "USD", "EUR", "AUD", "BGN", @@ -126,7 +130,7 @@ public boolean invalidCurrency(String currency) { } // checks that a string date is a valid format for the api - public boolean invalidDate(String inDate) { + public static boolean invalidDate(String inDate) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date date; try { @@ -145,7 +149,7 @@ public Date getDateFromString(String inDate) { date = df.parse(inDate); return date; } catch (ParseException e) { - Log.w("invalidDate", "Date: " + inDate + " is invalid"); + Log.w("getDateFromString", "Date: " + inDate + " is invalid"); date = new Date(); return date; } @@ -156,10 +160,10 @@ public String getRatesAsString(){ return this.httpGet(); } - // returns an unprocessed jsonobject from our query public JSONObject getRatesAsJSON() { JSONObject jsonGetResult; String httpGetResult = this.httpGet(); + Log.i("getRatesAsJSON", httpGetResult); try { jsonGetResult = new JSONObject(httpGetResult); // convert our string into a JSONObject @@ -187,35 +191,7 @@ public double getLatestRate() { return rate; } } - /* - public TrippeCurrency getLatestAsTrippeCurrency(){ - JSONObject jsonGetResult = this.getRatesAsJSON(); - JSONObject rate; - TrippeCurrency currency = new TrippeCurrency(); - try { - JSONObject rates = jsonGetResult.getJSONObject("rates"); // neck down the data to the rates fields - JSONArray keys = rates.names(); - Date date = this.getDateFromString(rates.getString("date")); - for (int x = 0; x < keys.length(); x++) { - currency.setAbbreviation(keys.getString(x)); // set our currency abbrev - rate = rates.getJSONObject(keys.getString(x)); - // currency.addRate(date, rate); - } - } catch(JSONException e){ - return new TrippeCurrency(); - } - return currency; - } -*/ - - /* // return an array of currency objects - public TrippeCurrency[] getHistoricalAsTrippeCurrency(){ - TrippeCurrency currencies[]; - return currencies; - } - */ - // perform http get request and return a string of json data public String httpGet() { URL url; HttpURLConnection request; @@ -228,6 +204,8 @@ public String httpGet() { } try { request = (HttpURLConnection) url.openConnection(); + request.setReadTimeout(20000); + request.setConnectTimeout(20000); request.setRequestMethod("GET"); // GET request is needed for this api InputStream inputStream = request.getInputStream(); // connect and get a stream of data @@ -244,8 +222,57 @@ public String httpGet() { } } -/* - private void sortDates() { - }*/ + + public Map getHistoryAsMap() { + Map currencyMap = new HashMap(); + TrippeCurrency currency; + try { + JSONObject result = this.getRatesAsJSON(); + + JSONObject rates = result.getJSONObject("rates"); + + String day; + String strCurrency; + Double rate; + for (Iterator it1 = rates.keys(); it1.hasNext(); ) { + day = it1.next(); + Date date = this.getDateFromString(day); + JSONObject days = rates.getJSONObject(day); + for (Iterator it2 = days.keys(); it2.hasNext();) { + strCurrency = it2.next(); + Log.i("iterator", strCurrency); + if (currencyMap.containsKey(strCurrency)) { + currency = currencyMap.get(strCurrency); + if (days.has(strCurrency)) { + rate = days.getDouble(strCurrency); + Log.i("gotrate", "map and rates: " + String.valueOf(rate)); + } else { + rate = 0.0; + Log.i("gotrate", "map no rates " + String.valueOf(rate)); + } + currency.addRate(this.getDateFromString(day), rate); + currencyMap.replace(strCurrency, currency); + } else { + if (days.has(strCurrency)) { + rate = days.getDouble(strCurrency); + Log.i("gotrate", "no map and rates " + String.valueOf(rate)); + } else { + rate = 0.0; + Log.i("gotrate", "no map and no rates " + String.valueOf(rate)); + } + currency = new TrippeCurrency(strCurrency); + currency.addRate(date, rate); + currencyMap.put(strCurrency, currency); + } + } + } + } catch (JSONException e) { + Log.e("getHistoryAsList", e.toString(), e); + return currencyMap; + } catch (Exception e) { + Log.e("getHistoryAsList", e.toString(), e); + } + return currencyMap; + } } diff --git a/app/src/main/java/com/example/trippe/util/Utility.java b/app/src/main/java/com/example/trippe/util/Utility.java index 192c16c..ec37789 100644 --- a/app/src/main/java/com/example/trippe/util/Utility.java +++ b/app/src/main/java/com/example/trippe/util/Utility.java @@ -5,6 +5,8 @@ import com.example.trippe.dao.TripDao; import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.concurrent.ThreadLocalRandom; public class Utility { @@ -56,4 +58,65 @@ public static int getResourceIndicatorByString(String resourceName, Class any return -1; } } + + + /** + * this method is used to get the current date as a string in the format yyyy-MM-dd + * in order to interface with the database or CurrencyDao and/or WebAPIRequest classes + * @return today's date as a String + */ + public static String getTodaysDate(){ + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Long now = System.currentTimeMillis(); // current time in ms + String strNow = ""; + try { + strNow = formatter.format(new Date(now)); + } catch (Exception e) { + Log.e("getTodaysDate", e.toString(), e); + } + return strNow; + } + + + /** + * this method is used to get the current date 'daysAgo' number of days ago as a + * string in the format yyyy-MM-dd + * in order to interface with the database or CurrencyDao and/or WebAPIRequest classes + * @param daysAgo + * @return date 'daysAgo' as a String + */ + public static String getDateAgo(int daysAgo){ + long DAY_IN_MILLIS = 86400000; // one day in milliseconds + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Long now = System.currentTimeMillis(); // current time in ms + long ago = now - daysAgo * DAY_IN_MILLIS; // calculate date 10 days ago + String strAgo = ""; + try { + strAgo = formatter.format(new Date(ago)); + } catch (Exception e) { + Log.e("getDateAgo", e.toString(), e); + } + return strAgo; + } + + + /** + * this method is used to get the current date 'daysAgo' number of days ago as a + * string in the format yyyy-MM-dd + * in order to interface with the database or CurrencyDao and/or WebAPIRequest classes + * @param daysAgo + * @return date 'daysAgo' as a String + */ + public static Date getDateAgoAsDate(int daysAgo){ + long DAY_IN_MILLIS = 86400000; // one day in milliseconds + Long now = System.currentTimeMillis(); // current time in ms + long ago = now - daysAgo * DAY_IN_MILLIS; // calculate date 10 days ago + Date dateAgo = new Date(); + try { + dateAgo = new Date(ago); + } catch (Exception e) { + Log.e("getDateAgo", e.toString(), e); + } + return dateAgo; + } } diff --git a/app/src/main/res/layout/fragment_currency.xml b/app/src/main/res/layout/fragment_currency.xml index ddad786..452fcad 100644 --- a/app/src/main/res/layout/fragment_currency.xml +++ b/app/src/main/res/layout/fragment_currency.xml @@ -80,10 +80,12 @@ android:textColor="#FFFFFF"/> + android:layout_marginRight="5dp" + android:layout_marginLeft="5dp" + android:layout_height="250dip" + android:layout_below="@id/txtResult" /> diff --git a/local.properties b/local.properties index 4b7bd7f..068bf6d 100644 --- a/local.properties +++ b/local.properties @@ -4,5 +4,5 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Tue Nov 12 22:26:48 EST 2019 -sdk.dir=/Users/robertogonzales/Library/Android/sdk +#Tue Nov 26 20:07:29 EST 2019 +sdk.dir=C\:\\Users\\Joe\\AppData\\Local\\Android\\Sdk