mirror of
https://github.com/jahruz67/Bible-Daily.git
synced 2026-08-08 18:14:05 +00:00
Add dark mode support and improve language handling in SettingsActivity
- Refactored color constants to support both light and dark modes. - Implemented a toggle for dark mode in SettingsActivity. - Updated language selection functionality to correctly display "Español". - Enhanced prayer management in ExtrasActivity with a detailed view. - Added new styles for dark mode in styles.xml.
This commit is contained in:
@@ -0,0 +1,478 @@
|
|||||||
|
package com.bibliadiaria.app;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.Switch;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class SettingsActivity extends Activity {
|
||||||
|
// Light mode colors
|
||||||
|
private static final int COLOR_BG_LIGHT = Color.rgb(247, 248, 246);
|
||||||
|
private static final int COLOR_CARD_LIGHT = Color.WHITE;
|
||||||
|
private static final int COLOR_INK_LIGHT = Color.rgb(25, 31, 31);
|
||||||
|
private static final int COLOR_MUTED_LIGHT = Color.rgb(91, 99, 98);
|
||||||
|
private static final int COLOR_STROKE_LIGHT = Color.rgb(219, 226, 222);
|
||||||
|
private static final int COLOR_CARD_STROKE_LIGHT = Color.rgb(229, 232, 230);
|
||||||
|
|
||||||
|
// Dark mode colors
|
||||||
|
private static final int COLOR_BG_DARK = Color.rgb(26, 28, 30);
|
||||||
|
private static final int COLOR_CARD_DARK = Color.rgb(38, 41, 44);
|
||||||
|
private static final int COLOR_INK_DARK = Color.rgb(224, 226, 219);
|
||||||
|
private static final int COLOR_MUTED_DARK = Color.rgb(158, 163, 160);
|
||||||
|
private static final int COLOR_STROKE_DARK = Color.rgb(48, 52, 55);
|
||||||
|
private static final int COLOR_CARD_STROKE_DARK = Color.rgb(58, 62, 65);
|
||||||
|
|
||||||
|
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
||||||
|
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
||||||
|
|
||||||
|
private ExecutorService executor;
|
||||||
|
private TextView statusText;
|
||||||
|
private TextView installedVersionText;
|
||||||
|
private TextView checkButton;
|
||||||
|
private TextView downloadButton;
|
||||||
|
private TextView voiceSubtitleText;
|
||||||
|
private TextView voiceButton;
|
||||||
|
private UpdateManager.UpdateInfo latestInfo;
|
||||||
|
private boolean isEnglish;
|
||||||
|
private boolean isDarkMode;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
isEnglish = UpdateManager.isEnglish(this);
|
||||||
|
isDarkMode = UpdateManager.isDarkMode(this);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
getWindow().setStatusBarColor(bg());
|
||||||
|
getWindow().setNavigationBarColor(bg());
|
||||||
|
}
|
||||||
|
|
||||||
|
executor = Executors.newSingleThreadExecutor();
|
||||||
|
setContentView(createScreen());
|
||||||
|
updateInstalledVersionText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (executor != null) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int bg() { return isDarkMode ? COLOR_BG_DARK : COLOR_BG_LIGHT; }
|
||||||
|
private int card() { return isDarkMode ? COLOR_CARD_DARK : COLOR_CARD_LIGHT; }
|
||||||
|
private int ink() { return isDarkMode ? COLOR_INK_DARK : COLOR_INK_LIGHT; }
|
||||||
|
private int muted() { return isDarkMode ? COLOR_MUTED_DARK : COLOR_MUTED_LIGHT; }
|
||||||
|
private int stroke() { return isDarkMode ? COLOR_STROKE_DARK : COLOR_STROKE_LIGHT; }
|
||||||
|
private int cardStroke() { return isDarkMode ? COLOR_CARD_STROKE_DARK : COLOR_CARD_STROKE_LIGHT; }
|
||||||
|
|
||||||
|
private View createScreen() {
|
||||||
|
FrameLayout root = new FrameLayout(this);
|
||||||
|
root.setBackgroundColor(bg());
|
||||||
|
|
||||||
|
ScrollView scrollView = new ScrollView(this);
|
||||||
|
scrollView.setFillViewport(true);
|
||||||
|
scrollView.setClipToPadding(false);
|
||||||
|
|
||||||
|
LinearLayout content = new LinearLayout(this);
|
||||||
|
content.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
content.setPadding(dp(20), dp(28), dp(20), dp(28));
|
||||||
|
scrollView.addView(content, new ScrollView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
content.addView(createTopBar());
|
||||||
|
|
||||||
|
TextView title = textView("Settings", 34, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
titleParams.setMargins(0, dp(18), 0, dp(18));
|
||||||
|
content.addView(title, titleParams);
|
||||||
|
|
||||||
|
content.addView(createDarkModeCard());
|
||||||
|
content.addView(createLanguageCard());
|
||||||
|
content.addView(createVoiceCard());
|
||||||
|
content.addView(createVersionCard());
|
||||||
|
|
||||||
|
checkButton = actionButton(isEnglish ? "Check now" : "Comprobar", COLOR_ACCENT, Color.WHITE);
|
||||||
|
checkButton.setOnClickListener(view -> checkForUpdate());
|
||||||
|
LinearLayout.LayoutParams checkParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
dp(46)
|
||||||
|
);
|
||||||
|
checkParams.setMargins(0, dp(16), 0, 0);
|
||||||
|
content.addView(checkButton, checkParams);
|
||||||
|
|
||||||
|
downloadButton = actionButton("Download latest APK", COLOR_WARM, Color.WHITE);
|
||||||
|
downloadButton.setVisibility(View.GONE);
|
||||||
|
downloadButton.setOnClickListener(view -> {
|
||||||
|
String url = latestInfo == null ? UpdateManager.APK_URL : latestInfo.apkUrl;
|
||||||
|
UpdateManager.openDownload(this, url);
|
||||||
|
});
|
||||||
|
LinearLayout.LayoutParams downloadParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
dp(46)
|
||||||
|
);
|
||||||
|
downloadParams.setMargins(0, dp(10), 0, 0);
|
||||||
|
content.addView(downloadButton, downloadParams);
|
||||||
|
|
||||||
|
root.addView(scrollView, new FrameLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
));
|
||||||
|
|
||||||
|
root.setOnApplyWindowInsetsListener((view, insets) -> {
|
||||||
|
content.setPadding(
|
||||||
|
dp(20),
|
||||||
|
dp(28) + insets.getSystemWindowInsetTop(),
|
||||||
|
dp(20),
|
||||||
|
dp(28) + insets.getSystemWindowInsetBottom()
|
||||||
|
);
|
||||||
|
return insets;
|
||||||
|
});
|
||||||
|
root.requestApplyInsets();
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createTopBar() {
|
||||||
|
LinearLayout topBar = new LinearLayout(this);
|
||||||
|
topBar.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
topBar.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
|
TextView label = textView("APP", 12, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
topBar.addView(label, new LinearLayout.LayoutParams(
|
||||||
|
0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
1f
|
||||||
|
));
|
||||||
|
|
||||||
|
TextView back = textView(isEnglish ? "Extras" : "Extras", 15, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
back.setGravity(Gravity.CENTER);
|
||||||
|
back.setPadding(dp(14), 0, dp(14), 0);
|
||||||
|
back.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
|
back.setOnClickListener(view -> finish());
|
||||||
|
topBar.addView(back, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
dp(40)
|
||||||
|
));
|
||||||
|
|
||||||
|
return topBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createDarkModeCard() {
|
||||||
|
LinearLayout card = createCard();
|
||||||
|
card.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
card.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
|
LinearLayout copy = new LinearLayout(this);
|
||||||
|
copy.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
TextView title = textView(isEnglish ? "Dark Mode" : "Modo oscuro", 20, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
copy.addView(title);
|
||||||
|
|
||||||
|
TextView subtitle = textView(
|
||||||
|
isEnglish ? "Use dark colors for the interface" : "Usar colores oscuros para la interfaz",
|
||||||
|
14, muted(), Typeface.NORMAL);
|
||||||
|
LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
subtitleParams.setMargins(0, dp(6), 0, 0);
|
||||||
|
copy.addView(subtitle, subtitleParams);
|
||||||
|
|
||||||
|
card.addView(copy, new LinearLayout.LayoutParams(
|
||||||
|
0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
1f
|
||||||
|
));
|
||||||
|
|
||||||
|
final Switch darkToggle = new Switch(this);
|
||||||
|
darkToggle.setChecked(isDarkMode);
|
||||||
|
darkToggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
UpdateManager.setDarkMode(this, isChecked);
|
||||||
|
isDarkMode = isChecked;
|
||||||
|
recreate();
|
||||||
|
});
|
||||||
|
card.addView(darkToggle, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createLanguageCard() {
|
||||||
|
LinearLayout card = createCard();
|
||||||
|
card.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
card.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
|
LinearLayout copy = new LinearLayout(this);
|
||||||
|
copy.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
TextView title = textView("Language", 20, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
copy.addView(title);
|
||||||
|
|
||||||
|
TextView subtitle = textView("Select the language for daily readings", 14, muted(), Typeface.NORMAL);
|
||||||
|
LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
subtitleParams.setMargins(0, dp(6), 0, 0);
|
||||||
|
copy.addView(subtitle, subtitleParams);
|
||||||
|
|
||||||
|
card.addView(copy, new LinearLayout.LayoutParams(
|
||||||
|
0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
1f
|
||||||
|
));
|
||||||
|
|
||||||
|
TextView langToggle = actionButton(UpdateManager.isEnglish(this) ? "English" : "Español", COLOR_ACCENT, Color.WHITE);
|
||||||
|
langToggle.setOnClickListener(view -> {
|
||||||
|
boolean current = UpdateManager.isEnglish(this);
|
||||||
|
UpdateManager.setEnglish(this, !current);
|
||||||
|
langToggle.setText(!current ? "English" : "Español");
|
||||||
|
updateVoiceCard();
|
||||||
|
});
|
||||||
|
card.addView(langToggle, new LinearLayout.LayoutParams(dp(100), dp(40)));
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createVoiceCard() {
|
||||||
|
LinearLayout card = createCard();
|
||||||
|
card.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
LinearLayout copy = new LinearLayout(this);
|
||||||
|
copy.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
TextView title = textView("Voice", 20, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
copy.addView(title);
|
||||||
|
|
||||||
|
voiceSubtitleText = textView("", 14, muted(), Typeface.NORMAL);
|
||||||
|
LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
subtitleParams.setMargins(0, dp(6), 0, 0);
|
||||||
|
copy.addView(voiceSubtitleText, subtitleParams);
|
||||||
|
|
||||||
|
card.addView(copy, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
voiceButton = actionButton("", COLOR_ACCENT, Color.WHITE);
|
||||||
|
voiceButton.setOnClickListener(view -> showVoicePicker());
|
||||||
|
LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
dp(42)
|
||||||
|
);
|
||||||
|
buttonParams.setMargins(0, dp(12), 0, 0);
|
||||||
|
card.addView(voiceButton, buttonParams);
|
||||||
|
|
||||||
|
updateVoiceCard();
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createVersionCard() {
|
||||||
|
LinearLayout card = createCard();
|
||||||
|
card.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
TextView title = textView("Version", 20, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
card.addView(title);
|
||||||
|
|
||||||
|
installedVersionText = textView("", 15, muted(), Typeface.BOLD);
|
||||||
|
LinearLayout.LayoutParams installedParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
installedParams.setMargins(0, dp(10), 0, 0);
|
||||||
|
card.addView(installedVersionText, installedParams);
|
||||||
|
|
||||||
|
statusText = textView("Ready to check for updates.", 15, muted(), Typeface.NORMAL);
|
||||||
|
statusText.setLineSpacing(dp(3), 1.1f);
|
||||||
|
LinearLayout.LayoutParams statusParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
statusParams.setMargins(0, dp(8), 0, 0);
|
||||||
|
card.addView(statusText, statusParams);
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkForUpdate() {
|
||||||
|
if (executor == null || executor.isShutdown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
latestInfo = null;
|
||||||
|
downloadButton.setVisibility(View.GONE);
|
||||||
|
checkButton.setEnabled(false);
|
||||||
|
checkButton.setAlpha(0.62f);
|
||||||
|
statusText.setText("Checking for updates...");
|
||||||
|
|
||||||
|
executor.submit(() -> {
|
||||||
|
try {
|
||||||
|
UpdateManager.UpdateInfo info = UpdateManager.fetchLatestUpdate(this);
|
||||||
|
runOnUiThread(() -> showUpdateResult(info));
|
||||||
|
} catch (Exception error) {
|
||||||
|
runOnUiThread(() -> showUpdateError(error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showUpdateResult(UpdateManager.UpdateInfo info) {
|
||||||
|
latestInfo = info;
|
||||||
|
checkButton.setEnabled(true);
|
||||||
|
checkButton.setAlpha(1f);
|
||||||
|
|
||||||
|
if (info.updateAvailable) {
|
||||||
|
String version = info.latestVersionName.isEmpty()
|
||||||
|
? String.valueOf(info.latestVersionCode)
|
||||||
|
: info.latestVersionName + " (" + info.latestVersionCode + ")";
|
||||||
|
statusText.setText("Update available: " + version);
|
||||||
|
downloadButton.setVisibility(View.VISIBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusText.setText("You are on the latest build: "
|
||||||
|
+ info.currentVersionName + " (" + info.currentVersionCode + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showUpdateError(Exception error) {
|
||||||
|
checkButton.setEnabled(true);
|
||||||
|
checkButton.setAlpha(1f);
|
||||||
|
statusText.setText("Could not check for updates. " + cleanMessage(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showVoicePicker() {
|
||||||
|
boolean english = UpdateManager.isEnglish(this);
|
||||||
|
UpdateManager.VoiceOption[] options = UpdateManager.getTtsVoiceOptions(english);
|
||||||
|
String[] labels = new String[options.length];
|
||||||
|
for (int index = 0; index < options.length; index++) {
|
||||||
|
labels[index] = options[index].label;
|
||||||
|
}
|
||||||
|
|
||||||
|
int selectedIndex = UpdateManager.getTtsVoiceIndex(
|
||||||
|
english,
|
||||||
|
UpdateManager.getTtsVoice(this, english)
|
||||||
|
);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(english ? "English voice" : "Spanish voice")
|
||||||
|
.setSingleChoiceItems(labels, selectedIndex, (dialog, which) -> {
|
||||||
|
UpdateManager.setTtsVoice(this, english, options[which].id);
|
||||||
|
updateVoiceCard();
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVoiceCard() {
|
||||||
|
if (voiceSubtitleText == null || voiceButton == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean english = UpdateManager.isEnglish(this);
|
||||||
|
String voiceId = UpdateManager.getTtsVoice(this, english);
|
||||||
|
voiceSubtitleText.setText(english
|
||||||
|
? "English voices are shown while English is selected"
|
||||||
|
: "Las voces en español se muestran mientras el español esté seleccionado");
|
||||||
|
voiceButton.setText(UpdateManager.getTtsVoiceLabel(english, voiceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInstalledVersionText() {
|
||||||
|
try {
|
||||||
|
installedVersionText.setText(
|
||||||
|
(isEnglish ? "Installed: " : "Instalada: ")
|
||||||
|
+ UpdateManager.getInstalledVersionName(this)
|
||||||
|
+ " (" + UpdateManager.getInstalledVersionCode(this) + ")");
|
||||||
|
} catch (Exception error) {
|
||||||
|
installedVersionText.setText(isEnglish ? "Installed version unavailable." : "Versión instalada no disponible.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cleanMessage(Exception error) {
|
||||||
|
String message = error.getMessage();
|
||||||
|
if (message == null || message.trim().isEmpty()) {
|
||||||
|
return "Unknown error.";
|
||||||
|
}
|
||||||
|
return message.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinearLayout createCard() {
|
||||||
|
LinearLayout card = new LinearLayout(this);
|
||||||
|
card.setPadding(dp(18), dp(16), dp(18), dp(16));
|
||||||
|
card.setBackground(roundedRect(card(), dp(8), cardStroke(), dp(1)));
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
card.setElevation(dp(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
params.setMargins(0, 0, 0, dp(14));
|
||||||
|
card.setLayoutParams(params);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextView actionButton(String text, int backgroundColor, int textColor) {
|
||||||
|
TextView button = textView(text, 15, textColor, Typeface.BOLD);
|
||||||
|
button.setGravity(Gravity.CENTER);
|
||||||
|
button.setPadding(dp(14), 0, dp(14), 0);
|
||||||
|
button.setBackground(roundedRect(backgroundColor, dp(8), Color.TRANSPARENT, 0));
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextView textView(String text, int sizeSp, int color, int style) {
|
||||||
|
TextView textView = new TextView(this);
|
||||||
|
textView.setText(text);
|
||||||
|
textView.setTextSize(sizeSp);
|
||||||
|
textView.setTextColor(color);
|
||||||
|
textView.setTypeface(Typeface.DEFAULT, style);
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GradientDrawable roundedRect(int color, int radius, int strokeColor, int strokeWidth) {
|
||||||
|
GradientDrawable drawable = new GradientDrawable();
|
||||||
|
drawable.setShape(GradientDrawable.RECTANGLE);
|
||||||
|
drawable.setColor(color);
|
||||||
|
drawable.setCornerRadius(radius);
|
||||||
|
if (strokeWidth > 0) {
|
||||||
|
drawable.setStroke(strokeWidth, strokeColor);
|
||||||
|
}
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dp(int value) {
|
||||||
|
return Math.round(value * getResources().getDisplayMetrics().density);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,424 @@
|
|||||||
|
package com.bibliadiaria.app;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
public class ExtrasActivity extends Activity {
|
||||||
|
// Light mode colors
|
||||||
|
private static final int COLOR_BG_LIGHT = Color.rgb(247, 248, 246);
|
||||||
|
private static final int COLOR_CARD_LIGHT = Color.WHITE;
|
||||||
|
private static final int COLOR_INK_LIGHT = Color.rgb(25, 31, 31);
|
||||||
|
private static final int COLOR_MUTED_LIGHT = Color.rgb(91, 99, 98);
|
||||||
|
private static final int COLOR_STROKE_LIGHT = Color.rgb(219, 226, 222);
|
||||||
|
private static final int COLOR_CARD_STROKE_LIGHT = Color.rgb(229, 232, 230);
|
||||||
|
|
||||||
|
// Dark mode colors
|
||||||
|
private static final int COLOR_BG_DARK = Color.rgb(26, 28, 30);
|
||||||
|
private static final int COLOR_CARD_DARK = Color.rgb(38, 41, 44);
|
||||||
|
private static final int COLOR_INK_DARK = Color.rgb(224, 226, 219);
|
||||||
|
private static final int COLOR_MUTED_DARK = Color.rgb(158, 163, 160);
|
||||||
|
private static final int COLOR_STROKE_DARK = Color.rgb(48, 52, 55);
|
||||||
|
private static final int COLOR_CARD_STROKE_DARK = Color.rgb(58, 62, 65);
|
||||||
|
|
||||||
|
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
||||||
|
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
||||||
|
|
||||||
|
private boolean isEnglish;
|
||||||
|
private boolean isDarkMode;
|
||||||
|
|
||||||
|
private static final String VENI_CREATOR_PRAYER =
|
||||||
|
"Ven, Esp\u00edritu Creador,\n"
|
||||||
|
+ "visita las almas de tus fieles\n"
|
||||||
|
+ "y llena de la gracia divina\n"
|
||||||
|
+ "los corazones que t\u00fa mismo creaste.\n\n"
|
||||||
|
+ "T\u00fa eres nuestro Consolador,\n"
|
||||||
|
+ "don del Dios alt\u00edsimo,\n"
|
||||||
|
+ "fuente viva, fuego, caridad\n"
|
||||||
|
+ "y espiritual unci\u00f3n.\n\n"
|
||||||
|
+ "T\u00fa derramas sobre nosotros\n"
|
||||||
|
+ "los siete dones;\n"
|
||||||
|
+ "t\u00fa eres el dedo de la diestra del Padre,\n"
|
||||||
|
+ "promesa solemne del Padre,\n"
|
||||||
|
+ "que pones en nuestros labios la palabra.\n\n"
|
||||||
|
+ "Enciende tu luz en nuestras mentes,\n"
|
||||||
|
+ "infunde tu amor en nuestros corazones\n"
|
||||||
|
+ "y fortalece con tu fuerza constante\n"
|
||||||
|
+ "la debilidad de nuestro cuerpo.\n\n"
|
||||||
|
+ "Aleja de nosotros al enemigo,\n"
|
||||||
|
+ "danos pronto la paz;\n"
|
||||||
|
+ "siendo t\u00fa nuestro gu\u00eda,\n"
|
||||||
|
+ "evitaremos todo mal.\n\n"
|
||||||
|
+ "Por ti conozcamos al Padre,\n"
|
||||||
|
+ "y tambi\u00e9n al Hijo;\n"
|
||||||
|
+ "y que en ti, Esp\u00edritu de ambos,\n"
|
||||||
|
+ "creamos en todo tiempo.\n\n"
|
||||||
|
+ "Gloria a Dios Padre,\n"
|
||||||
|
+ "y al Hijo que resucit\u00f3,\n"
|
||||||
|
+ "y al Esp\u00edritu Consolador,\n"
|
||||||
|
+ "por los siglos de los siglos.\n\n"
|
||||||
|
+ "Am\u00e9n.";
|
||||||
|
|
||||||
|
private static final String ANGELUS_PRAYER =
|
||||||
|
"El \u00c1ngel del Se\u00f1or anunci\u00f3 a Mar\u00eda.\n"
|
||||||
|
+ "Y concibi\u00f3 por obra y gracia del Esp\u00edritu Santo.\n\n"
|
||||||
|
+ "Dios te salve, Mar\u00eda, llena eres de gracia,\n"
|
||||||
|
+ "el Se\u00f1or es contigo.\n"
|
||||||
|
+ "Bendita t\u00fa eres entre todas las mujeres,\n"
|
||||||
|
+ "y bendito es el fruto de tu vientre, Jes\u00fas.\n"
|
||||||
|
+ "Santa Mar\u00eda, Madre de Dios,\n"
|
||||||
|
+ "ruega por nosotros, pecadores,\n"
|
||||||
|
+ "ahora y en la hora de nuestra muerte.\n"
|
||||||
|
+ "Am\u00e9n.\n\n"
|
||||||
|
+ "He aqu\u00ed la esclava del Se\u00f1or.\n"
|
||||||
|
+ "H\u00e1gase en m\u00ed seg\u00fan tu palabra.\n\n"
|
||||||
|
+ "Dios te salve, Mar\u00eda...\n\n"
|
||||||
|
+ "Y el Verbo se hizo carne.\n"
|
||||||
|
+ "Y habit\u00f3 entre nosotros.\n\n"
|
||||||
|
+ "Dios te salve, Mar\u00eda...\n\n"
|
||||||
|
+ "Ruega por nosotros, Santa Madre de Dios.\n"
|
||||||
|
+ "Para que seamos dignos de alcanzar las promesas de Cristo.\n\n"
|
||||||
|
+ "Infunde, Se\u00f1or, tu gracia en nuestros corazones,\n"
|
||||||
|
+ "para que quienes hemos conocido por el anuncio del \u00c1ngel\n"
|
||||||
|
+ "la encarnaci\u00f3n de tu Hijo Jesucristo,\n"
|
||||||
|
+ "por su pasi\u00f3n y cruz seamos llevados\n"
|
||||||
|
+ "a la gloria de su resurrecci\u00f3n.\n"
|
||||||
|
+ "Por Jesucristo nuestro Se\u00f1or.\n\n"
|
||||||
|
+ "Am\u00e9n.";
|
||||||
|
|
||||||
|
private static final String SALVE_REGINA_PRAYER =
|
||||||
|
"Dios te salve, Reina y Madre de misericordia,\n"
|
||||||
|
+ "vida, dulzura y esperanza nuestra;\n"
|
||||||
|
+ "Dios te salve.\n\n"
|
||||||
|
+ "A ti llamamos los desterrados hijos de Eva;\n"
|
||||||
|
+ "a ti suspiramos, gimiendo y llorando\n"
|
||||||
|
+ "en este valle de l\u00e1grimas.\n\n"
|
||||||
|
+ "Ea, pues, Se\u00f1ora, abogada nuestra,\n"
|
||||||
|
+ "vuelve a nosotros esos tus ojos misericordiosos;\n"
|
||||||
|
+ "y despu\u00e9s de este destierro,\n"
|
||||||
|
+ "mu\u00e9stranos a Jes\u00fas,\n"
|
||||||
|
+ "fruto bendito de tu vientre.\n\n"
|
||||||
|
+ "\u00a1Oh clemente, oh piadosa,\n"
|
||||||
|
+ "oh dulce Virgen Mar\u00eda!\n\n"
|
||||||
|
+ "Ruega por nosotros, Santa Madre de Dios,\n"
|
||||||
|
+ "para que seamos dignos de alcanzar\n"
|
||||||
|
+ "las promesas de nuestro Se\u00f1or Jesucristo.\n\n"
|
||||||
|
+ "Am\u00e9n.";
|
||||||
|
|
||||||
|
private static final String MEMORARE_PRAYER =
|
||||||
|
"Acordaos, oh piados\u00edsima Virgen Mar\u00eda,\n"
|
||||||
|
+ "que jam\u00e1s se ha o\u00eddo decir\n"
|
||||||
|
+ "que ninguno de los que han acudido a vuestra protecci\u00f3n,\n"
|
||||||
|
+ "implorado vuestra asistencia\n"
|
||||||
|
+ "y reclamado vuestro socorro,\n"
|
||||||
|
+ "haya sido abandonado de vos.\n\n"
|
||||||
|
+ "Animado con esta confianza,\n"
|
||||||
|
+ "a vos tambi\u00e9n acudo,\n"
|
||||||
|
+ "oh Madre, Virgen de las v\u00edrgenes;\n"
|
||||||
|
+ "y aunque gimiendo bajo el peso de mis pecados,\n"
|
||||||
|
+ "me atrevo a comparecer ante vuestra presencia soberana.\n\n"
|
||||||
|
+ "No desech\u00e9is, oh Madre de Dios,\n"
|
||||||
|
+ "mis humildes s\u00faplicas;\n"
|
||||||
|
+ "antes bien, escuchadlas y acogedlas benignamente.\n\n"
|
||||||
|
+ "Am\u00e9n.";
|
||||||
|
|
||||||
|
private static final PrayerItem[] PRAYERS = {
|
||||||
|
new PrayerItem("Ven, Esp\u00edritu Creador", "Veni Creator Spiritus", VENI_CREATOR_PRAYER),
|
||||||
|
new PrayerItem("\u00c1ngelus", "Oraci\u00f3n de la Encarnaci\u00f3n", ANGELUS_PRAYER),
|
||||||
|
new PrayerItem("Salve Regina", "Dios te salve, Reina", SALVE_REGINA_PRAYER),
|
||||||
|
new PrayerItem("Acordaos", "Memorare", MEMORARE_PRAYER)
|
||||||
|
};
|
||||||
|
|
||||||
|
private ScrollView scrollView;
|
||||||
|
private LinearLayout listContainer;
|
||||||
|
private LinearLayout detailContainer;
|
||||||
|
private TextView titleText;
|
||||||
|
private PrayerItem selectedPrayer = PRAYERS[0];
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
isEnglish = UpdateManager.isEnglish(this);
|
||||||
|
isDarkMode = UpdateManager.isDarkMode(this);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
getWindow().setStatusBarColor(bg());
|
||||||
|
getWindow().setNavigationBarColor(bg());
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(createScreen());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
boolean currentLanguage = UpdateManager.isEnglish(this);
|
||||||
|
boolean currentDark = UpdateManager.isDarkMode(this);
|
||||||
|
if (currentLanguage != isEnglish || currentDark != isDarkMode) {
|
||||||
|
isEnglish = currentLanguage;
|
||||||
|
isDarkMode = currentDark;
|
||||||
|
recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (detailContainer != null && detailContainer.getVisibility() == View.VISIBLE) {
|
||||||
|
showPrayerList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int bg() { return isDarkMode ? COLOR_BG_DARK : COLOR_BG_LIGHT; }
|
||||||
|
private int card() { return isDarkMode ? COLOR_CARD_DARK : COLOR_CARD_LIGHT; }
|
||||||
|
private int ink() { return isDarkMode ? COLOR_INK_DARK : COLOR_INK_LIGHT; }
|
||||||
|
private int muted() { return isDarkMode ? COLOR_MUTED_DARK : COLOR_MUTED_LIGHT; }
|
||||||
|
private int stroke() { return isDarkMode ? COLOR_STROKE_DARK : COLOR_STROKE_LIGHT; }
|
||||||
|
private int cardStroke() { return isDarkMode ? COLOR_CARD_STROKE_DARK : COLOR_CARD_STROKE_LIGHT; }
|
||||||
|
|
||||||
|
private View createScreen() {
|
||||||
|
FrameLayout root = new FrameLayout(this);
|
||||||
|
root.setBackgroundColor(bg());
|
||||||
|
|
||||||
|
scrollView = new ScrollView(this);
|
||||||
|
scrollView.setFillViewport(true);
|
||||||
|
scrollView.setClipToPadding(false);
|
||||||
|
|
||||||
|
LinearLayout content = new LinearLayout(this);
|
||||||
|
content.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
content.setPadding(dp(20), dp(28), dp(20), dp(28));
|
||||||
|
scrollView.addView(content, new ScrollView.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
content.addView(createTopBar());
|
||||||
|
|
||||||
|
titleText = textView(isEnglish ? "Extras" : "Extras", 34, ink(), Typeface.BOLD);
|
||||||
|
titleText.setIncludeFontPadding(false);
|
||||||
|
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
titleParams.setMargins(0, dp(18), 0, dp(18));
|
||||||
|
content.addView(titleText, titleParams);
|
||||||
|
|
||||||
|
listContainer = new LinearLayout(this);
|
||||||
|
listContainer.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
for (PrayerItem prayer : PRAYERS) {
|
||||||
|
listContainer.addView(createPrayerCard(prayer));
|
||||||
|
}
|
||||||
|
content.addView(listContainer, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
detailContainer = new LinearLayout(this);
|
||||||
|
detailContainer.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
detailContainer.setVisibility(View.GONE);
|
||||||
|
content.addView(detailContainer, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
root.addView(scrollView, new FrameLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
));
|
||||||
|
|
||||||
|
root.setOnApplyWindowInsetsListener((view, insets) -> {
|
||||||
|
content.setPadding(
|
||||||
|
dp(20),
|
||||||
|
dp(28) + insets.getSystemWindowInsetTop(),
|
||||||
|
dp(20),
|
||||||
|
dp(28) + insets.getSystemWindowInsetBottom()
|
||||||
|
);
|
||||||
|
return insets;
|
||||||
|
});
|
||||||
|
root.requestApplyInsets();
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createTopBar() {
|
||||||
|
LinearLayout topBar = new LinearLayout(this);
|
||||||
|
topBar.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
topBar.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
|
TextView label = textView(isEnglish ? "PRAYERS" : "ORACIONES", 12, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
topBar.addView(label, new LinearLayout.LayoutParams(
|
||||||
|
0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
1f
|
||||||
|
));
|
||||||
|
|
||||||
|
TextView settings = textView(isEnglish ? "Settings" : "Ajustes", 15, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
settings.setGravity(Gravity.CENTER);
|
||||||
|
settings.setPadding(dp(14), 0, dp(14), 0);
|
||||||
|
settings.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
|
settings.setOnClickListener(view -> startActivity(new Intent(this, SettingsActivity.class)));
|
||||||
|
LinearLayout.LayoutParams settingsParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
dp(40)
|
||||||
|
);
|
||||||
|
settingsParams.setMargins(0, 0, dp(8), 0);
|
||||||
|
topBar.addView(settings, settingsParams);
|
||||||
|
|
||||||
|
TextView home = textView(isEnglish ? "Home" : "Inicio", 15, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
home.setGravity(Gravity.CENTER);
|
||||||
|
home.setPadding(dp(14), 0, dp(14), 0);
|
||||||
|
home.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
|
home.setOnClickListener(view -> finish());
|
||||||
|
topBar.addView(home, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
dp(40)
|
||||||
|
));
|
||||||
|
|
||||||
|
return topBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createPrayerCard(PrayerItem prayer) {
|
||||||
|
LinearLayout card = new LinearLayout(this);
|
||||||
|
card.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
card.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
card.setPadding(dp(18), dp(16), dp(16), dp(16));
|
||||||
|
card.setBackground(roundedRect(card(), dp(8), cardStroke(), dp(1)));
|
||||||
|
card.setOnClickListener(view -> showPrayerDetail(prayer));
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
card.setElevation(dp(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayout copy = new LinearLayout(this);
|
||||||
|
copy.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
TextView title = textView(prayer.title, 20, ink(), Typeface.BOLD);
|
||||||
|
title.setIncludeFontPadding(false);
|
||||||
|
copy.addView(title);
|
||||||
|
|
||||||
|
TextView subtitle = textView(prayer.subtitle, 14, muted(), Typeface.BOLD);
|
||||||
|
LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
subtitleParams.setMargins(0, dp(6), 0, 0);
|
||||||
|
copy.addView(subtitle, subtitleParams);
|
||||||
|
|
||||||
|
card.addView(copy, new LinearLayout.LayoutParams(
|
||||||
|
0,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
1f
|
||||||
|
));
|
||||||
|
|
||||||
|
TextView arrow = textView(">", 22, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
arrow.setGravity(Gravity.CENTER);
|
||||||
|
card.addView(arrow, new LinearLayout.LayoutParams(
|
||||||
|
dp(28),
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
cardParams.setMargins(0, 0, 0, dp(12));
|
||||||
|
card.setLayoutParams(cardParams);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderPrayerDetail() {
|
||||||
|
detailContainer.removeAllViews();
|
||||||
|
|
||||||
|
TextView subtitle = textView(selectedPrayer.subtitle, 14, COLOR_WARM, Typeface.BOLD);
|
||||||
|
detailContainer.addView(subtitle);
|
||||||
|
|
||||||
|
TextView prayer = textView(selectedPrayer.body, 21, ink(), Typeface.NORMAL);
|
||||||
|
prayer.setLineSpacing(dp(5), 1.14f);
|
||||||
|
LinearLayout.LayoutParams prayerParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
prayerParams.setMargins(0, dp(16), 0, dp(18));
|
||||||
|
detailContainer.addView(prayer, prayerParams);
|
||||||
|
|
||||||
|
TextView backToList = textView(isEnglish ? "Back to extras" : "Volver a extras", 15, COLOR_ACCENT, Typeface.BOLD);
|
||||||
|
backToList.setGravity(Gravity.CENTER);
|
||||||
|
backToList.setPadding(dp(14), 0, dp(14), 0);
|
||||||
|
backToList.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
|
backToList.setOnClickListener(view -> showPrayerList());
|
||||||
|
detailContainer.addView(backToList, new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
dp(42)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPrayerDetail(PrayerItem prayer) {
|
||||||
|
selectedPrayer = prayer;
|
||||||
|
titleText.setText(prayer.title);
|
||||||
|
renderPrayerDetail();
|
||||||
|
listContainer.setVisibility(View.GONE);
|
||||||
|
detailContainer.setVisibility(View.VISIBLE);
|
||||||
|
scrollToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPrayerList() {
|
||||||
|
titleText.setText(isEnglish ? "Extras" : "Extras");
|
||||||
|
detailContainer.setVisibility(View.GONE);
|
||||||
|
listContainer.setVisibility(View.VISIBLE);
|
||||||
|
scrollToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scrollToTop() {
|
||||||
|
if (scrollView != null) {
|
||||||
|
scrollView.post(() -> scrollView.smoothScrollTo(0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextView textView(String text, int sizeSp, int color, int style) {
|
||||||
|
TextView textView = new TextView(this);
|
||||||
|
textView.setText(text);
|
||||||
|
textView.setTextSize(sizeSp);
|
||||||
|
textView.setTextColor(color);
|
||||||
|
textView.setTypeface(Typeface.DEFAULT, style);
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GradientDrawable roundedRect(int color, int radius, int strokeColor, int strokeWidth) {
|
||||||
|
GradientDrawable drawable = new GradientDrawable();
|
||||||
|
drawable.setShape(GradientDrawable.RECTANGLE);
|
||||||
|
drawable.setColor(color);
|
||||||
|
drawable.setCornerRadius(radius);
|
||||||
|
if (strokeWidth > 0) {
|
||||||
|
drawable.setStroke(strokeWidth, strokeColor);
|
||||||
|
}
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dp(int value) {
|
||||||
|
return Math.round(value * getResources().getDisplayMetrics().density);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PrayerItem {
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
final String body;
|
||||||
|
|
||||||
|
PrayerItem(String title, String subtitle, String body) {
|
||||||
|
this.title = title;
|
||||||
|
this.subtitle = subtitle;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,10 +50,29 @@ import java.util.concurrent.Executors;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
private static final int COLOR_BACKGROUND = Color.rgb(247, 248, 246);
|
// Light mode colors
|
||||||
private static final int COLOR_CARD = Color.WHITE;
|
private static final int COLOR_BACKGROUND_LIGHT = Color.rgb(247, 248, 246);
|
||||||
private static final int COLOR_INK = Color.rgb(25, 31, 31);
|
private static final int COLOR_CARD_LIGHT = Color.WHITE;
|
||||||
private static final int COLOR_MUTED = Color.rgb(91, 99, 98);
|
private static final int COLOR_INK_LIGHT = Color.rgb(25, 31, 31);
|
||||||
|
private static final int COLOR_MUTED_LIGHT = Color.rgb(91, 99, 98);
|
||||||
|
private static final int COLOR_STROKE_LIGHT = Color.rgb(229, 232, 230);
|
||||||
|
private static final int COLOR_CHIP_BG_LIGHT = Color.rgb(219, 226, 222);
|
||||||
|
private static final int COLOR_SPEAKER_BG_LIGHT = Color.rgb(229, 244, 240);
|
||||||
|
private static final int COLOR_REFERENCE_BG_LIGHT = Color.rgb(229, 244, 240);
|
||||||
|
private static final int COLOR_TODAY_BG_LIGHT = Color.rgb(255, 239, 236);
|
||||||
|
|
||||||
|
// Dark mode colors
|
||||||
|
private static final int COLOR_BACKGROUND_DARK = Color.rgb(26, 28, 30);
|
||||||
|
private static final int COLOR_CARD_DARK = Color.rgb(38, 41, 44);
|
||||||
|
private static final int COLOR_INK_DARK = Color.rgb(224, 226, 219);
|
||||||
|
private static final int COLOR_MUTED_DARK = Color.rgb(158, 163, 160);
|
||||||
|
private static final int COLOR_STROKE_DARK = Color.rgb(58, 62, 65);
|
||||||
|
private static final int COLOR_CHIP_BG_DARK = Color.rgb(48, 52, 55);
|
||||||
|
private static final int COLOR_SPEAKER_BG_DARK = Color.rgb(45, 65, 60);
|
||||||
|
private static final int COLOR_REFERENCE_BG_DARK = Color.rgb(45, 65, 60);
|
||||||
|
private static final int COLOR_TODAY_BG_DARK = Color.rgb(75, 50, 48);
|
||||||
|
|
||||||
|
// Shared colors (no change between modes)
|
||||||
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
||||||
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
||||||
private static final int COLOR_HOLIDAY_BG = Color.rgb(255, 246, 229);
|
private static final int COLOR_HOLIDAY_BG = Color.rgb(255, 246, 229);
|
||||||
@@ -120,19 +139,21 @@ public class MainActivity extends Activity {
|
|||||||
private int ttsGeneration;
|
private int ttsGeneration;
|
||||||
private float readingFontSp;
|
private float readingFontSp;
|
||||||
private boolean isEnglish;
|
private boolean isEnglish;
|
||||||
|
private boolean isDarkMode;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
getWindow().setStatusBarColor(COLOR_BACKGROUND);
|
getWindow().setStatusBarColor(bg());
|
||||||
getWindow().setNavigationBarColor(COLOR_BACKGROUND);
|
getWindow().setNavigationBarColor(bg());
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences = getSharedPreferences("preferencias_lectura", MODE_PRIVATE);
|
preferences = getSharedPreferences("preferencias_lectura", MODE_PRIVATE);
|
||||||
readingFontSp = preferences.getFloat("tamano_letra", 20f);
|
readingFontSp = preferences.getFloat("tamano_letra", 20f);
|
||||||
isEnglish = preferences.getBoolean("is_english", false);
|
isEnglish = preferences.getBoolean("is_english", false);
|
||||||
|
isDarkMode = preferences.getBoolean("dark_mode", false);
|
||||||
selectedDateCalendar = startOfDay(Calendar.getInstance());
|
selectedDateCalendar = startOfDay(Calendar.getInstance());
|
||||||
visibleMonthCalendar = startOfMonth(selectedDateCalendar);
|
visibleMonthCalendar = startOfMonth(selectedDateCalendar);
|
||||||
executor = Executors.newSingleThreadExecutor();
|
executor = Executors.newSingleThreadExecutor();
|
||||||
@@ -163,15 +184,28 @@ public class MainActivity extends Activity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
boolean currentLanguage = UpdateManager.isEnglish(this);
|
boolean currentLanguage = UpdateManager.isEnglish(this);
|
||||||
if (currentLanguage != isEnglish) {
|
boolean currentDark = UpdateManager.isDarkMode(this);
|
||||||
|
if (currentLanguage != isEnglish || currentDark != isDarkMode) {
|
||||||
isEnglish = currentLanguage;
|
isEnglish = currentLanguage;
|
||||||
|
isDarkMode = currentDark;
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Dark mode aware color helpers ---
|
||||||
|
private int bg() { return isDarkMode ? COLOR_BACKGROUND_DARK : COLOR_BACKGROUND_LIGHT; }
|
||||||
|
private int card() { return isDarkMode ? COLOR_CARD_DARK : COLOR_CARD_LIGHT; }
|
||||||
|
private int ink() { return isDarkMode ? COLOR_INK_DARK : COLOR_INK_LIGHT; }
|
||||||
|
private int muted() { return isDarkMode ? COLOR_MUTED_DARK : COLOR_MUTED_LIGHT; }
|
||||||
|
private int stroke() { return isDarkMode ? COLOR_STROKE_DARK : COLOR_STROKE_LIGHT; }
|
||||||
|
private int chipBg() { return isDarkMode ? COLOR_CHIP_BG_DARK : COLOR_CHIP_BG_LIGHT; }
|
||||||
|
private int speakerBg() { return isDarkMode ? COLOR_SPEAKER_BG_DARK : COLOR_SPEAKER_BG_LIGHT; }
|
||||||
|
private int referenceBg() { return isDarkMode ? COLOR_REFERENCE_BG_DARK : COLOR_REFERENCE_BG_LIGHT; }
|
||||||
|
private int todayBg() { return isDarkMode ? COLOR_TODAY_BG_DARK : COLOR_TODAY_BG_LIGHT; }
|
||||||
|
|
||||||
private View createScreen() {
|
private View createScreen() {
|
||||||
FrameLayout root = new FrameLayout(this);
|
FrameLayout root = new FrameLayout(this);
|
||||||
root.setBackgroundColor(COLOR_BACKGROUND);
|
root.setBackgroundColor(bg());
|
||||||
|
|
||||||
ScrollView scrollView = new ScrollView(this);
|
ScrollView scrollView = new ScrollView(this);
|
||||||
scrollView.setFillViewport(true);
|
scrollView.setFillViewport(true);
|
||||||
@@ -195,7 +229,7 @@ public class MainActivity extends Activity {
|
|||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
));
|
));
|
||||||
|
|
||||||
sourceText = textView(isEnglish ? "Source: Vatican News" : "Fuente: Vatican News", 13, COLOR_MUTED, Typeface.NORMAL);
|
sourceText = textView(isEnglish ? "Source: Vatican News" : "Fuente: Vatican News", 13, muted(), Typeface.NORMAL);
|
||||||
LinearLayout.LayoutParams sourceParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams sourceParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
@@ -268,7 +302,7 @@ public class MainActivity extends Activity {
|
|||||||
topRow.addView(createDateChip());
|
topRow.addView(createDateChip());
|
||||||
header.addView(topRow);
|
header.addView(topRow);
|
||||||
|
|
||||||
TextView title = textView(isEnglish ? "Word of the day" : "Palabra del día", 34, COLOR_INK, Typeface.BOLD);
|
TextView title = textView(isEnglish ? "Word of the day" : "Palabra del día", 34, ink(), Typeface.BOLD);
|
||||||
title.setIncludeFontPadding(false);
|
title.setIncludeFontPadding(false);
|
||||||
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
@@ -292,7 +326,7 @@ public class MainActivity extends Activity {
|
|||||||
calendarParams.setMargins(0, dp(2), 0, dp(14));
|
calendarParams.setMargins(0, dp(2), 0, dp(14));
|
||||||
header.addView(calendarPanel, calendarParams);
|
header.addView(calendarPanel, calendarParams);
|
||||||
|
|
||||||
dateText = textView("", 16, COLOR_MUTED, Typeface.BOLD);
|
dateText = textView("", 16, muted(), Typeface.BOLD);
|
||||||
header.addView(dateText);
|
header.addView(dateText);
|
||||||
|
|
||||||
holidayTagsRow = new LinearLayout(this);
|
holidayTagsRow = new LinearLayout(this);
|
||||||
@@ -306,7 +340,7 @@ public class MainActivity extends Activity {
|
|||||||
tagsParams.setMargins(0, dp(8), 0, 0);
|
tagsParams.setMargins(0, dp(8), 0, 0);
|
||||||
header.addView(holidayTagsRow, tagsParams);
|
header.addView(holidayTagsRow, tagsParams);
|
||||||
|
|
||||||
liturgyText = textView("", 16, COLOR_INK, Typeface.NORMAL);
|
liturgyText = textView("", 16, ink(), Typeface.NORMAL);
|
||||||
liturgyText.setLineSpacing(0, 1.12f);
|
liturgyText.setLineSpacing(0, 1.12f);
|
||||||
LinearLayout.LayoutParams liturgyParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams liturgyParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
@@ -339,7 +373,7 @@ public class MainActivity extends Activity {
|
|||||||
chip.setOrientation(LinearLayout.HORIZONTAL);
|
chip.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
chip.setGravity(Gravity.CENTER_VERTICAL);
|
chip.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
chip.setPadding(dp(12), dp(8), dp(10), dp(8));
|
chip.setPadding(dp(12), dp(8), dp(10), dp(8));
|
||||||
chip.setBackground(roundedRect(Color.WHITE, dp(8), Color.rgb(219, 226, 222), dp(1)));
|
chip.setBackground(roundedRect(card(), dp(8), chipBg(), dp(1)));
|
||||||
chip.setContentDescription(isEnglish ? "Choose date" : "Elegir fecha");
|
chip.setContentDescription(isEnglish ? "Choose date" : "Elegir fecha");
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
chip.setElevation(dp(1));
|
chip.setElevation(dp(1));
|
||||||
@@ -350,11 +384,11 @@ public class MainActivity extends Activity {
|
|||||||
labelGroup.setOrientation(LinearLayout.VERTICAL);
|
labelGroup.setOrientation(LinearLayout.VERTICAL);
|
||||||
labelGroup.setGravity(Gravity.CENTER_VERTICAL);
|
labelGroup.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
dateChipPrimary = textView("", 20, COLOR_INK, Typeface.BOLD);
|
dateChipPrimary = textView("", 20, ink(), Typeface.BOLD);
|
||||||
dateChipPrimary.setIncludeFontPadding(false);
|
dateChipPrimary.setIncludeFontPadding(false);
|
||||||
labelGroup.addView(dateChipPrimary);
|
labelGroup.addView(dateChipPrimary);
|
||||||
|
|
||||||
dateChipSecondary = textView("", 11, COLOR_MUTED, Typeface.BOLD);
|
dateChipSecondary = textView("", 11, muted(), Typeface.BOLD);
|
||||||
dateChipSecondary.setIncludeFontPadding(false);
|
dateChipSecondary.setIncludeFontPadding(false);
|
||||||
labelGroup.addView(dateChipSecondary);
|
labelGroup.addView(dateChipSecondary);
|
||||||
|
|
||||||
@@ -378,7 +412,7 @@ public class MainActivity extends Activity {
|
|||||||
panel.setOrientation(LinearLayout.VERTICAL);
|
panel.setOrientation(LinearLayout.VERTICAL);
|
||||||
panel.setPadding(dp(14), dp(12), dp(14), dp(14));
|
panel.setPadding(dp(14), dp(12), dp(14), dp(14));
|
||||||
panel.setVisibility(View.GONE);
|
panel.setVisibility(View.GONE);
|
||||||
panel.setBackground(roundedRect(Color.WHITE, dp(8), Color.rgb(219, 226, 222), dp(1)));
|
panel.setBackground(roundedRect(card(), dp(8), chipBg(), dp(1)));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
panel.setElevation(dp(4));
|
panel.setElevation(dp(4));
|
||||||
}
|
}
|
||||||
@@ -389,7 +423,7 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
monthRow.addView(calendarNavButton("<", view -> changeVisibleMonth(-1)));
|
monthRow.addView(calendarNavButton("<", view -> changeVisibleMonth(-1)));
|
||||||
|
|
||||||
calendarMonthText = textView("", 18, COLOR_INK, Typeface.BOLD);
|
calendarMonthText = textView("", 18, ink(), Typeface.BOLD);
|
||||||
calendarMonthText.setGravity(Gravity.CENTER);
|
calendarMonthText.setGravity(Gravity.CENTER);
|
||||||
monthRow.addView(calendarMonthText, new LinearLayout.LayoutParams(
|
monthRow.addView(calendarMonthText, new LinearLayout.LayoutParams(
|
||||||
0,
|
0,
|
||||||
@@ -418,7 +452,7 @@ public class MainActivity extends Activity {
|
|||||||
weekdays.setOrientation(LinearLayout.HORIZONTAL);
|
weekdays.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
String[] labels = {"L", "M", "X", "J", "V", "S", "D"};
|
String[] labels = {"L", "M", "X", "J", "V", "S", "D"};
|
||||||
for (String label : labels) {
|
for (String label : labels) {
|
||||||
TextView dayLabel = textView(label, 12, COLOR_MUTED, Typeface.BOLD);
|
TextView dayLabel = textView(label, 12, muted(), Typeface.BOLD);
|
||||||
dayLabel.setGravity(Gravity.CENTER);
|
dayLabel.setGravity(Gravity.CENTER);
|
||||||
weekdays.addView(dayLabel, new LinearLayout.LayoutParams(
|
weekdays.addView(dayLabel, new LinearLayout.LayoutParams(
|
||||||
0,
|
0,
|
||||||
@@ -443,7 +477,7 @@ public class MainActivity extends Activity {
|
|||||||
private TextView calendarNavButton(String text, View.OnClickListener listener) {
|
private TextView calendarNavButton(String text, View.OnClickListener listener) {
|
||||||
TextView button = textView(text, 22, COLOR_ACCENT, Typeface.BOLD);
|
TextView button = textView(text, 22, COLOR_ACCENT, Typeface.BOLD);
|
||||||
button.setGravity(Gravity.CENTER);
|
button.setGravity(Gravity.CENTER);
|
||||||
button.setBackground(roundedRect(Color.rgb(229, 244, 240), dp(8), Color.TRANSPARENT, 0));
|
button.setBackground(roundedRect(speakerBg(), dp(8), Color.TRANSPARENT, 0));
|
||||||
button.setOnClickListener(listener);
|
button.setOnClickListener(listener);
|
||||||
button.setContentDescription(text.equals("<") ? (isEnglish ? "Previous month" : "Mes anterior") : (isEnglish ? "Next month" : "Mes siguiente"));
|
button.setContentDescription(text.equals("<") ? (isEnglish ? "Previous month" : "Mes anterior") : (isEnglish ? "Next month" : "Mes siguiente"));
|
||||||
return button;
|
return button;
|
||||||
@@ -453,7 +487,7 @@ public class MainActivity extends Activity {
|
|||||||
TextView button = textView(text, 13, COLOR_ACCENT, Typeface.BOLD);
|
TextView button = textView(text, 13, COLOR_ACCENT, Typeface.BOLD);
|
||||||
button.setGravity(Gravity.CENTER);
|
button.setGravity(Gravity.CENTER);
|
||||||
button.setPadding(dp(8), 0, dp(8), 0);
|
button.setPadding(dp(8), 0, dp(8), 0);
|
||||||
button.setBackground(roundedRect(Color.rgb(229, 244, 240), dp(8), Color.TRANSPARENT, 0));
|
button.setBackground(roundedRect(speakerBg(), dp(8), Color.TRANSPARENT, 0));
|
||||||
button.setOnClickListener(listener);
|
button.setOnClickListener(listener);
|
||||||
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
@@ -512,7 +546,7 @@ public class MainActivity extends Activity {
|
|||||||
Calendar today = startOfDay(Calendar.getInstance());
|
Calendar today = startOfDay(Calendar.getInstance());
|
||||||
|
|
||||||
for (int cell = 0; cell < 42; cell++) {
|
for (int cell = 0; cell < 42; cell++) {
|
||||||
TextView dayCell = textView("", 16, COLOR_INK, Typeface.BOLD);
|
TextView dayCell = textView("", 16, ink(), Typeface.BOLD);
|
||||||
dayCell.setGravity(Gravity.CENTER);
|
dayCell.setGravity(Gravity.CENTER);
|
||||||
dayCell.setIncludeFontPadding(false);
|
dayCell.setIncludeFontPadding(false);
|
||||||
|
|
||||||
@@ -540,7 +574,7 @@ public class MainActivity extends Activity {
|
|||||||
dayCell.setBackground(roundedRect(COLOR_HOLIDAY_BG, dp(8), COLOR_HOLIDAY_BORDER, dp(1)));
|
dayCell.setBackground(roundedRect(COLOR_HOLIDAY_BG, dp(8), COLOR_HOLIDAY_BORDER, dp(1)));
|
||||||
} else if (isSameDay(cellDate, today)) {
|
} else if (isSameDay(cellDate, today)) {
|
||||||
dayCell.setTextColor(COLOR_WARM);
|
dayCell.setTextColor(COLOR_WARM);
|
||||||
dayCell.setBackground(roundedRect(Color.rgb(255, 239, 236), dp(8), Color.TRANSPARENT, 0));
|
dayCell.setBackground(roundedRect(todayBg(), dp(8), Color.TRANSPARENT, 0));
|
||||||
} else {
|
} else {
|
||||||
dayCell.setBackground(roundedRect(Color.TRANSPARENT, dp(8), Color.TRANSPARENT, 0));
|
dayCell.setBackground(roundedRect(Color.TRANSPARENT, dp(8), Color.TRANSPARENT, 0));
|
||||||
}
|
}
|
||||||
@@ -983,7 +1017,7 @@ public class MainActivity extends Activity {
|
|||||||
statusBlock = new LinearLayout(this);
|
statusBlock = new LinearLayout(this);
|
||||||
statusBlock.setOrientation(LinearLayout.VERTICAL);
|
statusBlock.setOrientation(LinearLayout.VERTICAL);
|
||||||
statusBlock.setPadding(dp(18), dp(16), dp(18), dp(16));
|
statusBlock.setPadding(dp(18), dp(16), dp(18), dp(16));
|
||||||
statusBlock.setBackground(roundedRect(COLOR_CARD, dp(8), Color.TRANSPARENT, 0));
|
statusBlock.setBackground(roundedRect(card(), dp(8), Color.TRANSPARENT, 0));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
statusBlock.setElevation(dp(1));
|
statusBlock.setElevation(dp(1));
|
||||||
}
|
}
|
||||||
@@ -997,7 +1031,7 @@ public class MainActivity extends Activity {
|
|||||||
progressParams.setMargins(0, 0, dp(12), 0);
|
progressParams.setMargins(0, 0, dp(12), 0);
|
||||||
row.addView(progressBar, progressParams);
|
row.addView(progressBar, progressParams);
|
||||||
|
|
||||||
statusText = textView(isEnglish ? "Loading today's Word..." : "Cargando la Palabra de hoy...", 16, COLOR_INK, Typeface.NORMAL);
|
statusText = textView(isEnglish ? "Loading today's Word..." : "Cargando la Palabra de hoy...", 16, ink(), Typeface.NORMAL);
|
||||||
statusText.setLineSpacing(0, 1.16f);
|
statusText.setLineSpacing(0, 1.16f);
|
||||||
row.addView(statusText, new LinearLayout.LayoutParams(
|
row.addView(statusText, new LinearLayout.LayoutParams(
|
||||||
0,
|
0,
|
||||||
@@ -1035,7 +1069,7 @@ public class MainActivity extends Activity {
|
|||||||
panel.setOrientation(LinearLayout.VERTICAL);
|
panel.setOrientation(LinearLayout.VERTICAL);
|
||||||
panel.setPadding(dp(16), dp(14), dp(16), dp(14));
|
panel.setPadding(dp(16), dp(14), dp(16), dp(14));
|
||||||
panel.setVisibility(View.GONE);
|
panel.setVisibility(View.GONE);
|
||||||
panel.setBackground(roundedRect(Color.WHITE, dp(8), Color.rgb(223, 229, 226), dp(1)));
|
panel.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
panel.setElevation(dp(8));
|
panel.setElevation(dp(8));
|
||||||
}
|
}
|
||||||
@@ -1043,10 +1077,10 @@ public class MainActivity extends Activity {
|
|||||||
LinearLayout labelRow = new LinearLayout(this);
|
LinearLayout labelRow = new LinearLayout(this);
|
||||||
labelRow.setGravity(Gravity.CENTER_VERTICAL);
|
labelRow.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
TextView label = textView(isEnglish ? "Font size" : "Tamaño de letra", 15, COLOR_INK, Typeface.BOLD);
|
TextView label = textView(isEnglish ? "Font size" : "Tamaño de letra", 15, ink(), Typeface.BOLD);
|
||||||
labelRow.addView(label, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
|
labelRow.addView(label, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
|
||||||
|
|
||||||
fontValueText = textView(Math.round(readingFontSp) + " sp", 14, COLOR_MUTED, Typeface.BOLD);
|
fontValueText = textView(Math.round(readingFontSp) + " sp", 14, muted(), Typeface.BOLD);
|
||||||
labelRow.addView(fontValueText);
|
labelRow.addView(fontValueText);
|
||||||
panel.addView(labelRow);
|
panel.addView(labelRow);
|
||||||
|
|
||||||
@@ -1380,7 +1414,7 @@ public class MainActivity extends Activity {
|
|||||||
button.setTextColor(COLOR_ACCENT);
|
button.setTextColor(COLOR_ACCENT);
|
||||||
button.setTextSize(14);
|
button.setTextSize(14);
|
||||||
button.setAllCaps(false);
|
button.setAllCaps(false);
|
||||||
button.setBackground(roundedRect(Color.WHITE, dp(8), Color.rgb(219, 226, 222), dp(1)));
|
button.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1674,7 +1708,7 @@ public class MainActivity extends Activity {
|
|||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(Gravity.CENTER_VERTICAL);
|
row.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
|
||||||
TextView titleText = textView(title, titleSizeSp, COLOR_INK, Typeface.BOLD);
|
TextView titleText = textView(title, titleSizeSp, ink(), Typeface.BOLD);
|
||||||
titleText.setIncludeFontPadding(false);
|
titleText.setIncludeFontPadding(false);
|
||||||
row.addView(titleText, new LinearLayout.LayoutParams(
|
row.addView(titleText, new LinearLayout.LayoutParams(
|
||||||
0,
|
0,
|
||||||
@@ -1686,7 +1720,7 @@ public class MainActivity extends Activity {
|
|||||||
speakerButton.setImageResource(R.drawable.ic_speaker_24);
|
speakerButton.setImageResource(R.drawable.ic_speaker_24);
|
||||||
speakerButton.setColorFilter(COLOR_ACCENT);
|
speakerButton.setColorFilter(COLOR_ACCENT);
|
||||||
speakerButton.setPadding(dp(8), dp(8), dp(8), dp(8));
|
speakerButton.setPadding(dp(8), dp(8), dp(8), dp(8));
|
||||||
speakerButton.setBackground(roundedRect(Color.rgb(229, 244, 240), dp(8), Color.TRANSPARENT, 0));
|
speakerButton.setBackground(roundedRect(speakerBg(), dp(8), Color.TRANSPARENT, 0));
|
||||||
speakerButton.setContentDescription((isEnglish ? "Listen to " : "Escuchar ") + title);
|
speakerButton.setContentDescription((isEnglish ? "Listen to " : "Escuchar ") + title);
|
||||||
speakerButton.setOnClickListener(view -> startTtsConversionForText(speechText, controls));
|
speakerButton.setOnClickListener(view -> startTtsConversionForText(speechText, controls));
|
||||||
|
|
||||||
@@ -1697,7 +1731,7 @@ public class MainActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TtsControls createTtsControls() {
|
private TtsControls createTtsControls() {
|
||||||
TextView status = textView("", 14, COLOR_MUTED, Typeface.BOLD);
|
TextView status = textView("", 14, muted(), Typeface.BOLD);
|
||||||
status.setVisibility(View.GONE);
|
status.setVisibility(View.GONE);
|
||||||
|
|
||||||
LinearLayout playerPanel = new LinearLayout(this);
|
LinearLayout playerPanel = new LinearLayout(this);
|
||||||
@@ -1738,7 +1772,7 @@ public class MainActivity extends Activity {
|
|||||||
seekParams.setMargins(dp(8), 0, dp(8), 0);
|
seekParams.setMargins(dp(8), 0, dp(8), 0);
|
||||||
playerPanel.addView(seekBar, seekParams);
|
playerPanel.addView(seekBar, seekParams);
|
||||||
|
|
||||||
TextView timeText = textView("0:00", 13, COLOR_MUTED, Typeface.BOLD);
|
TextView timeText = textView("0:00", 13, muted(), Typeface.BOLD);
|
||||||
timeText.setGravity(Gravity.CENTER_VERTICAL);
|
timeText.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
playerPanel.addView(timeText, new LinearLayout.LayoutParams(
|
playerPanel.addView(timeText, new LinearLayout.LayoutParams(
|
||||||
dp(86),
|
dp(86),
|
||||||
@@ -1797,7 +1831,7 @@ public class MainActivity extends Activity {
|
|||||||
addTtsControlsToCard(card, ttsControls);
|
addTtsControlsToCard(card, ttsControls);
|
||||||
|
|
||||||
if (!section.introduction.isEmpty()) {
|
if (!section.introduction.isEmpty()) {
|
||||||
TextView introText = textView(section.introduction, 16, COLOR_MUTED, Typeface.BOLD);
|
TextView introText = textView(section.introduction, 16, muted(), Typeface.BOLD);
|
||||||
introText.setLineSpacing(0, 1.14f);
|
introText.setLineSpacing(0, 1.14f);
|
||||||
resizableTextViews.add(introText);
|
resizableTextViews.add(introText);
|
||||||
card.addView(introText);
|
card.addView(introText);
|
||||||
@@ -1806,7 +1840,7 @@ public class MainActivity extends Activity {
|
|||||||
if (!section.reference.isEmpty()) {
|
if (!section.reference.isEmpty()) {
|
||||||
TextView referenceText = textView(section.reference, 15, COLOR_ACCENT, Typeface.BOLD);
|
TextView referenceText = textView(section.reference, 15, COLOR_ACCENT, Typeface.BOLD);
|
||||||
referenceText.setGravity(Gravity.CENTER_VERTICAL);
|
referenceText.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
referenceText.setBackground(roundedRect(Color.rgb(229, 244, 240), dp(8), Color.TRANSPARENT, 0));
|
referenceText.setBackground(roundedRect(referenceBg(), dp(8), Color.TRANSPARENT, 0));
|
||||||
referenceText.setPadding(dp(10), dp(6), dp(10), dp(6));
|
referenceText.setPadding(dp(10), dp(6), dp(10), dp(6));
|
||||||
LinearLayout.LayoutParams referenceParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams referenceParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
@@ -1816,7 +1850,7 @@ public class MainActivity extends Activity {
|
|||||||
card.addView(referenceText, referenceParams);
|
card.addView(referenceText, referenceParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView bodyText = textView(section.body, Math.round(readingFontSp), COLOR_INK, Typeface.NORMAL);
|
TextView bodyText = textView(section.body, Math.round(readingFontSp), ink(), Typeface.NORMAL);
|
||||||
bodyText.setLineSpacing(dp(4), 1.16f);
|
bodyText.setLineSpacing(dp(4), 1.16f);
|
||||||
resizableTextViews.add(bodyText);
|
resizableTextViews.add(bodyText);
|
||||||
card.addView(bodyText);
|
card.addView(bodyText);
|
||||||
@@ -1841,7 +1875,7 @@ public class MainActivity extends Activity {
|
|||||||
));
|
));
|
||||||
addTtsControlsToCard(card, ttsControls);
|
addTtsControlsToCard(card, ttsControls);
|
||||||
|
|
||||||
TextView body = textView(section.body, Math.round(readingFontSp), COLOR_INK, Typeface.NORMAL);
|
TextView body = textView(section.body, Math.round(readingFontSp), ink(), Typeface.NORMAL);
|
||||||
body.setLineSpacing(dp(4), 1.16f);
|
body.setLineSpacing(dp(4), 1.16f);
|
||||||
LinearLayout.LayoutParams bodyParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams bodyParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
@@ -1858,7 +1892,7 @@ public class MainActivity extends Activity {
|
|||||||
LinearLayout card = new LinearLayout(this);
|
LinearLayout card = new LinearLayout(this);
|
||||||
card.setOrientation(LinearLayout.VERTICAL);
|
card.setOrientation(LinearLayout.VERTICAL);
|
||||||
card.setPadding(padding, padding, padding, padding);
|
card.setPadding(padding, padding, padding, padding);
|
||||||
card.setBackground(roundedRect(COLOR_CARD, dp(8), Color.rgb(229, 232, 230), dp(1)));
|
card.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
card.setElevation(dp(1));
|
card.setElevation(dp(1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,20 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class SettingsActivity extends Activity {
|
public class SettingsActivity extends Activity {
|
||||||
private static final int COLOR_BACKGROUND = Color.rgb(247, 248, 246);
|
// Light mode colors
|
||||||
private static final int COLOR_CARD = Color.WHITE;
|
private static final int COLOR_BG_LIGHT = Color.rgb(247, 248, 246);
|
||||||
private static final int COLOR_INK = Color.rgb(25, 31, 31);
|
private static final int COLOR_CARD_LIGHT = Color.WHITE;
|
||||||
private static final int COLOR_MUTED = Color.rgb(91, 99, 98);
|
private static final int COLOR_INK_LIGHT = Color.rgb(25, 31, 31);
|
||||||
|
private static final int COLOR_MUTED_LIGHT = Color.rgb(91, 99, 98);
|
||||||
|
private static final int COLOR_STROKE_LIGHT = Color.rgb(219, 226, 222);
|
||||||
|
|
||||||
|
// Dark mode colors
|
||||||
|
private static final int COLOR_BG_DARK = Color.rgb(26, 28, 30);
|
||||||
|
private static final int COLOR_CARD_DARK = Color.rgb(38, 41, 44);
|
||||||
|
private static final int COLOR_INK_DARK = Color.rgb(224, 226, 219);
|
||||||
|
private static final int COLOR_MUTED_DARK = Color.rgb(158, 163, 160);
|
||||||
|
private static final int COLOR_STROKE_DARK = Color.rgb(58, 62, 65);
|
||||||
|
|
||||||
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
|
||||||
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
private static final int COLOR_WARM = Color.rgb(217, 75, 61);
|
||||||
|
|
||||||
@@ -183,11 +193,11 @@ public class SettingsActivity extends Activity {
|
|||||||
1f
|
1f
|
||||||
));
|
));
|
||||||
|
|
||||||
TextView langToggle = actionButton(UpdateManager.isEnglish(this) ? "English" : "Español", COLOR_ACCENT, Color.WHITE);
|
TextView langToggle = actionButton(UpdateManager.isEnglish(this) ? "English" : "Español", COLOR_ACCENT, Color.WHITE);
|
||||||
langToggle.setOnClickListener(view -> {
|
langToggle.setOnClickListener(view -> {
|
||||||
boolean current = UpdateManager.isEnglish(this);
|
boolean current = UpdateManager.isEnglish(this);
|
||||||
UpdateManager.setEnglish(this, !current);
|
UpdateManager.setEnglish(this, !current);
|
||||||
langToggle.setText(!current ? "English" : "Español");
|
langToggle.setText(!current ? "English" : "Español");
|
||||||
updateVoiceCard();
|
updateVoiceCard();
|
||||||
});
|
});
|
||||||
card.addView(langToggle, new LinearLayout.LayoutParams(dp(100), dp(40)));
|
card.addView(langToggle, new LinearLayout.LayoutParams(dp(100), dp(40)));
|
||||||
@@ -338,7 +348,7 @@ public class SettingsActivity extends Activity {
|
|||||||
String voiceId = UpdateManager.getTtsVoice(this, english);
|
String voiceId = UpdateManager.getTtsVoice(this, english);
|
||||||
voiceSubtitleText.setText(english
|
voiceSubtitleText.setText(english
|
||||||
? "English voices are shown while English is selected"
|
? "English voices are shown while English is selected"
|
||||||
: "Las voces en español se muestran mientras el español esté seleccionado");
|
: "Las voces en español se muestran mientras el español esté seleccionado");
|
||||||
voiceButton.setText(UpdateManager.getTtsVoiceLabel(english, voiceId));
|
voiceButton.setText(UpdateManager.getTtsVoiceLabel(english, voiceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +359,7 @@ public class SettingsActivity extends Activity {
|
|||||||
+ UpdateManager.getInstalledVersionName(this)
|
+ UpdateManager.getInstalledVersionName(this)
|
||||||
+ " (" + UpdateManager.getInstalledVersionCode(this) + ")");
|
+ " (" + UpdateManager.getInstalledVersionCode(this) + ")");
|
||||||
} catch (Exception error) {
|
} catch (Exception error) {
|
||||||
installedVersionText.setText(isEnglish ? "Installed version unavailable." : "Versión instalada no disponible.");
|
installedVersionText.setText(isEnglish ? "Installed version unavailable." : "Versión instalada no disponible.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ final class UpdateManager {
|
|||||||
static final String PREFS_NAME = "preferencias_lectura";
|
static final String PREFS_NAME = "preferencias_lectura";
|
||||||
static final String KEY_AUTO_UPDATES = "auto_updates_enabled";
|
static final String KEY_AUTO_UPDATES = "auto_updates_enabled";
|
||||||
static final String KEY_IS_ENGLISH = "is_english";
|
static final String KEY_IS_ENGLISH = "is_english";
|
||||||
|
static final String KEY_DARK_MODE = "dark_mode";
|
||||||
static final String KEY_TTS_VOICE_ENGLISH = "tts_voice_english";
|
static final String KEY_TTS_VOICE_ENGLISH = "tts_voice_english";
|
||||||
static final String KEY_TTS_VOICE_SPANISH = "tts_voice_spanish";
|
static final String KEY_TTS_VOICE_SPANISH = "tts_voice_spanish";
|
||||||
static final String DEFAULT_TTS_VOICE_ENGLISH = "af_heart";
|
static final String DEFAULT_TTS_VOICE_ENGLISH = "af_heart";
|
||||||
@@ -89,6 +90,14 @@ final class UpdateManager {
|
|||||||
preferences(context).edit().putBoolean(KEY_IS_ENGLISH, enabled).apply();
|
preferences(context).edit().putBoolean(KEY_IS_ENGLISH, enabled).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isDarkMode(Context context) {
|
||||||
|
return preferences(context).getBoolean(KEY_DARK_MODE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setDarkMode(Context context, boolean enabled) {
|
||||||
|
preferences(context).edit().putBoolean(KEY_DARK_MODE, enabled).apply();
|
||||||
|
}
|
||||||
|
|
||||||
static VoiceOption[] getTtsVoiceOptions(boolean isEnglish) {
|
static VoiceOption[] getTtsVoiceOptions(boolean isEnglish) {
|
||||||
return isEnglish ? ENGLISH_VOICES : SPANISH_VOICES;
|
return isEnglish ? ENGLISH_VOICES : SPANISH_VOICES;
|
||||||
}
|
}
|
||||||
@@ -207,10 +216,10 @@ final class UpdateManager {
|
|||||||
|
|
||||||
boolean english = isEnglish(activity);
|
boolean english = isEnglish(activity);
|
||||||
new AlertDialog.Builder(activity)
|
new AlertDialog.Builder(activity)
|
||||||
.setTitle(english ? "Update available" : "Actualización disponible")
|
.setTitle(english ? "Update available" : "Actualización disponible")
|
||||||
.setMessage((english ? "Version " : "Versión ") + version + (english ? " is ready to download." : " está lista para descargar."))
|
.setMessage((english ? "Version " : "Versión ") + version + (english ? " is ready to download." : " está lista para descargar."))
|
||||||
.setPositiveButton(english ? "Download" : "Descargar", (dialog, which) -> openDownload(activity, info.apkUrl))
|
.setPositiveButton(english ? "Download" : "Descargar", (dialog, which) -> openDownload(activity, info.apkUrl))
|
||||||
.setNegativeButton(english ? "Later" : "Después", null)
|
.setNegativeButton(english ? "Later" : "Después", null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme" parent="android:style/Theme.Material.NoActionBar">
|
||||||
|
<item name="android:fontFamily">sans</item>
|
||||||
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:colorAccent">#006B5A</item>
|
||||||
|
<item name="android:navigationBarColor">#1A1C1E</item>
|
||||||
|
<item name="android:windowActionModeOverlay">true</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
Reference in New Issue
Block a user