mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 15:04:50 +01:00
wip
This commit is contained in:
parent
f76bec5753
commit
29aa934f8d
12 changed files with 805 additions and 408 deletions
|
@ -84,6 +84,12 @@ android {
|
|||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
assets.srcDirs = ['src/main/assets', 'src/main/res/assets']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// Caution! In production, you need to generate your own keystore file.
|
||||
|
@ -95,6 +101,13 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
task copyFiatUnits(type: Copy) {
|
||||
from '../../models/fiatUnits.json'
|
||||
into 'src/main/assets'
|
||||
}
|
||||
|
||||
preBuild.dependsOn(copyFiatUnits)
|
||||
|
||||
dependencies {
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
|
@ -110,6 +123,7 @@ dependencies {
|
|||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation "androidx.work:work-runtime:2.7.1"
|
||||
}
|
||||
apply plugin: 'com.google.gms.google-services' // Google Services plugin
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<uses-permission android:name="android.permission.ACTION_GET_CONTENT" />
|
||||
<uses-permission android:name="android.permission.ACTION_CREATE_DOCUMENT" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
|
@ -58,7 +59,8 @@
|
|||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
|
||||
<receiver
|
||||
android:name=".BitcoinPriceWidget"
|
||||
android:exported="true"
|
||||
android:label="Bitcoin Price Widget">
|
||||
|
@ -70,7 +72,6 @@
|
|||
android:resource="@xml/bitcoin_price_widget_info" />
|
||||
</receiver>
|
||||
|
||||
|
||||
<service
|
||||
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
|
||||
android:exported="false">
|
||||
|
|
408
android/app/src/main/assets/fiatUnits.json
Normal file
408
android/app/src/main/assets/fiatUnits.json
Normal file
|
@ -0,0 +1,408 @@
|
|||
{
|
||||
"USD": {
|
||||
"endPointKey": "USD",
|
||||
"locale": "en-US",
|
||||
"source": "Kraken",
|
||||
"symbol": "$",
|
||||
"country": "United States (US Dollar)"
|
||||
},
|
||||
"AED": {
|
||||
"endPointKey": "AED",
|
||||
"locale": "ar-AE",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "د.إ.",
|
||||
"country": "United Arab Emirates (UAE Dirham)"
|
||||
},
|
||||
"ANG": {
|
||||
"endPointKey": "ANG",
|
||||
"locale": "en-SX",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "ƒ",
|
||||
"country": "Sint Maarten (Netherlands Antillean Guilder)"
|
||||
},
|
||||
"ARS": {
|
||||
"endPointKey": "ARS",
|
||||
"locale": "es-AR",
|
||||
"source": "Yadio",
|
||||
"symbol": "$",
|
||||
"country": "Argentina (Argentine Peso)"
|
||||
},
|
||||
"AUD": {
|
||||
"endPointKey": "AUD",
|
||||
"locale": "en-AU",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "$",
|
||||
"country": "Australia (Australian Dollar)"
|
||||
},
|
||||
"AWG": {
|
||||
"endPointKey": "AWG",
|
||||
"locale": "nl-AW",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "ƒ",
|
||||
"country": "Aruba (Aruban Florin)"
|
||||
},
|
||||
"BHD": {
|
||||
"endPointKey": "BHD",
|
||||
"locale": "ar-BH",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "د.ب.",
|
||||
"country": "Bahrain (Bahraini Dinar)"
|
||||
},
|
||||
"BRL": {
|
||||
"endPointKey": "BRL",
|
||||
"locale": "pt-BR",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "R$",
|
||||
"country": "Brazil (Brazilian Real)"
|
||||
},
|
||||
"CAD": {
|
||||
"endPointKey": "CAD",
|
||||
"locale": "en-CA",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "$",
|
||||
"country": "Canada (Canadian Dollar)"
|
||||
},
|
||||
"CHF": {
|
||||
"endPointKey": "CHF",
|
||||
"locale": "de-CH",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "CHF",
|
||||
"country": "Switzerland (Swiss Franc)"
|
||||
},
|
||||
"CLP": {
|
||||
"endPointKey": "CLP",
|
||||
"locale": "es-CL",
|
||||
"source": "Yadio",
|
||||
"symbol": "$",
|
||||
"country": "Chile (Chilean Peso)"
|
||||
},
|
||||
"CNY": {
|
||||
"endPointKey": "CNY",
|
||||
"locale": "zh-CN",
|
||||
"source": "Coinbase",
|
||||
"symbol": "¥",
|
||||
"country": "China (Chinese Yuan)"
|
||||
},
|
||||
"COP": {
|
||||
"endPointKey": "COP",
|
||||
"locale": "es-CO",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "$",
|
||||
"country": "Colombia (Colombian Peso)"
|
||||
},
|
||||
"CZK": {
|
||||
"endPointKey": "CZK",
|
||||
"locale": "cs-CZ",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "Kč",
|
||||
"country": "Czech Republic (Czech Koruna)"
|
||||
},
|
||||
"DKK": {
|
||||
"endPointKey": "DKK",
|
||||
"locale": "da-DK",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "kr",
|
||||
"country": "Denmark (Danish Krone)"
|
||||
},
|
||||
"EUR": {
|
||||
"endPointKey": "EUR",
|
||||
"locale": "en-IE",
|
||||
"source": "Kraken",
|
||||
"symbol": "€",
|
||||
"country": "European Union (Euro)"
|
||||
},
|
||||
"GBP": {
|
||||
"endPointKey": "GBP",
|
||||
"locale": "en-GB",
|
||||
"source": "Kraken",
|
||||
"symbol": "£",
|
||||
"country": "United Kingdom (British Pound)"
|
||||
},
|
||||
"HRK": {
|
||||
"endPointKey": "HRK",
|
||||
"locale": "hr-HR",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "HRK",
|
||||
"country": "Croatia (Croatian Kuna)"
|
||||
},
|
||||
"HUF": {
|
||||
"endPointKey": "HUF",
|
||||
"locale": "hu-HU",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "Ft",
|
||||
"country": "Hungary (Hungarian Forint)"
|
||||
},
|
||||
"IDR": {
|
||||
"endPointKey": "IDR",
|
||||
"locale": "id-ID",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "Rp",
|
||||
"country": "Indonesia (Indonesian Rupiah)"
|
||||
},
|
||||
"ILS": {
|
||||
"endPointKey": "ILS",
|
||||
"locale": "he-IL",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₪",
|
||||
"country": "Israel (Israeli New Shekel)"
|
||||
},
|
||||
"INR": {
|
||||
"endPointKey": "INR",
|
||||
"locale": "hi-IN",
|
||||
"source": "wazirx",
|
||||
"symbol": "₹",
|
||||
"country": "India (Indian Rupee)"
|
||||
},
|
||||
"IRR": {
|
||||
"endPointKey": "IRR",
|
||||
"locale": "fa-IR",
|
||||
"source": "Exir",
|
||||
"symbol": "﷼",
|
||||
"country": "Iran (Iranian Rial)"
|
||||
},
|
||||
"IRT": {
|
||||
"endPointKey": "IRT",
|
||||
"locale": "fa-IR",
|
||||
"source": "Exir",
|
||||
"symbol": "تومان",
|
||||
"country": "Iran (Iranian Toman)"
|
||||
},
|
||||
"ISK": {
|
||||
"endPointKey": "ISK",
|
||||
"locale": "is-IS",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "kr",
|
||||
"country": "Iceland (Icelandic Króna)"
|
||||
},
|
||||
"JPY": {
|
||||
"endPointKey": "JPY",
|
||||
"locale": "ja-JP",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "¥",
|
||||
"country": "Japan (Japanese Yen)"
|
||||
},
|
||||
"KES": {
|
||||
"endPointKey": "KES",
|
||||
"locale": "en-KE",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "Ksh",
|
||||
"country": "Kenya (Kenyan Shilling)"
|
||||
},
|
||||
"KRW": {
|
||||
"endPointKey": "KRW",
|
||||
"locale": "ko-KR",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₩",
|
||||
"country": "South Korea (South Korean Won)"
|
||||
},
|
||||
"KWD": {
|
||||
"endPointKey": "KWD",
|
||||
"locale": "ar-KW",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "د.ك.",
|
||||
"country": "Kuwait (Kuwaiti Dinar)"
|
||||
},
|
||||
"LBP": {
|
||||
"endPointKey": "LBP",
|
||||
"locale": "ar-LB",
|
||||
"source": "YadioConvert",
|
||||
"symbol": "ل.ل.",
|
||||
"country": "Lebanon (Lebanese Pound)"
|
||||
},
|
||||
"LKR": {
|
||||
"endPointKey": "LKR",
|
||||
"locale": "si-LK",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "රු.",
|
||||
"country": "Sri Lanka (Sri Lankan Rupee)"
|
||||
},
|
||||
"MXN": {
|
||||
"endPointKey": "MXN",
|
||||
"locale": "es-MX",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "$",
|
||||
"country": "Mexico (Mexican Peso)"
|
||||
},
|
||||
"MYR": {
|
||||
"endPointKey": "MYR",
|
||||
"locale": "ms-MY",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "RM",
|
||||
"country": "Malaysia (Malaysian Ringgit)"
|
||||
},
|
||||
"MZN": {
|
||||
"endPointKey": "MZN",
|
||||
"locale": "seh-MZ",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "MTn",
|
||||
"country": "Mozambique (Mozambican Metical)"
|
||||
},
|
||||
"NGN": {
|
||||
"endPointKey": "NGN",
|
||||
"locale": "en-NG",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₦",
|
||||
"country": "Nigeria (Nigerian Naira)"
|
||||
},
|
||||
"NOK": {
|
||||
"endPointKey": "NOK",
|
||||
"locale": "nb-NO",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "kr",
|
||||
"country": "Norway (Norwegian Krone)"
|
||||
},
|
||||
"NZD": {
|
||||
"endPointKey": "NZD",
|
||||
"locale": "en-NZ",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "$",
|
||||
"country": "New Zealand (New Zealand Dollar)"
|
||||
},
|
||||
"OMR": {
|
||||
"endPointKey": "OMR",
|
||||
"locale": "ar-OM",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "ر.ع.",
|
||||
"country": "Oman (Omani Rial)"
|
||||
},
|
||||
"PHP": {
|
||||
"endPointKey": "PHP",
|
||||
"locale": "en-PH",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₱",
|
||||
"country": "Philippines (Philippine Peso)"
|
||||
},
|
||||
"PLN": {
|
||||
"endPointKey": "PLN",
|
||||
"locale": "pl-PL",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "zł",
|
||||
"country": "Poland (Polish Zloty)"
|
||||
},
|
||||
"QAR": {
|
||||
"endPointKey": "QAR",
|
||||
"locale": "ar-QA",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "ر.ق.",
|
||||
"country": "Qatar (Qatari Riyal)"
|
||||
},
|
||||
"RON": {
|
||||
"endPointKey": "RON",
|
||||
"locale": "ro-RO",
|
||||
"source": "BNR",
|
||||
"symbol": "lei",
|
||||
"country": "Romania (Romanian Leu)"
|
||||
},
|
||||
"RUB": {
|
||||
"endPointKey": "RUB",
|
||||
"locale": "ru-RU",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₽",
|
||||
"country": "Russia (Russian Ruble)"
|
||||
},
|
||||
"SAR": {
|
||||
"endPointKey": "SAR",
|
||||
"locale": "ar-SA",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "ر.س.",
|
||||
"country": "Saudi Arabia (Saudi Riyal)"
|
||||
},
|
||||
"SEK": {
|
||||
"endPointKey": "SEK",
|
||||
"locale": "sv-SE",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "kr",
|
||||
"country": "Sweden (Swedish Krona)"
|
||||
},
|
||||
"SGD": {
|
||||
"endPointKey": "SGD",
|
||||
"locale": "zh-SG",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "S$",
|
||||
"country": "Singapore (Singapore Dollar)"
|
||||
},
|
||||
"THB": {
|
||||
"endPointKey": "THB",
|
||||
"locale": "th-TH",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "฿",
|
||||
"country": "Thailand (Thai Baht)"
|
||||
},
|
||||
"TRY": {
|
||||
"endPointKey": "TRY",
|
||||
"locale": "tr-TR",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₺",
|
||||
"country": "Turkey (Turkish Lira)"
|
||||
},
|
||||
"TWD": {
|
||||
"endPointKey": "TWD",
|
||||
"locale": "zh-Hant-TW",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "NT$",
|
||||
"country": "Taiwan (New Taiwan Dollar)"
|
||||
},
|
||||
"TZS": {
|
||||
"endPointKey": "TZS",
|
||||
"locale": "en-TZ",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "TSh",
|
||||
"country": "Tanzania (Tanzanian Shilling)"
|
||||
},
|
||||
"UAH": {
|
||||
"endPointKey": "UAH",
|
||||
"locale": "uk-UA",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "₴",
|
||||
"country": "Ukraine (Ukrainian Hryvnia)"
|
||||
},
|
||||
"UGX": {
|
||||
"endPointKey": "UGX",
|
||||
"locale": "en-UG",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "USh",
|
||||
"country": "Uganda (Ugandan Shilling)"
|
||||
},
|
||||
"UYU": {
|
||||
"endPointKey": "UYU",
|
||||
"locale": "es-UY",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "$",
|
||||
"country": "Uruguay (Uruguayan Peso)"
|
||||
},
|
||||
"VEF": {
|
||||
"endPointKey": "VEF",
|
||||
"locale": "es-VE",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "Bs.",
|
||||
"country": "Venezuela (Venezuelan Bolívar Fuerte)"
|
||||
},
|
||||
"VES": {
|
||||
"endPointKey": "VES",
|
||||
"locale": "es-VE",
|
||||
"source": "Yadio",
|
||||
"symbol": "Bs.",
|
||||
"country": "Venezuela (Venezuelan Bolívar Soberano)"
|
||||
},
|
||||
"XAF": {
|
||||
"endPointKey": "XAF",
|
||||
"locale": "fr-CF",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "Fr",
|
||||
"country": "Central African Republic (Central African Franc)"
|
||||
},
|
||||
"ZAR": {
|
||||
"endPointKey": "ZAR",
|
||||
"locale": "en-ZA",
|
||||
"source": "CoinGecko",
|
||||
"symbol": "R",
|
||||
"country": "South Africa (South African Rand)"
|
||||
},
|
||||
"GHS": {
|
||||
"endPointKey": "GHS",
|
||||
"locale": "en-GH",
|
||||
"source": "CoinDesk",
|
||||
"symbol": "₵",
|
||||
"country": "Ghana (Ghanaian Cedi)"
|
||||
}
|
||||
}
|
|
@ -1,205 +1,78 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||
|
||||
private static final String TAG = "BitcoinPriceWidget";
|
||||
private static final String ACTION_UPDATE = "io.bluewallet.bluewallet.UPDATE";
|
||||
private static final String PREFS_NAME = "BitcoinPriceWidgetPrefs";
|
||||
private static final String PREF_PREFIX_KEY = "appwidget_";
|
||||
private static final int UPDATE_INTERVAL_MINUTES = 10; // Adjustable interval in minutes
|
||||
private static ExecutorService executorService;
|
||||
|
||||
@Override
|
||||
public void onEnabled(Context context) {
|
||||
super.onEnabled(context);
|
||||
initializeExecutorService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled(Context context) {
|
||||
super.onDisabled(context);
|
||||
if (executorService != null) {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
initializeExecutorService();
|
||||
if (appWidgetIds.length > 0) {
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
Log.d(TAG, "Updating widget ID: " + appWidgetId);
|
||||
Log.d(TAG, "Updating widget");
|
||||
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
|
||||
// Set up the pending intent to open the app when the widget is clicked
|
||||
Intent launchAppIntent = new Intent(context, MainActivity.class);
|
||||
PendingIntent launchAppPendingIntent = PendingIntent.getActivity(context, 0, launchAppIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
views.setOnClickPendingIntent(R.id.widget_layout, launchAppPendingIntent);
|
||||
|
||||
// Set the loading indicator visible initially
|
||||
views.setViewVisibility(R.id.loading_indicator, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.price_value, View.GONE);
|
||||
views.setViewVisibility(R.id.last_updated, View.GONE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.GONE);
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
|
||||
executorService.execute(new FetchBitcoinPriceTask(context, appWidgetManager, appWidgetId));
|
||||
}
|
||||
|
||||
scheduleNextUpdate(context);
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
|
||||
WidgetUpdateWorker.scheduleWork(context); // Schedule to run periodically
|
||||
}
|
||||
|
||||
private void initializeExecutorService() {
|
||||
if (executorService == null || executorService.isShutdown()) {
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
}
|
||||
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
||||
String currentPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_price", "N/A");
|
||||
String currentTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_time", "N/A");
|
||||
String previousPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_previous_price", "N/A");
|
||||
String previousTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_previous_time", "N/A");
|
||||
|
||||
private void scheduleNextUpdate(Context context) {
|
||||
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UpdateWidgetWorker.class)
|
||||
.setInitialDelay(UPDATE_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
WorkManager.getInstance(context).enqueue(workRequest);
|
||||
}
|
||||
|
||||
private static class FetchBitcoinPriceTask implements Runnable {
|
||||
private final WeakReference<Context> contextRef;
|
||||
private final AppWidgetManager appWidgetManager;
|
||||
private final int appWidgetId;
|
||||
|
||||
FetchBitcoinPriceTask(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.appWidgetManager = appWidgetManager;
|
||||
this.appWidgetId = appWidgetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Context context = contextRef.get();
|
||||
if (context == null) return;
|
||||
|
||||
Log.d(TAG, "Starting to fetch Bitcoin price...");
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
String preferredCurrency = prefs.getString("preferredCurrency", "USD");
|
||||
String price = MarketAPI.fetchPrice(context, preferredCurrency);
|
||||
|
||||
if (price != null) {
|
||||
updateWidgetWithPrice(context, price);
|
||||
} else {
|
||||
handleError(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWidgetWithPrice(Context context, String price) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
||||
|
||||
// Fetch current and previous data
|
||||
String prevPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_prev_price", "N/A");
|
||||
String prevTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_prev_time", "N/A");
|
||||
String currentPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_price", null);
|
||||
String currentTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_time", null);
|
||||
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
String newTime = new SimpleDateFormat("hh:mm a", Locale.getDefault()).format(new Date());
|
||||
Log.d(TAG, "Fetch completed with price: " + price + " at " + newTime + ". Previous price: " + prevPrice + " at " + prevTime);
|
||||
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
|
||||
views.setTextViewText(R.id.price_value, currencyFormat.format(Double.parseDouble(price)));
|
||||
|
||||
if (currentPrice != null) {
|
||||
double previousPrice = Double.parseDouble(currentPrice);
|
||||
double newPrice = Double.parseDouble(price);
|
||||
if (newPrice > previousPrice) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
||||
} else if (newPrice < previousPrice) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
}
|
||||
|
||||
if (newPrice != previousPrice) {
|
||||
views.setTextViewText(R.id.previous_price, "from " + currencyFormat.format(previousPrice));
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.previous_price, View.VISIBLE);
|
||||
} else {
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
}
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
}
|
||||
|
||||
// Shift current to previous
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_prev_price", currentPrice);
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_prev_time", currentTime);
|
||||
|
||||
// Set new current
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_current_price", price);
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_current_time", newTime);
|
||||
editor.apply();
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
|
||||
if (!currentPrice.equals("N/A")) {
|
||||
views.setTextViewText(R.id.price_value, currentPrice);
|
||||
views.setTextViewText(R.id.last_updated, "Last Updated");
|
||||
views.setTextViewText(R.id.last_updated_time, newTime);
|
||||
|
||||
views.setTextViewText(R.id.last_updated_time, currentTime);
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
views.setViewVisibility(R.id.price_value, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.VISIBLE);
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
} else {
|
||||
views.setTextViewText(R.id.price_value, "Loading...");
|
||||
views.setViewVisibility(R.id.loading_indicator, View.VISIBLE);
|
||||
}
|
||||
|
||||
private void handleError(Context context) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
String errorMessage = "Network Error";
|
||||
Log.e(TAG, errorMessage);
|
||||
views.setTextViewText(R.id.price_value, errorMessage);
|
||||
views.setTextViewText(R.id.last_updated, "");
|
||||
views.setTextViewText(R.id.last_updated_time, "");
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
if (!previousPrice.equals("N/A") && !previousPrice.equals(currentPrice)) {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||
views.setTextViewText(R.id.previous_price, "From " + previousPrice);
|
||||
|
||||
try {
|
||||
double current = Double.parseDouble(currentPrice.replaceAll("[^\\d.]", ""));
|
||||
double previous = Double.parseDouble(previousPrice.replaceAll("[^\\d.]", ""));
|
||||
if (current > previous) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Error parsing prices", e);
|
||||
}
|
||||
|
||||
} else {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
|
||||
Log.e(TAG, "Failed to fetch Bitcoin price");
|
||||
}
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
}
|
||||
|
||||
public static void savePreferences(Context context, int appWidgetId, String currentPrice, String currentTime, String previousPrice, String previousTime) {
|
||||
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_current_price", currentPrice);
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_current_time", currentTime);
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_previous_price", previousPrice);
|
||||
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_previous_time", previousTime);
|
||||
prefs.apply();
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
public class Constants {
|
||||
public static final int UPDATE_INTERVAL_MINUTES = 3;
|
||||
}
|
|
@ -23,64 +23,59 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
public class MainApplication extends Application implements ReactApplication {
|
||||
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
new DefaultReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
private final ReactNativeHost mReactNativeHost =
|
||||
new DefaultReactNativeHost(this) {
|
||||
@Override
|
||||
public boolean getUseDeveloperSupport() {
|
||||
return BuildConfig.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
return packages;
|
||||
}
|
||||
@Override
|
||||
protected List<ReactPackage> getPackages() {
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
List<ReactPackage> packages = new PackageList(this).getPackages();
|
||||
return packages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isNewArchEnabled() {
|
||||
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
}
|
||||
@Override
|
||||
protected boolean isNewArchEnabled() {
|
||||
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean isHermesEnabled() {
|
||||
return BuildConfig.IS_HERMES_ENABLED;
|
||||
}
|
||||
};
|
||||
@Override
|
||||
protected Boolean isHermesEnabled() {
|
||||
return BuildConfig.IS_HERMES_ENABLED;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
|
||||
sharedI18nUtilInstance.allowRTL(getApplicationContext(), true);
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
DefaultNewArchitectureEntryPoint.load();
|
||||
@Override
|
||||
public ReactNativeHost getReactNativeHost() {
|
||||
return mReactNativeHost;
|
||||
}
|
||||
SharedPreferences sharedPref = getApplicationContext().getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE);
|
||||
|
||||
// Retrieve the "donottrack" value. Default to "0" if not found.
|
||||
String isDoNotTrackEnabled = sharedPref.getString("donottrack", "0");
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
|
||||
sharedI18nUtilInstance.allowRTL(getApplicationContext(), true);
|
||||
SoLoader.init(this, /* native exopackage */ false);
|
||||
|
||||
// Check if do not track is not enabled and initialize Bugsnag if so
|
||||
if (!isDoNotTrackEnabled.equals("1")) {
|
||||
// Initialize Bugsnag or your error tracking here
|
||||
Bugsnag.start(this);
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
DefaultNewArchitectureEntryPoint.load();
|
||||
}
|
||||
|
||||
SharedPreferences sharedPref = getApplicationContext().getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE);
|
||||
String isDoNotTrackEnabled = sharedPref.getString("donottrack", "0");
|
||||
|
||||
if (!isDoNotTrackEnabled.equals("1")) {
|
||||
Bugsnag.start(this);
|
||||
}
|
||||
|
||||
WidgetUpdateWorker.scheduleWork(this); // Schedule to run every 10 minutes
|
||||
}
|
||||
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(UpdateWidgetWorker.class, 10, TimeUnit.MINUTES)
|
||||
.build();
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork("UpdateWidgetWork", ExistingPeriodicWorkPolicy.REPLACE, workRequest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
@ -12,24 +13,26 @@ import java.net.URL;
|
|||
|
||||
public class MarketAPI {
|
||||
|
||||
private static final String TAG = "MarketAPI";
|
||||
private static final String HARD_CODED_JSON = "{\n" +
|
||||
" \"USD\": {\n" +
|
||||
" \"endPointKey\": \"USD\",\n" +
|
||||
" \"locale\": \"en-US\",\n" +
|
||||
" \"source\": \"Kraken\",\n" +
|
||||
" \"symbol\": \"$\",\n" +
|
||||
" \"country\": \"United States (US Dollar)\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
public static String fetchPrice(Context context, String currency) {
|
||||
try {
|
||||
// Load the JSON file from assets
|
||||
InputStreamReader is = new InputStreamReader(context.getAssets().open("fiatUnits.json"));
|
||||
StringBuilder json = new StringBuilder();
|
||||
int data = is.read();
|
||||
while (data != -1) {
|
||||
json.append((char) data);
|
||||
data = is.read();
|
||||
}
|
||||
is.close();
|
||||
|
||||
JSONObject jsonObject = new JSONObject(json.toString());
|
||||
JSONObject currencyInfo = jsonObject.getJSONObject(currency);
|
||||
JSONObject json = new JSONObject(HARD_CODED_JSON);
|
||||
JSONObject currencyInfo = json.getJSONObject(currency);
|
||||
String source = currencyInfo.getString("source");
|
||||
String endPointKey = currencyInfo.getString("endPointKey");
|
||||
|
||||
String urlString = buildURLString(source, endPointKey);
|
||||
Log.d(TAG, "Fetching from URL: " + urlString);
|
||||
URI uri = new URI(urlString);
|
||||
URL url = uri.toURL();
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||
|
@ -116,4 +119,4 @@ public class MarketAPI {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import androidx.work.OneTimeWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateWidgetWorker extends Worker {
|
||||
|
||||
private static final String TAG = "UpdateWidgetWorker";
|
||||
private static final String PREFS_NAME = "BitcoinPriceWidgetPrefs";
|
||||
private static final String PREF_PREFIX_KEY = "appwidget_";
|
||||
private static final int UPDATE_INTERVAL_MINUTES = 10; // Adjustable interval in minutes
|
||||
|
||||
public UpdateWidgetWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Context context = getApplicationContext();
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
ComponentName widget = new ComponentName(context, BitcoinPriceWidget.class);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget);
|
||||
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
fetchAndUpdatePrice(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
|
||||
scheduleNextUpdate(context); // Schedule the next update
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private void fetchAndUpdatePrice(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
Log.d(TAG, "Fetching Bitcoin price...");
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
String preferredCurrency = prefs.getString("preferredCurrency", "USD");
|
||||
String price = MarketAPI.fetchPrice(context, preferredCurrency);
|
||||
|
||||
if (price != null) {
|
||||
updateWidgetWithPrice(context, appWidgetManager, appWidgetId, price);
|
||||
} else {
|
||||
handleError(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWidgetWithPrice(Context context, AppWidgetManager appWidgetManager, int appWidgetId, String price) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
||||
|
||||
// Fetch current and previous data
|
||||
String prevPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_prev_price", "N/A");
|
||||
String prevTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_prev_time", "N/A");
|
||||
String currentPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_price", null);
|
||||
String currentTime = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_current_time", null);
|
||||
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
String newTime = new SimpleDateFormat("hh:mm a", Locale.getDefault()).format(new Date());
|
||||
Log.d(TAG, "Fetch completed with price: " + price + " at " + newTime + ". Previous price: " + prevPrice + " at " + prevTime);
|
||||
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
|
||||
views.setTextViewText(R.id.price_value, currencyFormat.format(Double.parseDouble(price)));
|
||||
|
||||
if (currentPrice != null) {
|
||||
double previousPrice = Double.parseDouble(currentPrice);
|
||||
double newPrice = Double.parseDouble(price);
|
||||
if (newPrice > previousPrice) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
||||
} else if (newPrice < previousPrice) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
}
|
||||
|
||||
if (newPrice != previousPrice) {
|
||||
views.setTextViewText(R.id.previous_price, "from " + currencyFormat.format(previousPrice));
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.previous_price, View.VISIBLE);
|
||||
} else {
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
}
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
}
|
||||
|
||||
// Shift current to previous
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_prev_price", currentPrice);
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_prev_time", currentTime);
|
||||
|
||||
// Set new current
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_current_price", price);
|
||||
editor.putString(PREF_PREFIX_KEY + appWidgetId + "_current_time", newTime);
|
||||
editor.apply();
|
||||
|
||||
views.setTextViewText(R.id.last_updated, "Last Updated");
|
||||
views.setTextViewText(R.id.last_updated_time, newTime);
|
||||
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
views.setViewVisibility(R.id.price_value, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.VISIBLE);
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
|
||||
private void handleError(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
String errorMessage = "Network Error";
|
||||
Log.e(TAG, errorMessage);
|
||||
views.setTextViewText(R.id.price_value, errorMessage);
|
||||
views.setTextViewText(R.id.last_updated, "");
|
||||
views.setTextViewText(R.id.last_updated_time, "");
|
||||
views.setImageViewResource(R.id.price_arrow, 0);
|
||||
views.setTextViewText(R.id.previous_price, "");
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
|
||||
private void scheduleNextUpdate(Context context) {
|
||||
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UpdateWidgetWorker.class)
|
||||
.setInitialDelay(UPDATE_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||
.build();
|
||||
WorkManager.getInstance(context).enqueue(workRequest);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WidgetUpdateManager extends Worker {
|
||||
private static final String TAG = "WidgetUpdateManager";
|
||||
private static final String PREFS_NAME = "BitcoinPriceWidgetPrefs";
|
||||
private static final String PREF_PREFIX_KEY = "appwidget_";
|
||||
private static final String PREFS_LAST_UPDATE_TIME_KEY = "lastUpdateTime_";
|
||||
private static final String PREFS_LAST_PRICE_KEY = "lastPrice_";
|
||||
private static final String PREFS_PREV_PRICE_KEY = "prevPrice_";
|
||||
private static final String PREFS_PREV_UPDATE_TIME_KEY = "prevUpdateTime_";
|
||||
|
||||
public WidgetUpdateManager(Context context, WorkerParameters params) {
|
||||
super(context, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Context context = getApplicationContext();
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, BitcoinPriceWidget.class));
|
||||
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
||||
String previousPrice = prefs.getString(PREFS_PREV_PRICE_KEY + appWidgetId, "N/A");
|
||||
String lastPrice = prefs.getString(PREFS_LAST_PRICE_KEY + appWidgetId, "N/A");
|
||||
String lastUpdateTime = prefs.getString(PREFS_LAST_UPDATE_TIME_KEY + appWidgetId, "N/A");
|
||||
String previousUpdateTime = prefs.getString(PREFS_PREV_UPDATE_TIME_KEY + appWidgetId, "N/A");
|
||||
|
||||
Log.d(TAG, "Fetch completed with price: " + lastPrice + " at " + lastUpdateTime + ". Previous price: " + previousPrice + " at " + previousUpdateTime);
|
||||
|
||||
String price = MarketAPI.fetchPrice(context, "USD");
|
||||
if (price != null) {
|
||||
Log.d(TAG, "Fetch completed with price: " + price);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(PREFS_PREV_PRICE_KEY + appWidgetId, lastPrice);
|
||||
editor.putString(PREFS_PREV_UPDATE_TIME_KEY + appWidgetId, lastUpdateTime);
|
||||
editor.putString(PREFS_LAST_PRICE_KEY + appWidgetId, price);
|
||||
editor.putString(PREFS_LAST_UPDATE_TIME_KEY + appWidgetId, DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()));
|
||||
editor.apply();
|
||||
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
views.setTextViewText(R.id.price_value, price);
|
||||
views.setTextViewText(R.id.last_updated_time, DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()));
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
views.setViewVisibility(R.id.price_value, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.VISIBLE);
|
||||
|
||||
if (!"N/A".equals(previousPrice)) {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.previous_price, View.VISIBLE);
|
||||
} else {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||
}
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
} else {
|
||||
Log.e(TAG, "Failed to fetch Bitcoin price");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Constraints;
|
||||
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class WidgetUpdateWorker extends Worker {
|
||||
|
||||
private static final String TAG = "WidgetUpdateWorker";
|
||||
private static final String WORK_NAME = "WidgetUpdateWorker";
|
||||
private static final int UPDATE_INTERVAL_MINUTES = 10; // You can adjust this value as needed
|
||||
|
||||
public WidgetUpdateWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Context context = getApplicationContext();
|
||||
SharedPreferences prefs = context.getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE);
|
||||
|
||||
// Fetch the preferred currency from shared preferences
|
||||
String preferredCurrency = prefs.getString("preferredCurrency", "USD");
|
||||
|
||||
Log.d(TAG, "Fetching price for currency: " + preferredCurrency);
|
||||
|
||||
// Fetch the price using MarketAPI
|
||||
String price = MarketAPI.fetchPrice(context, preferredCurrency);
|
||||
String previousPrice = prefs.getString("previous_price", "N/A");
|
||||
String previousTime = prefs.getString("previous_time", "N/A");
|
||||
|
||||
Log.d(TAG, "Fetch completed with price: " + price + " at " + getCurrentTime() + ". Previous price: " + previousPrice + " at " + previousTime);
|
||||
|
||||
// Update the widget with the fetched price
|
||||
if (price != null) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString("previous_price", prefs.getString("current_price", "N/A"));
|
||||
editor.putString("previous_time", prefs.getString("current_time", "N/A"));
|
||||
editor.putString("current_price", price);
|
||||
editor.putString("current_time", getCurrentTime());
|
||||
editor.apply();
|
||||
|
||||
updateWidget(context, price, preferredCurrency, previousPrice);
|
||||
} else {
|
||||
handleError(context);
|
||||
return Result.retry();
|
||||
}
|
||||
|
||||
Log.d(TAG, "Next fetch will occur at: " + getNextFetchTime());
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private void updateWidget(Context context, String price, String currency, String previousPrice) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
|
||||
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.getDefault());
|
||||
currencyFormat.setCurrency(java.util.Currency.getInstance(currency));
|
||||
|
||||
views.setTextViewText(R.id.price_value, currencyFormat.format(Double.parseDouble(price)));
|
||||
views.setTextViewText(R.id.last_updated, "Last Updated");
|
||||
views.setTextViewText(R.id.last_updated_time, getCurrentTime());
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences("group.io.bluewallet.bluewallet", Context.MODE_PRIVATE);
|
||||
String currentStoredPrice = prefs.getString("current_price", null);
|
||||
if (currentStoredPrice == null || currentStoredPrice.isEmpty()) {
|
||||
views.setViewVisibility(R.id.loading_indicator, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.price_value, View.GONE);
|
||||
views.setViewVisibility(R.id.last_updated, View.GONE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.GONE);
|
||||
} else {
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
views.setViewVisibility(R.id.price_value, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated, View.VISIBLE);
|
||||
views.setViewVisibility(R.id.last_updated_time, View.VISIBLE);
|
||||
}
|
||||
|
||||
if (!previousPrice.equals("N/A") && !previousPrice.equals(price)) {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||
views.setTextViewText(R.id.previous_price, "From " + currencyFormat.format(Double.parseDouble(previousPrice)));
|
||||
|
||||
double current = Double.parseDouble(price);
|
||||
double previous = Double.parseDouble(previousPrice);
|
||||
if (current > previous) {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
||||
}
|
||||
} else {
|
||||
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||
}
|
||||
|
||||
// Update the widget
|
||||
WidgetUtils.updateAppWidget(context, views);
|
||||
}
|
||||
|
||||
private void handleError(Context context) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||
views.setTextViewText(R.id.price_value, "Failed to fetch");
|
||||
views.setTextViewText(R.id.last_updated, "Last Updated");
|
||||
views.setTextViewText(R.id.last_updated_time, getCurrentTime());
|
||||
|
||||
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||
|
||||
// Update the widget
|
||||
WidgetUtils.updateAppWidget(context, views);
|
||||
}
|
||||
|
||||
private String getCurrentTime() {
|
||||
DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(getApplicationContext());
|
||||
return dateFormat.format(new Date());
|
||||
}
|
||||
|
||||
private String getNextFetchTime() {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
long nextFetchTimeMillis = currentTimeMillis + TimeUnit.MINUTES.toMillis(UPDATE_INTERVAL_MINUTES);
|
||||
Date nextFetchDate = new Date(nextFetchTimeMillis);
|
||||
DateFormat dateFormat = android.text.format.DateFormat.getTimeFormat(getApplicationContext());
|
||||
return dateFormat.format(nextFetchDate);
|
||||
}
|
||||
|
||||
public static PeriodicWorkRequest createWorkRequest(int intervalMinutes) {
|
||||
Constraints constraints = new Constraints.Builder()
|
||||
.setRequiresBatteryNotLow(true)
|
||||
.build();
|
||||
|
||||
return new PeriodicWorkRequest.Builder(WidgetUpdateWorker.class, intervalMinutes, TimeUnit.MINUTES)
|
||||
.setConstraints(constraints)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void scheduleWork(Context context) {
|
||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
|
||||
WORK_NAME,
|
||||
ExistingPeriodicWorkPolicy.REPLACE,
|
||||
createWorkRequest(UPDATE_INTERVAL_MINUTES)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.bluewallet.bluewallet;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
public class WidgetUtils {
|
||||
|
||||
public static void updateAppWidget(Context context, RemoteViews views) {
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
ComponentName thisWidget = new ComponentName(context, BitcoinPriceWidget.class);
|
||||
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
|
||||
|
||||
for (int widgetId : allWidgetIds) {
|
||||
appWidgetManager.updateAppWidget(widgetId, views);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="end">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_updated"
|
||||
style="@style/WidgetTextSecondary"
|
||||
|
@ -21,7 +21,7 @@
|
|||
android:text=""
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginEnd="8dp" />
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_updated_time"
|
||||
|
@ -31,7 +31,7 @@
|
|||
android:text=""
|
||||
android:textSize="12sp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="2dp" />
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -49,7 +49,7 @@
|
|||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/price_arrow_container"
|
||||
|
@ -63,7 +63,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/previous_price"
|
||||
|
@ -73,14 +73,15 @@
|
|||
android:text=""
|
||||
android:textSize="12sp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
android:layout_marginBottom="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
Loading…
Add table
Reference in a new issue