Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue-717: Android widget layout improvements #733

Merged
merged 15 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
Expand Down Expand Up @@ -411,11 +412,8 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
widgetRemoteViews.setImageViewResource(R.id.weatherIconImageView, drawableResId);
widgetRemoteViews.setContentDescription(R.id.weatherIconImageView, getSymbolTranslation(weatherSymbol));

// Update time TODO: should be hidden for release
widgetRemoteViews.setTextViewText(R.id.updateTimeTextView, DateFormat.getTimeInstance().format(new Date()));

// Crisis view
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref);
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref, false);

appWidgetManager.updateAppWidget(widgetId, widgetRemoteViews);
return;
Expand Down Expand Up @@ -568,10 +566,12 @@ private RemoteViews getRemoteViews(RemoteViews widgetRemoteViews, int widgetId)
return widgetRemoteViews;
}

protected void showCrisisViewIfNeeded(JSONArray announcementsJson, RemoteViews widgetRemoteViews, SharedPreferencesHelper pref) {
protected void showCrisisViewIfNeeded(
JSONArray announcementsJson, RemoteViews widgetRemoteViews, SharedPreferencesHelper pref, Boolean hideLocation
) {
announcementsJson = useNewOrStoredCrisisJsonObject(announcementsJson, pref);

// example forecastJson: [{"type":"Crisis","content":"Varoitusnauha -testi EN","link":"https://www.fmi.fi"}]
// example announcement json: [{"type":"Crisis","content":"Varoitusnauha -testi EN","link":"https://www.fmi.fi"}]
if (announcementsJson != null) {
boolean crisisFound = false;
try {
Expand All @@ -582,6 +582,11 @@ protected void showCrisisViewIfNeeded(JSONArray announcementsJson, RemoteViews w
String content = jsonObject.getString("content");
widgetRemoteViews.setViewVisibility(R.id.crisisTextView, VISIBLE);
widgetRemoteViews.setTextViewText(R.id.crisisTextView, content);
if (hideLocation) {
widgetRemoteViews.setViewVisibility(R.id.locationNameTextView, GONE);
widgetRemoteViews.setViewVisibility(R.id.locationRegionTextView, GONE);
widgetRemoteViews.setViewVisibility(R.id.timeTextView, GONE);
}
crisisFound = true;
// if a crisis found, exit the loop
break;
Expand All @@ -592,6 +597,9 @@ protected void showCrisisViewIfNeeded(JSONArray announcementsJson, RemoteViews w
}
if (!crisisFound) {
widgetRemoteViews.setViewVisibility(R.id.crisisTextView, GONE);
widgetRemoteViews.setViewVisibility(R.id.locationNameTextView, VISIBLE);
widgetRemoteViews.setViewVisibility(R.id.locationRegionTextView, VISIBLE);
widgetRemoteViews.setViewVisibility(R.id.timeTextView, VISIBLE);
}
} else {
widgetRemoteViews.setViewVisibility(R.id.crisisTextView, GONE);
Expand Down Expand Up @@ -619,14 +627,6 @@ else if (theme.equals(GRADIENT)) {
}
}

protected void setLargeWidgetSpecificColors(RemoteViews remoteViews, String theme) {
if (theme.equals(DARK) || theme.equals(GRADIENT)) {
setWeatherRowColors(remoteViews, Color.WHITE);
} else { // LIGHT theme
setWeatherRowColors(remoteViews, getPrimaryBlue(context));
}
}

protected void setColors(RemoteViews remoteViews, int backgroundResource, int backgroundColor, int textColor) {
if (backgroundResource != 0) {
remoteViews.setInt(R.id.mainLinearLayout, "setBackgroundResource", backgroundResource);
Expand All @@ -647,24 +647,6 @@ protected void setColors(RemoteViews remoteViews, int backgroundResource, int ba
}
}

protected void setWeatherRowColors(RemoteViews remoteViews, int textColor) {
int[] timeTextViews = {
R.id.timeTextView0, R.id.timeTextView1, R.id.timeTextView2,
R.id.timeTextView3, R.id.timeTextView4
};
int[] temperatureTextViews = {
R.id.temperatureTextView0, R.id.temperatureTextView1, R.id.temperatureTextView2,
R.id.temperatureTextView3, R.id.temperatureTextView4
};

for (int textView : timeTextViews) {
remoteViews.setInt(textView, "setTextColor", textColor);
}
for (int textView : temperatureTextViews) {
remoteViews.setInt(textView, "setTextColor", textColor);
}
}

protected String addPlusIfNeeded(String temperature) {
// temperature string to float
float tempFloat = Float.parseFloat(temperature);
Expand Down Expand Up @@ -849,4 +831,11 @@ protected String getSymbolTranslation(int symbol) {
);
return context.getString(symbolId);
}

protected int getWidgetWidthInPixels(int appWidgetId) {
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
int minWidth = options.getInt(appWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
return minWidth;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import static fi.fmi.mobileweather.Theme.LIGHT;

import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;
import android.view.View;

import org.json.JSONArray;
import org.json.JSONObject;

import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;

public class LargeForecastWidgetProvider extends BaseWidgetProvider {
Expand All @@ -25,10 +25,9 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
JSONObject forecastJson = widgetInitResult.forecastJson();
RemoteViews widgetRemoteViews = widgetInitResult.widgetRemoteViews();
String theme = widgetInitResult.theme();

// set colors for views which are specific for large widget
// (not set in the initWidget)
setLargeWidgetSpecificColors(widgetRemoteViews, theme);

final int timeStepCount = getWidgetWidthInPixels(appWidgetId) > 380 ? 7 : 6;
Log.d("widgetWidth", String.valueOf(getWidgetWidthInPixels(appWidgetId)));

try {
// Get the keys of the JSONObject
Expand All @@ -52,8 +51,10 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
throw new Exception("No future time found or less than 5 future times available");
}

widgetRemoteViews.removeAllViews(R.id.hourForecastRowLayout);

// handle the first 5 JsonObjects with future time
for (int i = firstFutureTimeIndex; i < (firstFutureTimeIndex + 5); i++) {
for (int i = firstFutureTimeIndex; i < (firstFutureTimeIndex + timeStepCount); i++) {
JSONObject forecast = data.getJSONObject(i);

// if first future index
Expand All @@ -65,35 +66,34 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
widgetRemoteViews.setTextViewText(R.id.locationRegionTextView, region);
}

RemoteViews timeStep = new RemoteViews(context.getPackageName(), R.layout.forecast_timestep);

// time at the selected location
String localTime = forecast.getString("localtime");
String temperature = forecast.getString("temperature");
int weatherSymbol = forecast.getInt("smartSymbol");

// get timeTextView0 or timeTextView1 etc. based on i from widgetRemoteViews
int timeTextViewId = context.getResources().getIdentifier("timeTextView" + i, "id", context.getPackageName());
int temperatureTextViewId = context.getResources().getIdentifier("temperatureTextView" + i, "id", context.getPackageName());
int weatherIconImageViewId = context.getResources().getIdentifier("weatherIconImageView" + i, "id", context.getPackageName());

// ** set the time, temperature and weather icon

String formattedTime = getFormattedWeatherTime(localTime);
widgetRemoteViews.setTextViewText(timeTextViewId, formattedTime);
timeStep.setTextViewText(R.id.timeStepTimeTextView, formattedTime);

temperature = addPlusIfNeeded(temperature);
widgetRemoteViews.setTextViewText(temperatureTextViewId, temperature + "°");
timeStep.setTextViewText(R.id.temperatureTextView, temperature + "°");

int drawableResId = context.getResources().getIdentifier("s_" + weatherSymbol + (theme.equals(LIGHT) ? "_light" : "_dark"), "drawable", context.getPackageName());
widgetRemoteViews.setImageViewResource(weatherIconImageViewId, drawableResId);
widgetRemoteViews.setContentDescription(weatherIconImageViewId, getSymbolTranslation(weatherSymbol));
}
timeStep.setImageViewResource(R.id.weatherIconImageView, drawableResId);
timeStep.setContentDescription(R.id.weatherIconImageView, getSymbolTranslation(weatherSymbol));

// Update time TODO: should be hidden for release
widgetRemoteViews.setTextViewText(R.id.updateTimeTextView, DateFormat.getTimeInstance().format(new Date()));
if (i == timeStepCount - 1) {
timeStep.setViewVisibility(R.id.forecastBorder, View.GONE);
}

widgetRemoteViews.addView(R.id.hourForecastRowLayout, timeStep);
}

// Crisis view
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref);
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref, true);

appWidgetManager.updateAppWidget(appWidgetId, widgetRemoteViews);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.graphics.Color;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

import org.json.JSONArray;
Expand All @@ -33,10 +34,12 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
JSONObject forecastJson = widgetInitResult.forecastJson();
RemoteViews widgetRemoteViews = widgetInitResult.widgetRemoteViews();
String theme = widgetInitResult.theme();
final int timeStepCount = getWidgetWidthInPixels(appWidgetId) > 380 ? 8 : 7;

Log.d("widgetWidth", String.valueOf(getWidgetWidthInPixels(appWidgetId)));

// set colors for views which are specific for large and max widgets
// (not set in the initWidget)
setLargeWidgetSpecificColors(widgetRemoteViews, theme);
setMaxWidgetSpecificColors(widgetRemoteViews, theme);

try {
Expand All @@ -61,8 +64,10 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
throw new Exception("No future time found or less than 6 future times available");
}

widgetRemoteViews.removeAllViews(R.id.forecastContainer);

// handle the first 6 JsonObjects with future time
for (int i = firstFutureTimeIndex; i < (firstFutureTimeIndex + 6); i++) {
for (int i = firstFutureTimeIndex; i < (firstFutureTimeIndex + timeStepCount); i++) {
JSONObject forecast = data.getJSONObject(i);

// if first future index set main part of the widget
Expand All @@ -89,6 +94,7 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
// next iteration in loop
continue;
}
RemoteViews timeStep = new RemoteViews(context.getPackageName(), R.layout.large_forecast_timestep);

// time at the selected location
String localTime = forecast.getString("localtime");
Expand All @@ -98,22 +104,19 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
// j = weather row layout index
int j = i - 1;

// get timeTextView0 or timeTextView1 etc. based on i from widgetRemoteViews
int timeTextViewId = context.getResources().getIdentifier("timeTextView" + j, "id", context.getPackageName());
int temperatureTextViewId = context.getResources().getIdentifier("temperatureTextView" + j, "id", context.getPackageName());
int weatherIconImageViewId = context.getResources().getIdentifier("weatherIconImageView" + j, "id", context.getPackageName());

// ** set the time, temperature and weather icon

String formattedTime = getFormattedWeatherTime(localTime);
widgetRemoteViews.setTextViewText(timeTextViewId, formattedTime);
timeStep.setTextViewText(R.id.timeTextView, formattedTime);

temperature = addPlusIfNeeded(temperature);
widgetRemoteViews.setTextViewText(temperatureTextViewId, temperature + "°");
timeStep.setTextViewText(R.id.temperatureTextView, temperature + "°");

int drawableResId = context.getResources().getIdentifier("s_" + weatherSymbol + (theme.equals(LIGHT) ? "_light" : "_dark"), "drawable", context.getPackageName());
widgetRemoteViews.setImageViewResource(weatherIconImageViewId, drawableResId);
widgetRemoteViews.setContentDescription(weatherIconImageViewId, getSymbolTranslation(weatherSymbol));
timeStep.setImageViewResource(R.id.weatherIconImageView, drawableResId);
timeStep.setContentDescription(R.id.weatherIconImageView, getSymbolTranslation(weatherSymbol));

widgetRemoteViews.addView(R.id.forecastContainer, timeStep);
}

// Get the current time
Expand All @@ -139,9 +142,8 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe

widgetRemoteViews.setTextViewText(R.id.updateTimeTextView, formattedText);


// Crisis view
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref);
showCrisisViewIfNeeded(announcementsJson, widgetRemoteViews, pref, true);

appWidgetManager.updateAppWidget(appWidgetId, widgetRemoteViews);
return;
Expand All @@ -163,19 +165,7 @@ protected void setWidgetData(JSONArray announcementsJson, SharedPreferencesHelpe
private void setMaxWidgetSpecificColors(RemoteViews remoteViews, String theme) {
boolean isDarkOrGradient = theme.equals(DARK) || theme.equals(GRADIENT);
int textColor = isDarkOrGradient ? Color.WHITE : getPrimaryBlue(context);
int visibility = isDarkOrGradient ? INVISIBLE : VISIBLE;
int clockIcon = isDarkOrGradient ? R.drawable.ic_clock_white : R.drawable.ic_clock_blue;
int weatherIcon = isDarkOrGradient ? R.drawable.ic_weather_white : R.drawable.ic_weather_blue;
int temperatureIcon = isDarkOrGradient ? R.drawable.ic_temperature_white : R.drawable.ic_temperature_blue;
int logoIcon = isDarkOrGradient ? R.drawable.fmi_logo_white : R.drawable.fmi_logo_blue;

remoteViews.setInt(R.id.timeTextView, "setTextColor", textColor);
remoteViews.setViewVisibility(R.id.verticalBarImageView0, visibility);
remoteViews.setViewVisibility(R.id.verticalBarImageView1, visibility);
remoteViews.setImageViewResource(R.id.clockSymbolImageView, clockIcon);
remoteViews.setImageViewResource(R.id.weatherSymbolImageView, weatherIcon);
remoteViews.setImageViewResource(R.id.temperatureSymbolImageView, temperatureIcon);
remoteViews.setImageViewResource(R.id.logoImageView, logoIcon);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,15 @@ public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidge

// TODO: needs to be tested well with all kind of devices:
private int getLayoutResourceIdForResize(int minWidth, int minHeight) {
if (minWidth > 100 && minWidth < 200 && minHeight > 120) {
if (minWidth < 100) {
Log.d("Widget Update", "xs widget " + minWidth + "x" + minHeight);
return R.layout.xs_forecast_widget_layout;
} else if (minWidth < 250) {
Log.d("Widget Update", "Small widget " + minWidth + "x" + minHeight);
return R.layout.small_forecast_widget_layout;
} else if (minWidth >= 200 && minWidth < 300 && minHeight > 120) {
Log.d("Widget Update", "Medium widget " + minWidth + "x" + minHeight);
return R.layout.medium_forecast_widget_layout;
} else if (minWidth >= 300) {
} else {
Log.d("Widget Update", "Horizontal widget " + minWidth + "x" + minHeight);
return R.layout.horizontal_forecast_widget_layout;
} else {
Log.d("Widget Update", "XS widget " + minWidth + "x" + minHeight);
return R.layout.xs_forecast_widget_layout;
}
}

Expand Down
38 changes: 38 additions & 0 deletions android/app/src/main/res/layout/forecast_symbol_column.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/forecastSymbolColumn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6dp"
android:orientation="vertical"
android:layout_alignParentStart="true"
>

<ImageView
android:id="@+id/clockSymbolImageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginVertical="7dp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/ic_clock_blue"
android:importantForAccessibility="no" />

<ImageView
android:id="@+id/weatherSymbolImageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginVertical="7dp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/ic_weather_blue"
android:importantForAccessibility="no" />

<ImageView
android:id="@+id/temperatureSymbolImageView"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginVertical="7dp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/ic_temperature_blue"
android:importantForAccessibility="no" />

</LinearLayout>
Loading