mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-13 19:16:52 +01:00
Fix
This commit is contained in:
parent
1e256130d7
commit
8f35063791
9 changed files with 292 additions and 98 deletions
|
@ -3,7 +3,6 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
|
||||||
|
|
||||||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning">
|
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning">
|
||||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<uses-permission android:name="android.permission.ACTION_OPEN_DOCUMENT" />
|
<uses-permission android:name="android.permission.ACTION_OPEN_DOCUMENT" />
|
||||||
<uses-permission android:name="android.permission.ACTION_GET_CONTENT" />
|
<uses-permission android:name="android.permission.ACTION_GET_CONTENT" />
|
||||||
<uses-permission android:name="android.permission.ACTION_CREATE_DOCUMENT" />
|
<uses-permission android:name="android.permission.ACTION_CREATE_DOCUMENT" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|
|
@ -7,19 +7,23 @@ import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.icu.text.NumberFormat;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.Toast;
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.work.Constraints;
|
||||||
|
import androidx.work.OneTimeWorkRequest;
|
||||||
|
import androidx.work.WorkManager;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.text.DateFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class BitcoinPriceWidget extends AppWidgetProvider {
|
public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
|
|
||||||
|
@ -27,24 +31,27 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
private static final String ACTION_UPDATE = "io.bluewallet.bluewallet.UPDATE";
|
private static final String ACTION_UPDATE = "io.bluewallet.bluewallet.UPDATE";
|
||||||
private static final String PREFS_NAME = "BitcoinPriceWidgetPrefs";
|
private static final String PREFS_NAME = "BitcoinPriceWidgetPrefs";
|
||||||
private static final String PREF_PREFIX_KEY = "appwidget_";
|
private static final String PREF_PREFIX_KEY = "appwidget_";
|
||||||
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
private static final int UPDATE_INTERVAL_MINUTES = 10; // Adjustable interval in minutes
|
||||||
private static final Handler handler = new Handler();
|
private static ExecutorService executorService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnabled(Context context) {
|
public void onEnabled(Context context) {
|
||||||
super.onEnabled(context);
|
super.onEnabled(context);
|
||||||
scheduleNextUpdate(context);
|
initializeExecutorService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisabled(Context context) {
|
public void onDisabled(Context context) {
|
||||||
super.onDisabled(context);
|
super.onDisabled(context);
|
||||||
|
if (executorService != null) {
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
handler.removeCallbacksAndMessages(null);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||||
|
initializeExecutorService();
|
||||||
|
if (appWidgetIds.length > 0) {
|
||||||
for (int appWidgetId : appWidgetIds) {
|
for (int appWidgetId : appWidgetIds) {
|
||||||
Log.d(TAG, "Updating widget ID: " + appWidgetId);
|
Log.d(TAG, "Updating widget ID: " + appWidgetId);
|
||||||
|
|
||||||
|
@ -55,6 +62,12 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
PendingIntent launchAppPendingIntent = PendingIntent.getActivity(context, 0, launchAppIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
PendingIntent launchAppPendingIntent = PendingIntent.getActivity(context, 0, launchAppIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||||
views.setOnClickPendingIntent(R.id.widget_layout, launchAppPendingIntent);
|
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);
|
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||||
|
|
||||||
executorService.execute(new FetchBitcoinPriceTask(context, appWidgetManager, appWidgetId));
|
executorService.execute(new FetchBitcoinPriceTask(context, appWidgetManager, appWidgetId));
|
||||||
|
@ -62,30 +75,20 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
|
|
||||||
scheduleNextUpdate(context);
|
scheduleNextUpdate(context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private void initializeExecutorService() {
|
||||||
public void onReceive(Context context, Intent intent) {
|
if (executorService == null || executorService.isShutdown()) {
|
||||||
super.onReceive(context, intent);
|
executorService = Executors.newSingleThreadExecutor();
|
||||||
if (ACTION_UPDATE.equals(intent.getAction())) {
|
|
||||||
Log.d(TAG, "Received update action");
|
|
||||||
|
|
||||||
ComponentName widget = new ComponentName(context, BitcoinPriceWidget.class);
|
|
||||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
|
||||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget);
|
|
||||||
onUpdate(context, appWidgetManager, appWidgetIds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleNextUpdate(final Context context) {
|
private void scheduleNextUpdate(Context context) {
|
||||||
handler.postDelayed(new Runnable() {
|
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(UpdateWidgetWorker.class)
|
||||||
@Override
|
.setInitialDelay(UPDATE_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||||
public void run() {
|
.build();
|
||||||
Intent intent = new Intent(context, BitcoinPriceWidget.class);
|
|
||||||
intent.setAction(ACTION_UPDATE);
|
WorkManager.getInstance(context).enqueue(workRequest);
|
||||||
context.sendBroadcast(intent);
|
|
||||||
scheduleNextUpdate(context);
|
|
||||||
}
|
|
||||||
}, 10 * 60 * 1000); // Update every 10 minutes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FetchBitcoinPriceTask implements Runnable {
|
private static class FetchBitcoinPriceTask implements Runnable {
|
||||||
|
@ -106,7 +109,9 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
|
|
||||||
Log.d(TAG, "Starting to fetch Bitcoin price...");
|
Log.d(TAG, "Starting to fetch Bitcoin price...");
|
||||||
|
|
||||||
String price = MarketAPI.fetchPrice("USD"); // Using hardcoded "USD" for now
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
|
String preferredCurrency = prefs.getString("preferredCurrency", "USD");
|
||||||
|
String price = MarketAPI.fetchPrice(context, preferredCurrency);
|
||||||
|
|
||||||
if (price != null) {
|
if (price != null) {
|
||||||
updateWidgetWithPrice(context, price);
|
updateWidgetWithPrice(context, price);
|
||||||
|
@ -118,47 +123,63 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
private void updateWidgetWithPrice(Context context, String price) {
|
private void updateWidgetWithPrice(Context context, String price) {
|
||||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
|
||||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
|
||||||
String prevPrice = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null);
|
|
||||||
|
// 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();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
|
||||||
Log.d(TAG, "Fetch completed with price: " + price);
|
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);
|
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
|
||||||
views.setTextViewText(R.id.price_value, currencyFormat.format(Double.parseDouble(price)));
|
views.setTextViewText(R.id.price_value, currencyFormat.format(Double.parseDouble(price)));
|
||||||
|
|
||||||
if (prevPrice != null) {
|
if (currentPrice != null) {
|
||||||
double previousPrice = Double.parseDouble(prevPrice);
|
double previousPrice = Double.parseDouble(currentPrice);
|
||||||
double currentPrice = Double.parseDouble(price);
|
double newPrice = Double.parseDouble(price);
|
||||||
if (currentPrice > previousPrice) {
|
if (newPrice > previousPrice) {
|
||||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_up_float);
|
||||||
} else if (currentPrice < previousPrice) {
|
} else if (newPrice < previousPrice) {
|
||||||
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
views.setImageViewResource(R.id.price_arrow, android.R.drawable.arrow_down_float);
|
||||||
} else {
|
} else {
|
||||||
views.setImageViewResource(R.id.price_arrow, 0);
|
views.setImageViewResource(R.id.price_arrow, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentPrice != previousPrice) {
|
if (newPrice != previousPrice) {
|
||||||
views.setTextViewText(R.id.previous_price, "from " + currencyFormat.format(previousPrice));
|
views.setTextViewText(R.id.previous_price, "from " + currencyFormat.format(previousPrice));
|
||||||
views.setViewVisibility(R.id.price_arrow, View.VISIBLE);
|
views.setViewVisibility(R.id.price_arrow_container, View.VISIBLE);
|
||||||
views.setViewVisibility(R.id.previous_price, View.VISIBLE);
|
views.setViewVisibility(R.id.previous_price, View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
views.setTextViewText(R.id.previous_price, "");
|
views.setTextViewText(R.id.previous_price, "");
|
||||||
views.setViewVisibility(R.id.price_arrow, View.GONE);
|
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
views.setImageViewResource(R.id.price_arrow, 0);
|
views.setImageViewResource(R.id.price_arrow, 0);
|
||||||
views.setTextViewText(R.id.previous_price, "");
|
views.setTextViewText(R.id.previous_price, "");
|
||||||
views.setViewVisibility(R.id.price_arrow, View.GONE);
|
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.putString(PREF_PREFIX_KEY + appWidgetId, price);
|
// 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();
|
editor.apply();
|
||||||
|
|
||||||
DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault());
|
|
||||||
String currentTime = timeFormat.format(new Date());
|
|
||||||
views.setTextViewText(R.id.last_updated, "Last Updated");
|
views.setTextViewText(R.id.last_updated, "Last Updated");
|
||||||
views.setTextViewText(R.id.last_updated_time, currentTime);
|
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);
|
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||||
}
|
}
|
||||||
|
@ -172,10 +193,13 @@ public class BitcoinPriceWidget extends AppWidgetProvider {
|
||||||
views.setTextViewText(R.id.last_updated_time, "");
|
views.setTextViewText(R.id.last_updated_time, "");
|
||||||
views.setImageViewResource(R.id.price_arrow, 0);
|
views.setImageViewResource(R.id.price_arrow, 0);
|
||||||
views.setTextViewText(R.id.previous_price, "");
|
views.setTextViewText(R.id.previous_price, "");
|
||||||
views.setViewVisibility(R.id.price_arrow, View.GONE);
|
views.setViewVisibility(R.id.price_arrow_container, View.GONE);
|
||||||
views.setViewVisibility(R.id.previous_price, View.GONE);
|
views.setViewVisibility(R.id.previous_price, View.GONE);
|
||||||
Toast.makeText(context, "Failed to fetch Bitcoin price", Toast.LENGTH_SHORT).show();
|
views.setViewVisibility(R.id.loading_indicator, View.GONE);
|
||||||
|
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||||
|
|
||||||
|
Log.e(TAG, "Failed to fetch Bitcoin price");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package io.bluewallet.bluewallet;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static final int UPDATE_INTERVAL_MINUTES = 3;
|
||||||
|
}
|
|
@ -16,6 +16,10 @@ import com.facebook.soloader.SoLoader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||||
|
import androidx.work.PeriodicWorkRequest;
|
||||||
|
import androidx.work.WorkManager;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MainApplication extends Application implements ReactApplication {
|
public class MainApplication extends Application implements ReactApplication {
|
||||||
|
|
||||||
|
@ -75,5 +79,8 @@ public class MainApplication extends Application implements ReactApplication {
|
||||||
// Initialize Bugsnag or your error tracking here
|
// Initialize Bugsnag or your error tracking here
|
||||||
Bugsnag.start(this);
|
Bugsnag.start(this);
|
||||||
}
|
}
|
||||||
|
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(UpdateWidgetWorker.class, 10, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
WorkManager.getInstance(this).enqueueUniquePeriodicWork("UpdateWidgetWork", ExistingPeriodicWorkPolicy.REPLACE, workRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package io.bluewallet.bluewallet;
|
package io.bluewallet.bluewallet;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
@ -10,19 +12,20 @@ import java.net.URL;
|
||||||
|
|
||||||
public class MarketAPI {
|
public class MarketAPI {
|
||||||
|
|
||||||
private static final String HARD_CODED_JSON = "{\n" +
|
public static String fetchPrice(Context context, String currency) {
|
||||||
" \"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(String currency) {
|
|
||||||
try {
|
try {
|
||||||
JSONObject json = new JSONObject(HARD_CODED_JSON);
|
// Load JSON from assets
|
||||||
|
InputStreamReader isr = new InputStreamReader(context.getAssets().open("fiatUnits.json"));
|
||||||
|
StringBuilder jsonBuilder = new StringBuilder();
|
||||||
|
char[] buffer = new char[1024];
|
||||||
|
int length;
|
||||||
|
while ((length = isr.read(buffer)) != -1) {
|
||||||
|
jsonBuilder.append(buffer, 0, length);
|
||||||
|
}
|
||||||
|
isr.close();
|
||||||
|
|
||||||
|
String jsonString = jsonBuilder.toString();
|
||||||
|
JSONObject json = new JSONObject(jsonString);
|
||||||
JSONObject currencyInfo = json.getJSONObject(currency);
|
JSONObject currencyInfo = json.getJSONObject(currency);
|
||||||
String source = currencyInfo.getString("source");
|
String source = currencyInfo.getString("source");
|
||||||
String endPointKey = currencyInfo.getString("endPointKey");
|
String endPointKey = currencyInfo.getString("endPointKey");
|
||||||
|
@ -42,9 +45,9 @@ public class MarketAPI {
|
||||||
InputStreamReader reader = new InputStreamReader(urlConnection.getInputStream());
|
InputStreamReader reader = new InputStreamReader(urlConnection.getInputStream());
|
||||||
StringBuilder jsonResponse = new StringBuilder();
|
StringBuilder jsonResponse = new StringBuilder();
|
||||||
int read;
|
int read;
|
||||||
char[] buffer = new char[1024];
|
char[] buffer2 = new char[1024];
|
||||||
while ((read = reader.read(buffer)) != -1) {
|
while ((read = reader.read(buffer2)) != -1) {
|
||||||
jsonResponse.append(buffer, 0, read);
|
jsonResponse.append(buffer2, 0, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseJSONBasedOnSource(jsonResponse.toString(), source, endPointKey);
|
return parseJSONBasedOnSource(jsonResponse.toString(), source, endPointKey);
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,5 +75,12 @@
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="8dp" />
|
android:layout_marginBottom="8dp" />
|
||||||
</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>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#Tue Jul 21 23:04:55 CDT 2020
|
#Wed Jun 26 20:30:20 AST 2024
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
|
|
||||||
networkTimeout=10000
|
|
Loading…
Add table
Reference in a new issue