diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..40b0348 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3963879 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fa9ddad --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f7567b8 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 26 + defaultConfig { + applicationId "com.nauk.coinfolio" + minSdkVersion 21 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main.java.srcDirs += 'src/main/binance/src' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support:design:26.1.0' + implementation 'com.android.support:cardview-v7:26.1.0' + implementation 'com.mcxiaoke.volley:library:1.0.19' + implementation 'com.diogobernardino:williamchart:2.5.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:support-v4:26.1.0' + implementation 'com.android.support:palette-v7:26.1.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.1' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/nauk/coinfolio/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/nauk/coinfolio/ExampleInstrumentedTest.java new file mode 100644 index 0000000..8f27629 --- /dev/null +++ b/app/src/androidTest/java/com/nauk/coinfolio/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.nauk.coinfolio; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.nauk.crystalvault", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e00c799 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/Icon_CrystalVault-web.png b/app/src/main/Icon_CrystalVault-web.png new file mode 100644 index 0000000..274833b Binary files /dev/null and b/app/src/main/Icon_CrystalVault-web.png differ diff --git a/app/src/main/ic_hitbtc-web.png b/app/src/main/ic_hitbtc-web.png new file mode 100644 index 0000000..88a68d6 Binary files /dev/null and b/app/src/main/ic_hitbtc-web.png differ diff --git a/app/src/main/java/com/nauk/coinfolio/Activities/AppCompatPreferenceActivity.java b/app/src/main/java/com/nauk/coinfolio/Activities/AppCompatPreferenceActivity.java new file mode 100644 index 0000000..bab14fe --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/Activities/AppCompatPreferenceActivity.java @@ -0,0 +1,109 @@ +package com.nauk.coinfolio.Activities; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.support.annotation.LayoutRes; +import android.support.annotation.Nullable; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatDelegate; +import android.support.v7.widget.Toolbar; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls + * to be used with AppCompat. + */ +public abstract class AppCompatPreferenceActivity extends PreferenceActivity { + + private AppCompatDelegate mDelegate; + + @Override + protected void onCreate(Bundle savedInstanceState) { + getDelegate().installViewFactory(); + getDelegate().onCreate(savedInstanceState); + super.onCreate(savedInstanceState); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + getDelegate().onPostCreate(savedInstanceState); + } + + public ActionBar getSupportActionBar() { + return getDelegate().getSupportActionBar(); + } + + public void setSupportActionBar(@Nullable Toolbar toolbar) { + getDelegate().setSupportActionBar(toolbar); + } + + @Override + public MenuInflater getMenuInflater() { + return getDelegate().getMenuInflater(); + } + + @Override + public void setContentView(@LayoutRes int layoutResID) { + getDelegate().setContentView(layoutResID); + } + + @Override + public void setContentView(View view) { + getDelegate().setContentView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().setContentView(view, params); + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + getDelegate().addContentView(view, params); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getDelegate().onPostResume(); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + super.onTitleChanged(title, color); + getDelegate().setTitle(title); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getDelegate().onConfigurationChanged(newConfig); + } + + @Override + protected void onStop() { + super.onStop(); + getDelegate().onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + getDelegate().onDestroy(); + } + + public void invalidateOptionsMenu() { + getDelegate().invalidateOptionsMenu(); + } + + private AppCompatDelegate getDelegate() { + if (mDelegate == null) { + mDelegate = AppCompatDelegate.create(this, null); + } + return mDelegate; + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/Activities/CurrencySelectionActivity.java b/app/src/main/java/com/nauk/coinfolio/Activities/CurrencySelectionActivity.java new file mode 100644 index 0000000..a981d9e --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/Activities/CurrencySelectionActivity.java @@ -0,0 +1,78 @@ +package com.nauk.coinfolio.Activities; + +import android.content.Intent; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.Menu; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AutoCompleteTextView; + +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; +import com.nauk.coinfolio.LayoutManagers.CurrencyAdapter; +import com.nauk.coinfolio.R; + +import java.util.ArrayList; + +public class CurrencySelectionActivity extends AppCompatActivity { + + String[] currencySymbols; + String[] currencyNames; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.activity_add_currency); + + Intent intent = getIntent(); + + currencySymbols = intent.getStringArrayExtra("currencyListSymbols"); + currencyNames = intent.getStringArrayExtra("currencyListNames"); + + setTitle("Select a coin"); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + final AutoCompleteTextView searchAutoComplete = findViewById(R.id.search_bar); + + searchAutoComplete.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + Intent intent = new Intent(CurrencySelectionActivity.this, RecordTransactionActivity.class); + intent.putExtra("coin", searchAutoComplete.getText().toString()); + intent.putExtra("symbol", searchAutoComplete.getCompletionHint().toString()); + startActivity(intent); + finish(); + } + }); + + String[] currencyFullname = new String[currencyNames.length]; + + for(int i = 0; i < currencyFullname.length; i++) + { + currencyFullname[i] = currencyNames[i] + " " + currencySymbols[i]; + } + + ArrayList currencyArrayList = new ArrayList<>(); + + for(int i = 0; i < currencyNames.length; i++) + { + currencyArrayList.add(new Currency(currencyNames[i], currencySymbols[i])); + } + + CurrencyAdapter adapter = new CurrencyAdapter(this, currencyArrayList); + + searchAutoComplete.setAdapter(adapter); + searchAutoComplete.setThreshold(0); + + return true; + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/Activities/HomeActivity.java b/app/src/main/java/com/nauk/coinfolio/Activities/HomeActivity.java new file mode 100644 index 0000000..d1fdf27 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/Activities/HomeActivity.java @@ -0,0 +1,470 @@ +package com.nauk.coinfolio.Activities; + +import android.app.Dialog; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.design.widget.CollapsingToolbarLayout; +import android.support.design.widget.Snackbar; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.graphics.Palette; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.nauk.coinfolio.DataManagers.BalanceManager; +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; +import com.nauk.coinfolio.DataManagers.DatabaseManager; +import com.nauk.coinfolio.LayoutManagers.HomeLayoutGenerator; +import com.nauk.coinfolio.DataManagers.PreferencesManager; +import com.nauk.coinfolio.R; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.List; + +//Use WilliamChart for charts https://github.com/diogobernardino/WilliamChart + +//Auto refresh with predefined intervals +//Adding manually currencies (date, purchased price) +//Multiple portfolio (exchanges & custom) +//Add currency details (market cap, 1h, 3h, 3d, 1w, 1m, 3m, 1y) +//Add roadmap to buy a coin +//Add reddit link ? +// + +public class HomeActivity extends AppCompatActivity { + + private BalanceManager balanceManager; + private int coinCounter; + private HomeLayoutGenerator layoutGenerator; + private LinearLayout currencyLayout; + private Toolbar toolbar; + private CollapsingToolbarLayout toolbarLayout; + private SwipeRefreshLayout refreshLayout; + private TextView toolbarSubtitle; + private boolean view; + private Dialog loadingDialog; + private boolean iconChecker; + private PreferencesManager preferencesManager; + private DatabaseManager databaseManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + setContentView(R.layout.activity_currency_summary); + toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + preferencesManager = new PreferencesManager(this); + + view = preferencesManager.getDetailOption(); + + generateSplash(); + + ImageButton detailsButton = findViewById(R.id.switch_button); + ImageButton settingsButton = findViewById(R.id.settings_button); + + refreshLayout = findViewById(R.id.swiperefresh); + + toolbarLayout = findViewById(R.id.toolbar_layout); + + toolbarSubtitle = findViewById(R.id.toolbarSubtitle); + + toolbarLayout.setExpandedTitleGravity(Gravity.CENTER); + toolbarLayout.setCollapsedTitleGravity(Gravity.CENTER); + toolbarLayout.setForegroundGravity(Gravity.CENTER); + toolbarLayout.setTitle("US$0.00"); + + toolbarSubtitle.setText("US$0.00"); + + detailsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + switchView(); + } + }); + + settingsButton.setBackground(this.getResources().getDrawable(R.drawable.ic_settings_black_24dp)); + settingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent settingIntent = new Intent(HomeActivity.this, SettingsActivity.class); + startActivity(settingIntent); + } + }); + + layoutGenerator = new HomeLayoutGenerator(this); + + balanceManager = new BalanceManager(this); + + currencyLayout = findViewById(R.id.currencyListLayout); + + refreshLayout.setOnRefreshListener( + new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + updateAll(); + } + } + ); + + final ImageButton addCurrencyButton = findViewById(R.id.addCurrencyButton); + + addCurrencyButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent addIntent = new Intent(HomeActivity.this, CurrencySelectionActivity.class); + + String[] symbolList = new String[balanceManager.getCurrenciesSymbol().size()]; + symbolList = balanceManager.getCurrenciesSymbol().toArray(symbolList); + String[] nameList = new String[balanceManager.getCurrenciesName().size()]; + nameList = balanceManager.getCurrenciesName().toArray(nameList); + + addIntent.putExtra("currencyListSymbols", symbolList); + addIntent.putExtra("currencyListNames", nameList); + + startActivity(addIntent); + + + /*Snackbar.make(findViewById(R.id.currencyListLayout), "This feature is not yet available...", Snackbar.LENGTH_LONG) + .show();*/ + } + }); + + databaseManager = new DatabaseManager(this); + databaseManager.getAllCurrencyFromManualCurrency(); + + updateViewButtonIcon(); + } + + @Override + protected void onResume() { + super.onResume(); + + updateAll(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + //getMenuInflater().inflate(R.menu.menu_currency_summary, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + switch (id) + { + /*case R.id.action_settings: + Log.d(this.getResources().getString(R.string.debug), "Setting button toggled"); + break;*/ + } + + return super.onOptionsItemSelected(item); + } + + private void switchView() + { + if(!view) + { + view = true; + + adaptView(); + } + else + { + view = false; + + adaptView(); + } + } + + private void adaptView() + { + if(!view) + { + for(int i = 0; i < currencyLayout.getChildCount(); i++) + { + currencyLayout.getChildAt(i).findViewWithTag("chart_layout").setVisibility(View.GONE); + currencyLayout.getChildAt(i).findViewWithTag("separator_layout").setVisibility(View.GONE); + } + } + else + { + currencyLayout.removeAllViews(); + + for(int i = 0; i < balanceManager.getTotalBalance().size(); i++) + { + final Currency currency = balanceManager.getTotalBalance().get(i); + + if(!currency.getSymbol().equals("USD") && (currency.getBalance() * currency.getValue()) > 0.001) + { + if(currency.getIcon() != null) + { + Palette.Builder builder = Palette.from(currency.getIcon()); + + currencyLayout.addView(layoutGenerator.getInfoLayout(currency, builder.generate().getDominantColor(0))); + } + else + { + currencyLayout.addView(layoutGenerator.getInfoLayout(currency, 12369084)); + } + + } + } + } + + updateViewButtonIcon(); + } + + + + private void updateAll() + { + resetCounter(); + balanceManager.updateExchangeKeys(); + DataUpdater updater = new DataUpdater(); + updater.execute(); + refreshLayout.setRefreshing(true); + } + + private void resetCounter() + { + coinCounter = 0; + iconChecker = false; + } + + private Bitmap getBitmapFromURL(String src) { + try { + java.net.URL url = new java.net.URL(src); + HttpURLConnection connection = (HttpURLConnection) url + .openConnection(); + connection.setDoInput(true); + connection.connect(); + InputStream input = connection.getInputStream(); + return BitmapFactory.decodeStream(input); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + private void countCoins(boolean isCoin, boolean isIcon) + { + float totalValue = 0; + float totalFluctuation = 0; + + if(isCoin) + { + coinCounter++; + } + + if(isIcon) + { + iconChecker = true; + } + + if(balanceManager.getTotalBalance() != null) + { + if(coinCounter == balanceManager.getTotalBalance().size()-1 && iconChecker) + { + refreshLayout.setRefreshing(false); + + balanceManager.sortCoins(); + + currencyLayout.removeAllViews(); + + for(int i = 0; i < balanceManager.getTotalBalance().size(); i++) + { + if(!balanceManager.getTotalBalance().get(i).getSymbol().equals("USD") && (balanceManager.getTotalBalance().get(i).getBalance() * balanceManager.getTotalBalance().get(i).getValue()) > 0.001) + { + totalValue += balanceManager.getTotalBalance().get(i).getValue() * balanceManager.getTotalBalance().get(i).getBalance(); + totalFluctuation += (balanceManager.getTotalBalance().get(i).getValue() * balanceManager.getTotalBalance().get(i).getBalance()) * (balanceManager.getTotalBalance().get(i).getDayFluctuationPercentage() / 100); + balanceManager.getTotalBalance().get(i).setIcon(getBitmapFromURL(balanceManager.getIconUrl(balanceManager.getTotalBalance().get(i).getSymbol()))); + currencyLayout.addView(layoutGenerator.getInfoLayout(balanceManager.getTotalBalance().get(i),0)); + } + } + + adaptView(); + + toolbarLayout.setTitle("US$" + String.format("%.2f", totalValue)); + + if(totalFluctuation > 0) + { + toolbarSubtitle.setTextColor(getResources().getColor(R.color.increase)); + } + else + { + toolbarSubtitle.setTextColor(getResources().getColor(R.color.decrease)); + } + + toolbarSubtitle.setText("US$" + String.format("%.2f", totalFluctuation)); + + + if(loadingDialog.isShowing()) + { + loadingDialog.dismiss(); + } + } + } + + if(balanceManager.getTotalBalance().size() == 0) + { + refreshLayout.setRefreshing(false); + + currencyLayout.removeAllViews(); + + if(loadingDialog.isShowing()) + { + loadingDialog.dismiss(); + } + } + } + + private void updateViewButtonIcon() + { + ImageButton imgButton = findViewById(R.id.switch_button); + + if(view) + { + imgButton.setBackground(this.getResources().getDrawable(R.drawable.ic_unfold_less_black_24dp)); + preferencesManager.setDetailOption(true); + } + else + { + imgButton.setBackground(this.getResources().getDrawable(R.drawable.ic_details_black_24dp)); + preferencesManager.setDetailOption(false); + } + } + + private void generateSplash() + { + LinearLayout loadingLayout = new LinearLayout(this); + loadingLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + loadingLayout.setGravity(Gravity.CENTER); + loadingLayout.setOrientation(LinearLayout.VERTICAL); + + loadingDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen); + + TextView txtView = new TextView(this); + txtView.setText("Loading data..."); + txtView.setTextSize(20); + txtView.setGravity(Gravity.CENTER); + txtView.setTextColor(this.getResources().getColor(R.color.cardview_light_background)); + + ProgressBar progressBar = new ProgressBar(this); + progressBar.setIndeterminate(true); + + loadingLayout.setBackgroundColor(this.getResources().getColor(R.color.colorPrimaryDark)); + loadingLayout.addView(txtView); + loadingLayout.addView(progressBar); + + loadingDialog.setContentView(loadingLayout); + loadingDialog.show(); + } + + private class DataUpdater extends AsyncTask + { + @Override + protected void onPreExecute() + { + super.onPreExecute(); + } + + @Override + protected void onProgressUpdate(Integer... values) + { + super.onProgressUpdate(values); + } + + @Override + protected Void doInBackground(Void... params) + { + balanceManager.updateTotalBalance(new BalanceManager.VolleyCallBack() { + @Override + public void onSuccess() { + + final List balance = balanceManager.getTotalBalance(); + + if(balanceManager.getTotalBalance().size() < 0) + { + for(int i = 0; i < balanceManager.getTotalBalance().size(); i++) + { + balance.get(i).updateDayPriceHistory(getApplicationContext(), new Currency.CurrencyCallBack() { + @Override + public void onSuccess(Currency currency) { + currency.updateName(getApplicationContext(), new Currency.CurrencyCallBack() { + @Override + public void onSuccess(Currency currency) { + countCoins(true, false); + } + }); + } + }); + } + } + else + { + countCoins(false, false); + } + } + + public void onError(String error) + { + switch (error) + { + case "com.android.volley.AuthFailureError": + preferencesManager.disableHitBTC(); + Snackbar.make(findViewById(R.id.currencyListLayout), "HitBTC synchronization error : Invalid keys", Snackbar.LENGTH_LONG) + .show(); + refreshLayout.setRefreshing(false); + updateAll(); + break; + default: + updateAll(); + } + //updateAll(); + } + }); + + balanceManager.updateDetails(new BalanceManager.IconCallBack() { + @Override + public void onSuccess() + { + countCoins(false, true); + } + }); + + return null; + } + + @Override + protected void onPostExecute(Void result) + { + + } + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/Activities/RecordTransactionActivity.java b/app/src/main/java/com/nauk/coinfolio/Activities/RecordTransactionActivity.java new file mode 100644 index 0000000..10aa791 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/Activities/RecordTransactionActivity.java @@ -0,0 +1,43 @@ +package com.nauk.coinfolio.Activities; + +import android.content.Intent; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.nauk.coinfolio.DataManagers.DatabaseManager; +import com.nauk.coinfolio.R; + +public class RecordTransactionActivity extends AppCompatActivity { + + String coin; + String symbol; + TextView symbolTxtView; + Button validateButton; + DatabaseManager databaseManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_transaction); + + Intent intent = getIntent(); + coin = intent.getStringExtra("coin"); + symbol = intent.getStringExtra("symbol"); + + setTitle("Add " + coin + " transaction"); + + databaseManager = new DatabaseManager(this); + + validateButton = findViewById(R.id.validateButton); + + validateButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + //databaseManager.addCurrencyToManualCurrency(); + } + }); + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/Activities/SettingsActivity.java b/app/src/main/java/com/nauk/coinfolio/Activities/SettingsActivity.java new file mode 100644 index 0000000..f17cd3e --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/Activities/SettingsActivity.java @@ -0,0 +1,290 @@ +package com.nauk.coinfolio.Activities; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.support.v7.app.ActionBar; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.preference.RingtonePreference; +import android.text.TextUtils; +import android.view.MenuItem; + +import com.nauk.coinfolio.R; + +import java.util.List; + +/** + * A {@link PreferenceActivity} that presents a set of application settings. On + * handset devices, settings are presented as a single list. On tablets, + * settings are split by category, with category headers shown to the left of + * the list of settings. + *

+ * See + * Android Design: Settings for design guidelines and the Settings + * API Guide for more information on developing a Settings UI. + */ +public class SettingsActivity extends AppCompatPreferenceActivity { + + /** + * A preference value change listener that updates the preference's summary + * to reflect its new value. + */ + private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object value) { + String stringValue = value.toString(); + + if (preference instanceof ListPreference) { + // For list preferences, look up the correct display value in + // the preference's 'entries' list. + ListPreference listPreference = (ListPreference) preference; + int index = listPreference.findIndexOfValue(stringValue); + + // Set the summary to reflect the new value. + preference.setSummary( + index >= 0 + ? listPreference.getEntries()[index] + : null); + + } else if (preference instanceof RingtonePreference) { + // For ringtone preferences, look up the correct display value + // using RingtoneManager. + if (TextUtils.isEmpty(stringValue)) { + // Empty values correspond to 'silent' (no ringtone). + preference.setSummary(R.string.pref_ringtone_silent); + + } else { + Ringtone ringtone = RingtoneManager.getRingtone( + preference.getContext(), Uri.parse(stringValue)); + + if (ringtone == null) { + // Clear the summary if there was a lookup error. + preference.setSummary(null); + } else { + // Set the summary to reflect the new ringtone display + // name. + String name = ringtone.getTitle(preference.getContext()); + preference.setSummary(name); + } + } + } else { + // For all other preferences, set the summary to the value's + // simple string representation. + preference.setSummary(stringValue); + } + return true; + } + }; + + /** + * Helper method to determine if the device has an extra-large screen. For + * example, 10" tablets are extra-large. + */ + private static boolean isXLargeTablet(Context context) { + return (context.getResources().getConfiguration().screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * Binds a preference's summary to its value. More specifically, when the + * preference's value is changed, its summary (line of text below the + * preference title) is updated to reflect the value. The summary is also + * immediately updated upon calling this method. The exact display format is + * dependent on the type of preference. + * + * @see #sBindPreferenceSummaryToValueListener + */ + private static void bindPreferenceSummaryToValue(Preference preference) { + // Set the listener to watch for value changes. + preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); + + // Trigger the listener immediately with the preference's + // current value. + sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, + PreferenceManager + .getDefaultSharedPreferences(preference.getContext()) + .getString(preference.getKey(), "")); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setupActionBar(); + } + + /** + * Set up the {@link android.app.ActionBar}, if the API is available. + */ + private void setupActionBar() { + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + // Show the Up button in the action bar. + actionBar.setDisplayHomeAsUpEnabled(true); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onIsMultiPane() { + return isXLargeTablet(this); + } + + /** + * {@inheritDoc} + */ + @Override + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public void onBuildHeaders(List

target) { + loadHeadersFromResource(R.xml.pref_headers, target); + } + + /** + * This method stops fragment injection in malicious applications. + * Make sure to deny any unknown fragments here. + */ + protected boolean isValidFragment(String fragmentName) { + return PreferenceFragment.class.getName().equals(fragmentName) + //|| GeneralPreferenceFragment.class.getName().equals(fragmentName) + || DataSyncPreferenceFragment.class.getName().equals(fragmentName) + || NotificationPreferenceFragment.class.getName().equals(fragmentName) + || ExchangePreferenceFragment.class.getName().equals(fragmentName); + } + + /** + * This fragment shows general preferences only. It is used when the + * activity is showing a two-pane settings UI. + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class GeneralPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_general); + setHasOptionsMenu(true); + + // Bind the summaries of EditText/List/Dialog/Ringtone preferences + // to their values. When their values change, their summaries are + // updated to reflect the new value, per the Android Design + // guidelines. + bindPreferenceSummaryToValue(findPreference("example_text")); + bindPreferenceSummaryToValue(findPreference("example_list")); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + //startActivity(new Intent(getActivity(), SettingsActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class ExchangePreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_exchange); + setHasOptionsMenu(true); + + bindPreferenceSummaryToValue(findPreference("hitbtc_publickey")); + bindPreferenceSummaryToValue(findPreference("hitbtc_privatekey")); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + //startActivity(new Intent(getActivity(), SettingsActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + } + + /** + * This fragment shows notification preferences only. It is used when the + * activity is showing a two-pane settings UI. + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class NotificationPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_notification); + setHasOptionsMenu(true); + + // Bind the summaries of EditText/List/Dialog/Ringtone preferences + // to their values. When their values change, their summaries are + // updated to reflect the new value, per the Android Design + // guidelines. + bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone")); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + startActivity(new Intent(getActivity(), SettingsActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + } + + /** + * This fragment shows data and sync preferences only. It is used when the + * activity is showing a two-pane settings UI. + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class DataSyncPreferenceFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.pref_data_sync); + setHasOptionsMenu(true); + + // Bind the summaries of EditText/List/Dialog/Ringtone preferences + // to their values. When their values change, their summaries are + // updated to reflect the new value, per the Android Design + // guidelines. + bindPreferenceSummaryToValue(findPreference("sync_frequency")); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + startActivity(new Intent(getActivity(), SettingsActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/BalanceManager.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/BalanceManager.java new file mode 100644 index 0000000..eb34738 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/BalanceManager.java @@ -0,0 +1,293 @@ +package com.nauk.coinfolio.DataManagers; + +import android.os.StrictMode; +import android.util.Base64; +import android.util.Log; + +import com.android.volley.AuthFailureError; +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.JsonArrayRequest; +import com.android.volley.toolbox.StringRequest; +import com.android.volley.toolbox.Volley; +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; +import com.nauk.coinfolio.R; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * Created by Tiji on 25/12/2017. + */ + +public class BalanceManager { + + private String publicHitKey; + private String publicBinanceKey; + private String publicPoloniex; + private String privateHitKey; + private String privateBinanceKey; + private String privatePoloniex; + final private String hitBalanceUrl = "https://api.hitbtc.com/api/2/trading/balance"; + final private String detailUrl = "https://www.cryptocompare.com/api/data/coinlist/"; + final private String binanceBalanceUrl = "https://api.binance.com/api/v3/account"; + final private String binanceTimeUrl = "https://api.binance.com/api/v1/time"; + private RequestQueue requestQueue; + private List hitBalance; + private List otherBalances; + private List totalBalance; + private android.content.Context context; + private Map iconUrlList; + private Map coinList; + private PreferencesManager preferenceManager; + + public BalanceManager(android.content.Context context) + { + this.context = context; + preferenceManager = new PreferencesManager(context); + requestQueue = Volley.newRequestQueue(context); + hitBalance = new ArrayList(); + otherBalances = new ArrayList(); + } + + public List getCurrenciesName() + { + return new ArrayList<>(coinList.values()); + } + + public List getCurrenciesSymbol() + { + return new ArrayList<>(coinList.keySet()); + } + + public void updateExchangeKeys() + { + publicHitKey = preferenceManager.getHitBTCPublicKey(); + privateHitKey = preferenceManager.getHitBTCPrivateKey(); + } + + public boolean isHitBTCConfigured() + { + boolean isConfigured = true; + + if(publicHitKey == null || privateHitKey == null) + { + isConfigured = false; + } + + return isConfigured; + } + + public void setPublicHitKey(String newKey) + { + publicHitKey = newKey; + } + + public void setPrivateHitKey(String newKey) + { + privateHitKey = newKey; + } + + public List getTotalBalance() + { + return totalBalance; + } + + public List getHitBalance() + { + return hitBalance; + } + + public List getOtherBalances() + { + return otherBalances; + } + + public void updateTotalBalance(final VolleyCallBack callBack) + { + if(privateHitKey != null && publicHitKey != null && preferenceManager.isHitBTCActivated()) + { + updateHitBalance(callBack); + } + else + { + hitBalance = new ArrayList(); + refreshAllBalances(callBack); + } + } + + private void updateHitBalance(final VolleyCallBack callBack) + { + JsonArrayRequest arrReq = new JsonArrayRequest(Request.Method.GET, hitBalanceUrl, + new Response.Listener() { + @Override + public void onResponse(JSONArray response) { + if (response.length() > 0) { + + parseHitBalance(response); + refreshAllBalances(callBack); + + } else { + //No balance + } + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Log.e(context.getResources().getString(R.string.debug_volley), "API Error : " + error.toString() + ":"); + callBack.onError(error.toString()); + } + } + ) { + @Override + public Map getHeaders()throws AuthFailureError { + Map headers = new HashMap<>(); + String credentials = publicHitKey + ":" + privateHitKey; + String auth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); + headers.put("Content-Type", "application/json"); + headers.put("Authorization", auth); + + return headers; + } + }; + + requestQueue.add(arrReq); + } + + private void parseHitBalance(JSONArray response) + { + hitBalance = new ArrayList<>(); + + for (int i = 0; i < response.length(); i++) + { + try { + JSONObject jsonObj = response.getJSONObject(i); + + if(Float.parseFloat(jsonObj.getString("available")) > 0) + { + hitBalance.add(new Currency(jsonObj.getString("currency"), Double.parseDouble(jsonObj.getString("available")))); + } + + } catch (JSONException e) { + Log.e(context.getResources().getString(R.string.debug_volley), "Invalid JSON Object"); + } + } + } + + private void refreshAllBalances(final VolleyCallBack callBack) + { + totalBalance = new ArrayList<>(); + + totalBalance.addAll(hitBalance); + + for(int i = 0; i < otherBalances.size(); i++) + { + boolean isIn = false; + + for(int j = 0; j < totalBalance.size(); j++) + { + if(otherBalances.get(i).getSymbol().equals(totalBalance.get(j).getSymbol())) + { + totalBalance.get(j).setBalance(totalBalance.get(j).getBalance() + otherBalances.get(i).getBalance()); + + isIn = true; + } + } + + if(!isIn) + { + totalBalance.add(otherBalances.get(i)); + } + } + + callBack.onSuccess(); + } + + public interface VolleyCallBack { + void onSuccess(); + void onError(String error); + } + + public interface IconCallBack { + void onSuccess(); + } + + public void sortCoins() + { + for(int i = 0; i < totalBalance.size(); i++) + { + for(int j = i; j < totalBalance.size(); j++) + { + if(totalBalance.get(j).getBalance() * totalBalance.get(j).getValue() > totalBalance.get(i).getBalance() * totalBalance.get(i).getValue()) + { + Currency temp = totalBalance.get(j); + totalBalance.set(j, totalBalance.get(i)); + totalBalance.set(i, temp); + } + } + } + } + + public void updateDetails(final IconCallBack callBack) + { + StringRequest strRequest = new StringRequest(Request.Method.GET, detailUrl, + new Response.Listener() { + @Override + public void onResponse(String response) { + if (response.length() > 0) { + processDetailResult(response, callBack); + } + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + + } + }); + + requestQueue.add(strRequest); + } + + public String getIconUrl(String symbol) + { + return iconUrlList.get(symbol); + } + + private void processDetailResult(String response, final IconCallBack callBack) + { + response = response.substring(response.indexOf("\"Data\"") + 7, response.lastIndexOf("},\"Type\":100}")); + String[] tab = response.split(Pattern.quote("},")); + + iconUrlList = new HashMap<>(); + coinList = new HashMap<>(); + + for(int i = 0; i < tab.length; i++) + { + tab[i] = tab[i].substring(tab[i].indexOf("\":{")+2, tab[i].length()) + "}"; + try { + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); + JSONObject jsonObject = new JSONObject(tab[i]); + + iconUrlList.put(jsonObject.getString("Symbol"), "https://www.cryptocompare.com" + jsonObject.getString("ImageUrl") + "?width=50"); + + coinList.put(jsonObject.getString("Symbol"), jsonObject.getString("CoinName")); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + callBack.onSuccess(); + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/Currency.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/Currency.java new file mode 100644 index 0000000..bb3401c --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/Currency.java @@ -0,0 +1,154 @@ +package com.nauk.coinfolio.DataManagers.CurrencyData; + +import android.graphics.Bitmap; + +import java.util.List; + +/** + * Created by Tiji on 25/12/2017. + */ + +public class Currency { + + private String name; + private String symbol; + private double value; + private double balance; + private float dayFluctuationPercentage; + private double dayFluctuation; + private List dayPriceHistory; + private CurrencyDataRetriver dataRetriver; + private Bitmap icon; + + public Currency(String symbol, double balance) + { + this.symbol = symbol; + this.balance = balance; + } + + public Currency(String symbol, String name, double balance) + { + this.symbol = symbol; + this.name = name; + this.balance = balance; + } + + public Currency(String name, String symbol) + { + this.name = name; + this.symbol = symbol; + } + + public void updateDayPriceHistory(android.content.Context context, final CurrencyCallBack callBack) + { + dataRetriver = new CurrencyDataRetriver(context); + dataRetriver.updateLastDayHistory(symbol, new CurrencyDataRetriver.DataChartCallBack() { + @Override + public void onSuccess(List dataChart) { + setDayPriceHistory(dataChart); + updateDayFluctuation(); + + setValue(dataChart.get(dataChart.size() - 1).getClose()); + + callBack.onSuccess(Currency.this); + } + }); + } + + public void updateName(android.content.Context context, final CurrencyCallBack callBack) + { + dataRetriver = new CurrencyDataRetriver(context); + dataRetriver.updateCurrencyName(symbol, new CurrencyDataRetriver.NameCallBack() { + @Override + public void onSuccess(String name) { + if(name != null) + { + setName(name); + } + else + { + setName("NameNotFound"); + } + + callBack.onSuccess(Currency.this); + } + }); + } + + public List getDayPriceHistory() + { + return dayPriceHistory; + } + + public String getName() + { + return name; + } + + public void setName(String newName) + { + name = newName; + } + + public String getSymbol() + { + return symbol; + } + + public double getValue() + { + return value; + } + + public void setValue(double newValue) + { + value = newValue; + } + + public double getBalance() + { + return balance; + } + + public float getDayFluctuationPercentage() + { + return dayFluctuationPercentage; + } + + public double getDayFluctuation() + { + return dayFluctuation; + } + + public void setBalance(double newBalance) + { + balance = newBalance; + } + + private void setDayPriceHistory(List newDataChart) + { + dayPriceHistory = newDataChart; + } + + public void setIcon(Bitmap newIcon) + { + icon = newIcon; + } + + public Bitmap getIcon() + { + return icon; + } + + private void updateDayFluctuation() + { + dayFluctuation = dayPriceHistory.get(dayPriceHistory.size() - 1).getOpen() - dayPriceHistory.get(0).getOpen(); + + dayFluctuationPercentage = (float) (dayFluctuation / dayPriceHistory.get(0).getOpen() * 100); + } + + public interface CurrencyCallBack { + void onSuccess(Currency currency); + } + +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataChart.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataChart.java new file mode 100644 index 0000000..df11263 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataChart.java @@ -0,0 +1,38 @@ +package com.nauk.coinfolio.DataManagers.CurrencyData; + +/** + * Created by Tiji on 05/01/2018. + */ + +public class CurrencyDataChart { + + long timestamp; + double close; + double high; + double low; + double open; + + public CurrencyDataChart(long timestamp, double close, double high, double low, double open) + { + this.timestamp = timestamp; + this.close = close; + this.high = high; + this.low = low; + this.open = open; + } + + public double getOpen() + { + return open; + } + + public double getClose() + { + return close; + } + + public long getTimestamp() + { + return timestamp; + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataRetriver.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataRetriver.java new file mode 100644 index 0000000..421e240 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/CurrencyData/CurrencyDataRetriver.java @@ -0,0 +1,169 @@ +package com.nauk.coinfolio.DataManagers.CurrencyData; + +import android.util.Log; + +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.StringRequest; +import com.android.volley.toolbox.Volley; +import com.nauk.coinfolio.R; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Created by Tiji on 05/01/2018. + */ + +public class CurrencyDataRetriver { + + String minuteHistoryUrl = "https://min-api.cryptocompare.com/data/histominute"; + String hourHistoryUrl = "https://min-api.cryptocompare.com/data/histohour"; + String dayHistoryUrl = "https://min-api.cryptocompare.com/data/histoday"; + String nameUrl = "https://api.hitbtc.com/api/2/public/currency/"; + + RequestQueue requestQueue; + + android.content.Context context; + + public CurrencyDataRetriver(android.content.Context context) + { + this.context = context; + + requestQueue = Volley.newRequestQueue(context); + } + + public void updateLastHourHistory(String symbolCurrencyFrom, String symbolCyrrencyTo, final DataChartCallBack callBack) + { + final String requestUrl = minuteHistoryUrl + "?fsym=" + symbolCurrencyFrom + "&tsym=" + symbolCyrrencyTo + "&limit=60"; + + StringRequest stringRequest = new StringRequest(Request.Method.GET, requestUrl, + new Response.Listener() { + @Override + public void onResponse(String response) { + callBack.onSuccess(processHourResult(response)); + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + + } + }); + + requestQueue.add(stringRequest); + } + + public void updateCurrencyName(String symbol, final NameCallBack callBack) + { + final String requestUrl = nameUrl + symbol; + + StringRequest stringRequest = new StringRequest(Request.Method.GET, requestUrl, + new Response.Listener() { + @Override + public void onResponse(String response) { + response = response.substring(response.indexOf(",") + 13); + response = response.substring(0, response.indexOf(",") - 1); + + callBack.onSuccess(response); + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + callBack.onSuccess(null); + } + }); + + requestQueue.add(stringRequest); + } + + public void updateLastDayHistory(String symbolCurrencyFrom, String symbolCyrrencyTo, final DataChartCallBack callBack) + { + final String requestUrl = minuteHistoryUrl + "?fsym=" + symbolCurrencyFrom + "&tsym=" + symbolCyrrencyTo + "&limit=1440"; + + StringRequest stringRequest = new StringRequest(Request.Method.GET, requestUrl, + new Response.Listener() { + @Override + public void onResponse(String response) { + callBack.onSuccess(processHourResult(response)); + } + }, + new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + + } + }); + + requestQueue.add(stringRequest); + } + + private List processHourResult(String response) + { + List dataChart = new ArrayList<>(); + + response = response.substring(response.indexOf("Data\":[{") + 7, response.lastIndexOf("}],\"TimeTo")); + String[] tab = response.split(Pattern.quote("},{")); + for(int i = 0; i < tab.length; i++) + { + + if(i == 0) + { + tab[i] = tab[i] + "}"; + } + else + { + tab[i] = "{" + tab[i] + "}"; + } + + try { + JSONObject jsonObject = new JSONObject(tab[i]); + + long timestamp = Long.parseLong(jsonObject.getString("time")); + double close = Double.parseDouble(jsonObject.getString("close")); + double high = Double.parseDouble(jsonObject.getString("high")); + double low = Double.parseDouble(jsonObject.getString("low")); + double open = Double.parseDouble(jsonObject.getString("open")); + + dataChart.add(new CurrencyDataChart(timestamp, close, high, low, open)); + + } catch (JSONException e) { + Log.d(context.getResources().getString(R.string.debug_volley), "API Request error: " + e + " index: " + i); + } + } + + return dataChart; + } + + public void updateLastHourHistory(String symbolCurrencyFrom, final DataChartCallBack callBack) + { + updateLastHourHistory(symbolCurrencyFrom, "USD", callBack); + } + + public void updateLastDayHistory(String symbolCurrencyFrom, final DataChartCallBack callBack) + { + if(!symbolCurrencyFrom.equals("USD")) + { + updateLastDayHistory(symbolCurrencyFrom, "USD", callBack); + } + } + + public interface DataChartCallBack { + void onSuccess(List dataChart); + } + + public interface CurrencyDetailCallBack { + void onSuccess(); + } + + public interface NameCallBack { + void onSuccess(String name); + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/DatabaseManager.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/DatabaseManager.java new file mode 100644 index 0000000..01aa8c6 --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/DatabaseManager.java @@ -0,0 +1,113 @@ +package com.nauk.coinfolio.DataManagers; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Guitoune on 14/01/2018. + */ + +public class DatabaseManager extends SQLiteOpenHelper{ + + private static final int DATABASE_VERSION = 4; + + private static final String DATABASE_NAME = "Currencies.db"; + + private static final String TABLE_MANUAL_CURRENCIES = "ManualCurrencies"; + private static final String TABLE_EXCHANGE_KEYS = "ExchangeKeys"; + + private static final String KEY_CURRENCY_ID = "idCurrency"; + private static final String KEY_CURRENCY_SYMBOL = "symbol"; + private static final String KEY_CURRENCY_NAME = "name"; + private static final String KEY_CURRENCY_BALANCE = "balance"; + private static final String KEY_CURRENCY_DATE = "addDate"; + private static final String KEY_CURRENCY_PURCHASED_PRICE = "purchasedPrice"; + private static final String KEY_CURRENCY_IS_MINED = "isMined"; + + private static final String KEY_EXCHANGE_ID = "idExchange"; + private static final String KEY_EXCHANGE_NAME = "name"; + private static final String KEY_EXCHANGE_PUBLIC_KEY = "publicKey"; + private static final String KEY_EXCHANGE_SECRET_KEY = "secretKey"; + + public DatabaseManager(Context context) + { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) + { + db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_MANUAL_CURRENCIES + "(" + + KEY_CURRENCY_ID + " INTEGER PRIMARY KEY," + + KEY_CURRENCY_SYMBOL + " VARCHAR(4)," + + KEY_CURRENCY_NAME + " VARCHAR(45)," + + KEY_CURRENCY_BALANCE + " TEXT," + + KEY_CURRENCY_DATE + " DATE," + + KEY_CURRENCY_PURCHASED_PRICE + " TEXT," + + KEY_CURRENCY_IS_MINED + " INTEGER" + + ");"); + + db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_EXCHANGE_KEYS + "(" + + KEY_EXCHANGE_ID + " INTEGER PRIMARY KEY," + + KEY_EXCHANGE_NAME + " TEXT," + + KEY_EXCHANGE_PUBLIC_KEY + " TEXT," + + KEY_EXCHANGE_SECRET_KEY + " TEXT" + + ");"); + + //loadSample(db); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_MANUAL_CURRENCIES); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_EXCHANGE_KEYS); + + onCreate(db); + } + + public void addCurrencyToManualCurrency(String symbol, double balance) + { + SQLiteDatabase db = this.getWritableDatabase(); + ContentValues values = new ContentValues(); + + values.put(KEY_CURRENCY_SYMBOL, symbol); + values.put(KEY_CURRENCY_BALANCE, balance); + //values.put(KEY_CURRENCY_DATE, getDate()); + //values.put(KEY_CURRENCY_PURCHASED_PRICE, something); + + db.insert(TABLE_MANUAL_CURRENCIES, null, values); + db.close(); + } + + public List getAllCurrencyFromManualCurrency() + { + String searchQuerry = "SELECT * FROM " + TABLE_MANUAL_CURRENCIES; + SQLiteDatabase db = this.getWritableDatabase(); + Cursor resultatList = db.rawQuery(searchQuerry, null); + + List currencyList = new ArrayList<>(); + + while(resultatList.moveToNext()) + { + //Currency currency = new Currency(resultatList.getString(1), resultatList.getString(2)); + Log.d("CrystalVault", "Database result : " + resultatList.getString(1) + " " + resultatList.getString(2) + " " + resultatList.getCount()); + //currencyList.add(new Currency(resultatList.getString(1), resultatList.getDouble(2))); + } + + resultatList.close(); + + db.close(); + + return currencyList; + } +} diff --git a/app/src/main/java/com/nauk/coinfolio/DataManagers/PreferencesManager.java b/app/src/main/java/com/nauk/coinfolio/DataManagers/PreferencesManager.java new file mode 100644 index 0000000..be1fb1b --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/DataManagers/PreferencesManager.java @@ -0,0 +1,68 @@ +package com.nauk.coinfolio.DataManagers; + +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +/** + * Created by Guitoune on 09/01/2018. + */ + +public class PreferencesManager { + + private static final String currencyListFile = "CustomCurrencies"; + private static final String preferencesFile = "Preferences"; + private SharedPreferences settingPreferences; + private SharedPreferences currencyList; + private SharedPreferences preferencesList; + android.content.Context context; + + public PreferencesManager(android.content.Context context) + { + this.context = context; + settingPreferences = PreferenceManager.getDefaultSharedPreferences(context); + currencyList = context.getSharedPreferences(currencyListFile, 0); + preferencesList = context.getSharedPreferences(preferencesFile, 0); + } + + public void addCurrency(String symbol, double balance) + { + SharedPreferences.Editor editor = currencyList.edit(); + editor.putString(symbol, String.valueOf(balance)); + editor.apply(); + } + + public void setDetailOption(boolean isExtended) + { + SharedPreferences.Editor editor = preferencesList.edit(); + editor.putBoolean("DetailOption", isExtended); + editor.apply(); + } + + public boolean getDetailOption() + { + return preferencesList.getBoolean("DetailOption", true); + } + + public String getHitBTCPublicKey() + { + return settingPreferences.getString("hitbtc_publickey", null); + } + + public String getHitBTCPrivateKey() + { + return settingPreferences.getString("hitbtc_privatekey", null); + } + + public boolean isHitBTCActivated() + { + return settingPreferences.getBoolean("enable_hitbtc", false); + } + + public void disableHitBTC() + { + SharedPreferences.Editor editor = settingPreferences.edit(); + editor.putBoolean("enable_hitbtc", false); + editor.apply(); + } + +} diff --git a/app/src/main/java/com/nauk/coinfolio/LayoutManagers/CurrencyAdapter.java b/app/src/main/java/com/nauk/coinfolio/LayoutManagers/CurrencyAdapter.java new file mode 100644 index 0000000..fda78eb --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/LayoutManagers/CurrencyAdapter.java @@ -0,0 +1,104 @@ +package com.nauk.coinfolio.LayoutManagers; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Filter; +import android.widget.TextView; + +import java.util.ArrayList; + +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; +import com.nauk.coinfolio.R; + +/** + * Created by Guitoune on 17/01/2018. + */ + +public class CurrencyAdapter extends ArrayAdapter { + + private ArrayList Currencys, tempCurrency, suggestions; + private Context context; + + public CurrencyAdapter(Context context, ArrayList objects) { + super(context, android.R.layout.simple_list_item_1, objects); + this.Currencys = objects; + this.tempCurrency = new ArrayList(objects); + this.suggestions = new ArrayList(objects); + + this.context = context; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Currency currency = getItem(position); + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom_row, parent, false); + } + TextView currencyName = (TextView) convertView.findViewById(R.id.currencyName); + TextView currencySymbol = (TextView) convertView.findViewById(R.id.currencySymbol); + if (currencyName != null) + currencyName.setText(currency.getName()); + if(currencySymbol != null) + { + currencySymbol.setText(currency.getSymbol()); + } + // Now assign alternate color for rows + if (position % 2 == 0) + convertView.setBackgroundColor(context.getResources().getColor(R.color.listBackground)); + else + convertView.setBackgroundColor(context.getResources().getColor(R.color.listBackground2)); + + return convertView; + } + + + @Override + public Filter getFilter() { + return myFilter; + } + + Filter myFilter = new Filter() { + @Override + public CharSequence convertResultToString(Object resultValue) { + Currency currency = (Currency) resultValue; + return currency.getName(); + } + + @Override + protected FilterResults performFiltering(CharSequence constraint) { + if (constraint != null) { + suggestions.clear(); + + String temp = constraint.toString().toLowerCase(); + for (Currency currency : tempCurrency) { + if (currency.getName().toLowerCase().startsWith(temp) + || currency.getSymbol().toLowerCase().startsWith(temp)) { + suggestions.add(currency); + } + } + + FilterResults filterResults = new FilterResults(); + filterResults.values = suggestions; + filterResults.count = suggestions.size(); + return filterResults; + } else { + return new FilterResults(); + } + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + ArrayList c = (ArrayList) results.values; + if (results != null && results.count > 0) { + clear(); + for (Currency currency : c) { + add(currency); + notifyDataSetChanged(); + } + } + } + }; +} diff --git a/app/src/main/java/com/nauk/coinfolio/LayoutManagers/HomeLayoutGenerator.java b/app/src/main/java/com/nauk/coinfolio/LayoutManagers/HomeLayoutGenerator.java new file mode 100644 index 0000000..591a9ae --- /dev/null +++ b/app/src/main/java/com/nauk/coinfolio/LayoutManagers/HomeLayoutGenerator.java @@ -0,0 +1,334 @@ +package com.nauk.coinfolio.LayoutManagers; + +import android.animation.AnimatorInflater; +import android.animation.StateListAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.support.design.widget.Snackbar; +import android.support.v7.widget.CardView; +import android.view.Gravity; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.db.chart.model.LineSet; +import com.db.chart.renderer.AxisRenderer; +import com.db.chart.view.LineChartView; +import com.nauk.coinfolio.DataManagers.CurrencyData.Currency; +import com.nauk.coinfolio.DataManagers.CurrencyData.CurrencyDataChart; +import com.nauk.coinfolio.R; + +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +import static java.lang.Math.abs; + +/** + * Created by Tiji on 05/01/2018. + */ + +public class HomeLayoutGenerator { + + android.content.Context context; + + public HomeLayoutGenerator(Context context) + { + this.context = context; + } + + public CardView getInfoLayout(Currency currency, int chartColor) + { + CardView mainCard = new CardView(context); + LinearLayout mainLinear = new LinearLayout(context); + View separationLine = new View(context); + LinearLayout chartLayout = new LinearLayout(context); + LinearLayout infoLayout = new LinearLayout(context); + LinearLayout separatorLayout = new LinearLayout(context); + TextView separatorTextView = new TextView(context); + + StateListAnimator stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.drawable.cardview_animator); + mainCard.setStateListAnimator(stateListAnimator); + + /*int[] attrs = new int[] { R.attr.selectableItemBackground }; + TypedArray ta = context.obtainStyledAttributes(attrs); + Drawable drawable = ta.getDrawable(0); + ta.recycle(); + + mainCard.setBackground(drawable);*/ + + mainCard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + view.animate(); + Snackbar.make(view, "This feature is not yet available...", Snackbar.LENGTH_LONG) + .show(); + } + }); + mainCard.setClickable(true); + + CardView.LayoutParams paramsCard = new CardView.LayoutParams(CardView.LayoutParams.MATCH_PARENT, CardView.LayoutParams.WRAP_CONTENT); + paramsCard.setMargins(10, 10, 10, 30); + + LinearLayout.LayoutParams paramsInfo = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + paramsInfo.setMargins(10, 10, 10, 10); + + chartLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + LinearLayout.LayoutParams separatorParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 3); + separatorParams.gravity = Gravity.CENTER_VERTICAL; + separatorParams.setMargins(10, 0, 10, 0); + + separationLine.setLayoutParams(separatorParams); + separationLine.setBackgroundColor(context.getResources().getColor(R.color.separationLine)); + + LinearLayout.LayoutParams separatorLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + separatorLayoutParams.setMargins(10, 0, 10, 0); + separatorLayout.setLayoutParams(separatorLayoutParams); + + separatorTextView.setText("Day history"); + separatorTextView.setTextSize(context.getResources().getDimension(R.dimen.secondaryText)); + + separatorLayout.addView(separatorTextView); + separatorLayout.addView(separationLine); + separatorLayout.setTag("separator_layout"); + + infoLayout.setLayoutParams(paramsInfo); + infoLayout.setOrientation(LinearLayout.VERTICAL); + + mainLinear.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + mainLinear.setOrientation(LinearLayout.VERTICAL); + + mainCard.setLayoutParams(paramsCard); + mainCard.setRadius(8); + + infoLayout.addView(topLayoutGenerator(currency.getName(), currency.getSymbol(), currency.getValue(), currency.getIcon())); + infoLayout.addView(bottomLayoutGenerator(currency.getSymbol(), currency.getBalance(), currency.getValue() * currency.getBalance(), currency.getDayFluctuationPercentage(), currency.getDayFluctuation())); + + mainLinear.addView(infoLayout); + + LineChartView lineChartView = chartGenerator(currency.getDayPriceHistory(), chartColor); + chartLayout.setTag("chart_layout"); + chartLayout.addView(lineChartView); + lineChartView.show(); + mainLinear.addView(separatorLayout); + mainLinear.addView(chartLayout); + + mainCard.addView(mainLinear); + + return mainCard; + } + + private LinearLayout topLayoutGenerator(String name, String symbol, double value, Bitmap logo) + { + LinearLayout mainLayout = new LinearLayout(context); + TextView nameTextView = new TextView(context); + TextView symbolTextView = new TextView(context); + TextView valueTextView = new TextView(context); + ImageView currencyIcon = new ImageView(context); + + mainLayout.setOrientation(LinearLayout.HORIZONTAL); + mainLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + iconParams.setMargins(5, 5, 5, 5); + currencyIcon.setLayoutParams(iconParams); + currencyIcon.setImageBitmap(logo); + + nameTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + nameTextView.setTextSize(context.getResources().getDimension(R.dimen.mainText)); + nameTextView.setTextColor(context.getResources().getColor(R.color.mainTextViewColor)); + nameTextView.setGravity(Gravity.LEFT); + nameTextView.setText(name); + + symbolTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + symbolTextView.setTextSize(context.getResources().getDimension(R.dimen.secondaryText)); + symbolTextView.setTextColor(context.getResources().getColor(R.color.secondaryTextViewColor)); + symbolTextView.setGravity(Gravity.LEFT); + symbolTextView.setText(" (" + symbol + ")"); + + valueTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + valueTextView.setTextSize(context.getResources().getDimension(R.dimen.mainText)); + valueTextView.setTextColor(context.getResources().getColor(R.color.secondaryTextViewColor)); + valueTextView.setGravity(Gravity.RIGHT); + valueTextView.setText("US$" + value); + + mainLayout.addView(currencyIcon); + mainLayout.addView(nameTextView); + mainLayout.addView(symbolTextView); + mainLayout.addView(valueTextView); + + return mainLayout; + } + + private LinearLayout bottomLayoutGenerator(String symbol, double owned, double value, float percentageFluctuation, double fluctuation) + { + LinearLayout mainLayout = new LinearLayout(context); + LinearLayout secondaryLayout = new LinearLayout(context); + TextView ownedTextView = new TextView(context); + TextView valueTextView = new TextView(context); + TextView percentageFluctuationTextView = new TextView(context); + TextView fluctuationTextView = new TextView(context); + + mainLayout.setOrientation(LinearLayout.HORIZONTAL); + mainLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + + secondaryLayout.setOrientation(LinearLayout.HORIZONTAL); + secondaryLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + secondaryLayout.setGravity(Gravity.RIGHT); + + ownedTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + ownedTextView.setTextSize(context.getResources().getDimension(R.dimen.mainText)); + ownedTextView.setTextColor(context.getResources().getColor(R.color.mainTextViewColor)); + ownedTextView.setGravity(Gravity.LEFT); + ownedTextView.setText(numberConformer(owned) + symbol); + + valueTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + valueTextView.setTextSize(context.getResources().getDimension(R.dimen.secondaryText)); + valueTextView.setTextColor(context.getResources().getColor(R.color.secondaryTextViewColor)); + valueTextView.setGravity(Gravity.LEFT); + valueTextView.setText(" (" + numberConformer(value) + "$)"); + + percentageFluctuationTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + percentageFluctuationTextView.setTextSize(context.getResources().getDimension(R.dimen.mainText)); + if(percentageFluctuation > 0) + { + percentageFluctuationTextView.setTextColor(context.getResources().getColor(R.color.increase)); + } + else + { + percentageFluctuationTextView.setTextColor(context.getResources().getColor(R.color.decrease)); + } + //percentageFluctuationTextView.setGravity(Gravity.RIGHT); + percentageFluctuationTextView.setText(numberConformer(percentageFluctuation) + "%"); + + fluctuationTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + fluctuationTextView.setTextSize(context.getResources().getDimension(R.dimen.secondaryText)); + if(fluctuation > 0) + { + fluctuationTextView.setTextColor(context.getResources().getColor(R.color.increase)); + } + else + { + fluctuationTextView.setTextColor(context.getResources().getColor(R.color.decrease)); + } + //fluctuationTextView.setGravity(Gravity.RIGHT); + fluctuationTextView.setText(" (" + numberConformer(fluctuation) + "$)"); + + secondaryLayout.addView(percentageFluctuationTextView); + secondaryLayout.addView(fluctuationTextView); + + mainLayout.addView(ownedTextView); + mainLayout.addView(valueTextView); + mainLayout.addView(secondaryLayout); + //mainLayout.addView(percentageFluctuationTextView); + //mainLayout.addView(fluctuationTextView); + + return mainLayout; + } + + private LineChartView chartGenerator(List dataChartList, int chartColor) + { + LineChartView chartView = new LineChartView(context); + LineSet lineSet = new LineSet(); + double valMin; + double valMax; + int counter = 0; + Calendar calendar = Calendar.getInstance(Locale.FRANCE); + String hour; + String minute; + + valMin = dataChartList.get(0).getOpen(); + valMax = dataChartList.get(0).getOpen(); + for(int i = 1; i < dataChartList.size(); i++) + { + if(valMax < dataChartList.get(i).getOpen()) + { + valMax = dataChartList.get(i).getOpen(); + } + + if(valMin > dataChartList.get(i).getOpen()) + { + valMin = dataChartList.get(i).getOpen(); + } + } + + chartView.setAxisBorderValues((float) valMin, (float) valMax); + chartView.setYLabels(AxisRenderer.LabelPosition.NONE); + chartView.setYAxis(false); + chartView.setXAxis(false); + + for(int i = 0; i < dataChartList.size(); i+=10) + { + if(counter == 30) + { + calendar.setTimeInMillis(dataChartList.get(i).getTimestamp()*1000); + + hour = String.valueOf(calendar.get(Calendar.HOUR_OF_DAY)); + minute = String.valueOf(calendar.get(Calendar.MINUTE)); + + if(hour.length() < 2) + { + hour = "0" + hour; + } + + if(minute.length() < 2) + { + minute = "0" + minute; + } + + lineSet.addPoint(hour + ":" + minute, (float) dataChartList.get(i).getOpen()); + counter = 0; + } + else + { + counter++; + lineSet.addPoint("", (float) dataChartList.get(i).getOpen()); + } + + + } + + lineSet.setSmooth(true); + lineSet.setThickness(4); + lineSet.setFill(getColorWithAplha(chartColor, 0.5f)); + lineSet.setColor(chartColor); + + chartView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 500)); + + chartView.setTag("Chart"); + + chartView.addData(lineSet); + + return chartView; + } + + private int getColorWithAplha(int color, float ratio) + { + int transColor; + int alpha = Math.round(Color.alpha(color) * ratio); + int r = Color.red(color); + int g = Color.green(color); + int b = Color.blue(color); + transColor = Color.argb(alpha, r, g, b); + return transColor ; + } + + private String numberConformer(double number) + { + String str; + + if(abs(number) > 1) + { + str = String.format("%.2f", number); + } + else + { + str = String.format("%.4f", number); + } + + return str; + } +} diff --git a/app/src/main/res/anim/fade_in_dialog.xml b/app/src/main/res/anim/fade_in_dialog.xml new file mode 100644 index 0000000..05d2699 --- /dev/null +++ b/app/src/main/res/anim/fade_in_dialog.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/fade_out_dialog.xml b/app/src/main/res/anim/fade_out_dialog.xml new file mode 100644 index 0000000..979ccb4 --- /dev/null +++ b/app/src/main/res/anim/fade_out_dialog.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/zoom_in.xml b/app/src/main/res/anim/zoom_in.xml new file mode 100644 index 0000000..3272b05 --- /dev/null +++ b/app/src/main/res/anim/zoom_in.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/zoom_out.xml b/app/src/main/res/anim/zoom_out.xml new file mode 100644 index 0000000..52dbe8c --- /dev/null +++ b/app/src/main/res/anim/zoom_out.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/cardview_animator.xml b/app/src/main/res/drawable/cardview_animator.xml new file mode 100644 index 0000000..7306f5c --- /dev/null +++ b/app/src/main/res/drawable/cardview_animator.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/crystal_background.xml b/app/src/main/res/drawable/crystal_background.xml new file mode 100644 index 0000000..5b604b8 --- /dev/null +++ b/app/src/main/res/drawable/crystal_background.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable/crystal_cave.png b/app/src/main/res/drawable/crystal_cave.png new file mode 100644 index 0000000..ac3b31c Binary files /dev/null and b/app/src/main/res/drawable/crystal_cave.png differ diff --git a/app/src/main/res/drawable/gradient_background.xml b/app/src/main/res/drawable/gradient_background.xml new file mode 100644 index 0000000..fae6990 --- /dev/null +++ b/app/src/main/res/drawable/gradient_background.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_button.xml b/app/src/main/res/drawable/gradient_button.xml new file mode 100644 index 0000000..dae2bff --- /dev/null +++ b/app/src/main/res/drawable/gradient_button.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_black_24dp.xml new file mode 100644 index 0000000..0258249 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml new file mode 100644 index 0000000..2483512 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_details_black_24dp.xml b/app/src/main/res/drawable/ic_details_black_24dp.xml new file mode 100644 index 0000000..573bdb5 --- /dev/null +++ b/app/src/main/res/drawable/ic_details_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_developer_board_black_24dp.xml b/app/src/main/res/drawable/ic_developer_board_black_24dp.xml new file mode 100644 index 0000000..27d3805 --- /dev/null +++ b/app/src/main/res/drawable/ic_developer_board_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_info_black_24dp.xml b/app/src/main/res/drawable/ic_info_black_24dp.xml new file mode 100644 index 0000000..34b8202 --- /dev/null +++ b/app/src/main/res/drawable/ic_info_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..e3400cf --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_settings_black_24dp.xml b/app/src/main/res/drawable/ic_settings_black_24dp.xml new file mode 100644 index 0000000..dd6cf1c --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml new file mode 100644 index 0000000..5a283aa --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml b/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml new file mode 100644 index 0000000..1be5b9b --- /dev/null +++ b/app/src/main/res/drawable/ic_unfold_less_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/icon_crystalvault_background.xml b/app/src/main/res/drawable/icon_crystalvault_background.xml new file mode 100644 index 0000000..01f0af0 --- /dev/null +++ b/app/src/main/res/drawable/icon_crystalvault_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ripple_animation.xml b/app/src/main/res/drawable/ripple_animation.xml new file mode 100644 index 0000000..289d7e6 --- /dev/null +++ b/app/src/main/res/drawable/ripple_animation.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_corners.xml b/app/src/main/res/drawable/rounded_corners.xml new file mode 100644 index 0000000..6f1db34 --- /dev/null +++ b/app/src/main/res/drawable/rounded_corners.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/soft_gradient.xml b/app/src/main/res/drawable/soft_gradient.xml new file mode 100644 index 0000000..590cad2 --- /dev/null +++ b/app/src/main/res/drawable/soft_gradient.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_add_currency.xml b/app/src/main/res/layout/activity_add_currency.xml new file mode 100644 index 0000000..00488bf --- /dev/null +++ b/app/src/main/res/layout/activity_add_currency.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_currency_summary.xml b/app/src/main/res/layout/activity_currency_summary.xml new file mode 100644 index 0000000..764889a --- /dev/null +++ b/app/src/main/res/layout/activity_currency_summary.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_record_transaction.xml b/app/src/main/res/layout/activity_record_transaction.xml new file mode 100644 index 0000000..1509b01 --- /dev/null +++ b/app/src/main/res/layout/activity_record_transaction.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + +