feat: android webview app + APK build script + CI artifact
Android app (WebView wrapper): - Wraps the public household sharing URL in a native Android app - Swipe-to-refresh, error handling, back navigation, settings dialog - User enters their household's public URL on first launch - Material Design with toolbar, progress indicator Build tooling: - build-apk.sh: one-command APK build (auto-installs Java, SDK, Gradle) - .gitignore updated for Android build artifacts CI (.gitea/workflows/ci.yml): - New 'build-android' job (needs test-and-package) - Installs Android SDK + Java 17, builds debug APK - Uploads APK as 'meal-tracker-apk' artifact
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.mealtracker.app'
|
||||
compileSdk 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mealtracker.app"
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
versionNameSuffix "-debug"
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.11.0'
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in the SDK tools.
|
||||
|
||||
# WebView - keep JavaScript interface methods
|
||||
-keepclassmembers class * {
|
||||
@android.webkit.JavascriptInterface <methods>;
|
||||
}
|
||||
|
||||
# Keep material components
|
||||
-dontwarn com.google.android.material.**
|
||||
-keep class com.google.android.material.** { *; }
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MealTracker"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="34">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
|
||||
android:theme="@style/Theme.MealTracker">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.mealtracker.app;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final String PREFS_NAME = "mealtracker_prefs";
|
||||
private static final String KEY_PUBLIC_URL = "public_url";
|
||||
|
||||
private WebView webView;
|
||||
private SwipeRefreshLayout swipeRefresh;
|
||||
private ProgressBar progressBar;
|
||||
private TextView errorView;
|
||||
private String currentUrl;
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
webView = findViewById(R.id.webview);
|
||||
swipeRefresh = findViewById(R.id.swipe_refresh);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
errorView = findViewById(R.id.error_view);
|
||||
ImageButton btnSettings = findViewById(R.id.btn_settings);
|
||||
ImageButton btnRefresh = findViewById(R.id.btn_refresh);
|
||||
|
||||
setupWebView();
|
||||
|
||||
swipeRefresh.setOnRefreshListener(() -> webView.reload());
|
||||
btnRefresh.setOnClickListener(v -> webView.reload());
|
||||
btnSettings.setOnClickListener(v -> showSettingsDialog());
|
||||
|
||||
// Load saved URL or show setup
|
||||
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
|
||||
String savedUrl = prefs.getString(KEY_PUBLIC_URL, "");
|
||||
if (!savedUrl.isEmpty()) {
|
||||
loadUrl(savedUrl);
|
||||
} else {
|
||||
showSettingsDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private void setupWebView() {
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setDomStorageEnabled(true);
|
||||
settings.setUseWideViewPort(true);
|
||||
settings.setLoadWithOverviewMode(true);
|
||||
settings.setSupportZoom(true);
|
||||
settings.setBuiltInZoomControls(true);
|
||||
settings.setDisplayZoomControls(false);
|
||||
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
|
||||
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
errorView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
swipeRefresh.setRefreshing(false);
|
||||
currentUrl = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request,
|
||||
WebResourceError error) {
|
||||
if (request.isForMainFrame()) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
swipeRefresh.setRefreshing(false);
|
||||
if (!isNetworkAvailable()) {
|
||||
errorView.setText(R.string.error_no_network);
|
||||
} else {
|
||||
errorView.setText(R.string.error_load_failed);
|
||||
}
|
||||
errorView.setVisibility(View.VISIBLE);
|
||||
webView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
// Keep all navigation inside the WebView
|
||||
view.loadUrl(request.getUrl().toString());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
webView.setWebChromeClient(new WebChromeClient() {
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int newProgress) {
|
||||
if (newProgress == 100) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
swipeRefresh.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Retry on error tap
|
||||
errorView.setOnClickListener(v -> {
|
||||
if (currentUrl != null) {
|
||||
loadUrl(currentUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadUrl(String url) {
|
||||
currentUrl = url;
|
||||
errorView.setVisibility(View.GONE);
|
||||
webView.setVisibility(View.VISIBLE);
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
|
||||
private void showSettingsDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.settings_title);
|
||||
|
||||
View dialogView = getLayoutInflater().inflate(R.layout.dialog_settings, null);
|
||||
EditText urlInput = dialogView.findViewById(R.id.url_input);
|
||||
TextView hintView = dialogView.findViewById(R.id.url_hint);
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
|
||||
String savedUrl = prefs.getString(KEY_PUBLIC_URL, "");
|
||||
urlInput.setText(savedUrl);
|
||||
|
||||
hintView.setText(R.string.url_hint_text);
|
||||
|
||||
builder.setView(dialogView);
|
||||
builder.setPositiveButton(R.string.save, (dialog, which) -> {
|
||||
String url = urlInput.getText().toString().trim();
|
||||
if (!url.isEmpty()) {
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
url = "https://" + url;
|
||||
}
|
||||
prefs.edit().putString(KEY_PUBLIC_URL, url).apply();
|
||||
loadUrl(url);
|
||||
Toast.makeText(this, R.string.url_saved, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.url_empty, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, null);
|
||||
builder.setCancelable(false);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private boolean isNetworkAvailable() {
|
||||
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
return info != null && info.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#1565C0"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<!-- Background circle -->
|
||||
<path
|
||||
android:fillColor="#1565C0"
|
||||
android:pathData="M54,54m-40,0a40,40 0,1 1,80 0a40,40 0,1 1,-80 0"/>
|
||||
<!-- Fork & knife icon (simplified) -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M50,30 L50,50 C50,54 48,56 45,56 C42,56 40,54 40,50 L40,30 L38,30 L38,50 C38,54 36,56 33,56 C30,56 28,54 28,50 L28,30 C24,30 22,32 22,36 L22,52 C22,58 28,62 34,62 L34,78 L44,78 L44,62 C50,62 56,58 56,52 L56,36 C56,32 54,30 50,30 Z"/>
|
||||
<!-- Plate/meal circle -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M62,36m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||
android:strokeColor="#1565C0"
|
||||
android:strokeWidth="2"/>
|
||||
<!-- Inner dot -->
|
||||
<path
|
||||
android:fillColor="#1565C0"
|
||||
android:pathData="M62,36m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="@android:color/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="@android:color/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/swipe_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/app_name"
|
||||
app:titleTextColor="@android:color/white"
|
||||
android:background="@color/colorPrimary">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_refresh"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:src="@drawable/ic_refresh"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/refresh" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_settings"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/settings" />
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
android:indeterminateTint="@color/colorAccent" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:padding="32dp"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/url_label"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:paddingBottom="4dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/url_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textUri"
|
||||
android:hint="https://meals.example.com/public/..."
|
||||
android:padding="12dp"
|
||||
android:background="@android:drawable/edit_text"
|
||||
android:textSize="14sp"
|
||||
android:importantForAutofill="no" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/url_hint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:paddingTop="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#1565C0</color>
|
||||
<color name="colorPrimaryDark">#0D47A1</color>
|
||||
<color name="colorAccent">#1565C0</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Meal Tracker</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="settings_title">Public URL</string>
|
||||
<string name="url_label">Enter the public sharing URL for your household:</string>
|
||||
<string name="url_hint_text">Paste the link your household admin shared with you. It looks like:\nhttps://.../public/abc123...</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="url_saved">URL saved</string>
|
||||
<string name="url_empty">Please enter a URL</string>
|
||||
<string name="error_no_network">No network connection.\nTap to retry.</string>
|
||||
<string name="error_load_failed">Could not load the page.\nTap to retry.</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="Theme.MealTracker" parent="Theme.MaterialComponents.Light.DarkActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user