diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/service/BatteryRateTracker.java b/app/src/main/java/com/almothafar/simplebatterynotifier/service/BatteryRateTracker.java index 9845a94..604d571 100644 --- a/app/src/main/java/com/almothafar/simplebatterynotifier/service/BatteryRateTracker.java +++ b/app/src/main/java/com/almothafar/simplebatterynotifier/service/BatteryRateTracker.java @@ -61,7 +61,7 @@ public final class BatteryRateTracker { static final int MAX_PLAUSIBLE_RATE_PPH = 500; // The "red / high drain" limit shared with the fast-drain alert (#109): default and accepted range. - // MIN/MAX must match the slider bounds (android:min/android:max) in pref_notification.xml; they are + // MIN/MAX must match the slider bounds (android:min/android:max) in pref_alerts.xml; they are // enforced when the preference is read, so an out-of-range stored value can't skew the red line. public static final int DEFAULT_DRAIN_LIMIT_PPH = 20; public static final int MIN_DRAIN_LIMIT_PPH = 5; @@ -363,7 +363,7 @@ public static int getDrainLimitPercentPerHour(final Context context) { /** * Clamps a stored drain limit to the accepted range, so a corrupt or out-of-range preference value * can't skew the red line here or the fast-drain trigger in #109. The bounds mirror the slider's - * {@code android:min}/{@code android:max} in {@code pref_notification.xml}. Pure so it is unit-testable. + * {@code android:min}/{@code android:max} in {@code pref_alerts.xml}. Pure so it is unit-testable. * * @param stored the raw persisted limit in %/h * diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/service/NotificationService.java b/app/src/main/java/com/almothafar/simplebatterynotifier/service/NotificationService.java index 571574e..8f3e3b1 100644 --- a/app/src/main/java/com/almothafar/simplebatterynotifier/service/NotificationService.java +++ b/app/src/main/java/com/almothafar/simplebatterynotifier/service/NotificationService.java @@ -87,7 +87,7 @@ public final class NotificationService { private static final String ZEN_MODE = "zen_mode"; private static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; - // Charge-connected notification style (values persisted by the ListPreference in pref_notification.xml). + // Charge-connected notification style (values persisted by the ListPreference in pref_alerts.xml). // Toast is the default so plugging in stays low-clutter (issue #122). static final String CHARGE_STYLE_TOAST = "toast"; static final String CHARGE_STYLE_NOTIFICATION = "notification"; @@ -842,7 +842,7 @@ private static boolean isVibrationEnabled(final Context context, final SharedPre * @return true if alerts are allowed at the current time */ private static boolean isWithinNotificationWindow(final Context context, final SharedPreferences prefs) { - // Default ON to match the toggle's XML default (pref_time_settings.xml). Reading false here let a + // Default ON to match the toggle's XML default (pref_behaviour.xml). Reading false here let a // fresh install that never opened Time Settings alert around the clock, so quiet hours silently // did nothing (issue #111). Now quiet hours apply by default (06:30–23:30). final boolean limitedTime = prefs.getBoolean(context.getString(R.string._pref_key_notifications_time_range), true); diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/AboutDialog.java b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/AboutDialog.java new file mode 100644 index 0000000..cf5a33b --- /dev/null +++ b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/AboutDialog.java @@ -0,0 +1,79 @@ +package com.almothafar.simplebatterynotifier.ui; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.util.Log; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.almothafar.simplebatterynotifier.R; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +/** + * Shared "About the app" dialog and app-version lookup. + *
+ * Used from two entry points: the main screen's overflow menu (#136) and the version footer at
+ * the bottom of the Settings root screen (#113), so both stay one implementation.
+ */
+public final class AboutDialog {
+
+ private static final String TAG = "AboutDialog";
+
+ private AboutDialog() {
+ }
+
+ /**
+ * Show the "About the app" dialog: what the app is, the current version, developer credit,
+ * the open-source license, and a short accuracy/warranty note.
+ *
+ * @param activity The host activity
+ */
+ public static void show(final Activity activity) {
+ final View content = activity.getLayoutInflater().inflate(R.layout.dialog_about, null);
+
+ final TextView versionView = content.findViewById(R.id.aboutVersion);
+ versionView.setText(activity.getString(R.string.about_version, appVersionName(activity)));
+
+ final TextView developerView = content.findViewById(R.id.aboutDeveloper);
+ developerView.setText(activity.getString(R.string.about_developer, activity.getString(R.string.developer_name)));
+
+ new MaterialAlertDialogBuilder(activity)
+ .setView(content)
+ .setPositiveButton(android.R.string.ok, null)
+ .setNeutralButton(R.string.about_view_github, (dialog, which) -> openProjectPage(activity))
+ .show();
+ }
+
+ /**
+ * The app's version name (e.g. "2.0.71"), or an empty string if it can't be read.
+ *
+ * @param context Any context of this app
+ */
+ public static String appVersionName(final Context context) {
+ try {
+ return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ // The app can always resolve its own package, so this is effectively unreachable;
+ // log it rather than swallow silently, and degrade to an empty version string.
+ Log.w(TAG, "Unable to read app version name", e);
+ return "";
+ }
+ }
+
+ /**
+ * Open the project's GitHub page in a browser.
+ */
+ private static void openProjectPage(final Activity activity) {
+ final Uri uri = Uri.parse(activity.getString(R.string.about_github_url));
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(activity, R.string.no_browser_found, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/MainActivity.java b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/MainActivity.java
index 13465b0..6933e26 100644
--- a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/MainActivity.java
+++ b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/MainActivity.java
@@ -15,7 +15,6 @@
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.almothafar.simplebatterynotifier.ui.fragment.BatteryDetailsFragment;
@@ -105,7 +104,7 @@ public boolean onOptionsItemSelected(final MenuItem item) {
return true;
}
if (id == R.id.action_about) {
- showAboutDialog();
+ AboutDialog.show(this);
return true;
}
return super.onOptionsItemSelected(item);
@@ -463,38 +462,6 @@ private void openBatteryInsights() {
startActivity(intent);
}
- /**
- * Show the "About the app" dialog: what the app is, the current version, developer credit,
- * the open-source license, and a short accuracy/warranty note.
- */
- private void showAboutDialog() {
- final View content = getLayoutInflater().inflate(R.layout.dialog_about, null);
-
- final TextView versionView = content.findViewById(R.id.aboutVersion);
- versionView.setText(getString(R.string.about_version, appVersionName()));
-
- final TextView developerView = content.findViewById(R.id.aboutDeveloper);
- developerView.setText(getString(R.string.about_developer, getString(R.string.developer_name)));
-
- new MaterialAlertDialogBuilder(this)
- .setView(content)
- .setPositiveButton(android.R.string.ok, null)
- .setNeutralButton(R.string.about_view_github, (dialog, which) -> openProjectPage())
- .show();
- }
-
- /**
- * Open the project's GitHub page in a browser.
- */
- private void openProjectPage() {
- final Uri uri = Uri.parse(getString(R.string.about_github_url));
- try {
- startActivity(new Intent(Intent.ACTION_VIEW, uri));
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.no_browser_found, Toast.LENGTH_SHORT).show();
- }
- }
-
/**
* Show the feedback chooser: report on GitHub, or email the developer.
*/
@@ -534,7 +501,7 @@ private void openGitHubIssues() {
private void emailDeveloper() {
final Intent intent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("mailto", getString(R.string.feedback_support_email), null));
- intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.feedback_email_subject, appVersionName()));
+ intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.feedback_email_subject, AboutDialog.appVersionName(this)));
intent.putExtra(Intent.EXTRA_TEXT, deviceInfoBlock());
try {
startActivity(intent);
@@ -543,26 +510,12 @@ private void emailDeveloper() {
}
}
- /**
- * The app's version name (e.g. "2.0.71"), or an empty string if it can't be read.
- */
- private String appVersionName() {
- try {
- return getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
- } catch (PackageManager.NameNotFoundException e) {
- // The app can always resolve its own package, so this is effectively unreachable;
- // log it rather than swallow silently, and degrade to an empty version string.
- Log.w(TAG, "Unable to read app version name", e);
- return "";
- }
- }
-
/**
* A short diagnostic block appended to a feedback email so reports carry the essentials.
*/
private String deviceInfoBlock() {
return "\n\n---\n"
- + "App: " + appVersionName() + "\n"
+ + "App: " + AboutDialog.appVersionName(this) + "\n"
+ "Device: " + Build.MANUFACTURER + " " + Build.MODEL + "\n"
+ "Android: " + Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ")";
}
diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/SettingsActivity.java b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/SettingsActivity.java
index ac4d28c..685f6c0 100644
--- a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/SettingsActivity.java
+++ b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/SettingsActivity.java
@@ -139,6 +139,17 @@ public static class HeaderFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
setPreferencesFromResource(R.xml.pref_headers_root, rootKey);
+
+ // Version footer (#113): show the running app version at the bottom of the root
+ // screen; tapping it opens the shared About dialog (same one as the main menu, #136).
+ final Preference about = findPreference(getString(R.string._pref_key_about));
+ if (nonNull(about)) {
+ about.setTitle(getString(R.string.about_version, AboutDialog.appVersionName(requireContext())));
+ about.setOnPreferenceClickListener(pref -> {
+ AboutDialog.show(requireActivity());
+ return true;
+ });
+ }
}
}
}
diff --git a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/fragment/GenericPreferenceFragment.java b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/fragment/GenericPreferenceFragment.java
index 44c4f74..7f06712 100644
--- a/app/src/main/java/com/almothafar/simplebatterynotifier/ui/fragment/GenericPreferenceFragment.java
+++ b/app/src/main/java/com/almothafar/simplebatterynotifier/ui/fragment/GenericPreferenceFragment.java
@@ -120,11 +120,11 @@ public void onCreatePreferences(final Bundle savedInstanceState, final String ro
if (category.equals(getString(R.string.pref_category_general))) {
setPreferencesFromResource(R.xml.pref_general, rootKey);
configureLanguagePreference();
- } else if (category.equals(getString(R.string.pref_category_notifications))) {
- setPreferencesFromResource(R.xml.pref_notification, rootKey);
+ } else if (category.equals(getString(R.string.pref_category_alerts))) {
+ setPreferencesFromResource(R.xml.pref_alerts, rootKey);
configureTemperatureThreshold();
- } else if (category.equals(getString(R.string.pref_category_time_settings))) {
- setPreferencesFromResource(R.xml.pref_time_settings, rootKey);
+ } else if (category.equals(getString(R.string.pref_category_behaviour))) {
+ setPreferencesFromResource(R.xml.pref_behaviour, rootKey);
}
}
}
diff --git a/app/src/main/res/layout/dialog_about.xml b/app/src/main/res/layout/dialog_about.xml
index 436e8ea..681b5c6 100644
--- a/app/src/main/res/layout/dialog_about.xml
+++ b/app/src/main/res/layout/dialog_about.xml
@@ -1,5 +1,5 @@
-
+