Compare commits

...

2 Commits

Author SHA1 Message Date
bdc1a6f44a
cs-3443: bring LakeWatch in-tree 2024-08-31 02:13:52 -05:00
09c66095ed
summer-2024: archive it 2024-08-31 02:13:09 -05:00
239 changed files with 52847 additions and 11 deletions

View File

@ -0,0 +1,69 @@
* Systems Programming Midterm Topics
1. Linux environment / shell commands
- Common commands
- Chmod/permissions
- Wildcards
- Input/output redirection
- Shell parsing steps
- Shell command resolution variables
- Shell vs environment and their inheritance
- Exit statuses
- Subshells / child shells
- Arithmetic (operators: expansion vs evaluation)
- Floating arithmetic in bash: how?
2. Bash Scripting
3. ~find~/~grep~
4. Regular expressions (BRE vs ERE)
5. ~sed~
NOTE: No AWK material will be covered on the exam
* Example Questions
1. Answer =True= or =False= for the following statements:
- [TRUE] The extended regular expression ~{0,1}~ is equivalent to the ~?~ quantifier?
- [FALSE] An exit status of ~0~ is used to indicate success.
- [FALSE] Given the string "abc123" the regex ~/[a-z]{1,3}/~ will produce a match of "a".
- [FALSE] The following loop will never execute:
#+begin_src bash
while [ 0 ]; do let i++; echo $i; done
#+end_src
- [TRUE] The following loop will never execute:
#+begin_src bash
while (( 0 )); do let i++; echo $i; done
#+end_src
- [TRUE] ~sed~ will emit the contents of the pattern space, including a trailing newline character, by default at the end of each input cycle.
- [FALSE] The following bash filename pattern will match all text files in the user's current directory:
#+begin_src bash
ls -la .*\.txt
#+end_src
- [TRUE] The ~source~ built-in executes the contents of a specified file within the current script (i.e. no subshell is utilized).
- [FALSE] ~grep~ uses extended regular expressions by default
2. Enter the octal number corresponding to the following Linux file permissions: ~rwxr-x---~
Answer: ~0750~
3. Write out the erroneous line numbers from the following script (hint there are six):
#+begin_src bash
data="./data"
org_data=/usr/local/courses/ssilvestro/cs3424/Spring21/assign1/
if [[ $# -eq 1 ]]; then
data = $1
else if [[ $# -eq 2 ]]; then
data = $1
orig_data = $2
fi
if [[! -d $data]]; then
echo "ERROR: data directory '$data' does not exist"
exit 1
fi
if [[ not -d $orig_data ]]; then
echo "ERROR: original data directory '$data' does not exist"
exit 1
fi
echo "rm -rf \"$data\"..."
rm -rf "$data"
echo "cp -r \"$org_data\" \"$data\"..."
cp -r "$orig_data" "$data"
#+end_src
Answer: ~4,5,6,7,9,13~

Binary file not shown.

View File

@ -0,0 +1,11 @@
export APP_API_HOST="localhost"
export APP_API_PORT="8000"
export APP_DATABASE_HOST="localhost"
export APP_DATABASE_PORT="5432"
export APP_DATABASE_USERNAME="postgres"
export APP_DATABASE_PASSWORD="password"
export APP_DATABASE_NAME="lakewatch"
export APP_DATABASE_REQUIRE_SSL="false"
export DATABASE_URL="postgres://${APP_DATABASE_USERNAME}:${APP_DATABASE_PASSWORD}@${APP_DATABASE_HOST}:${APP_DATABASE_PORT}/${APP_DATABASE_NAME}"

View File

@ -0,0 +1 @@
.idea/

View File

@ -0,0 +1,10 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

View File

@ -0,0 +1,3 @@
# `LakeWatch`
This repository contains the actual Android application.

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,43 @@
plugins {
alias(libs.plugins.android.application)
}
android {
namespace = "edu.utsa.cs3443.lakewatch"
compileSdk = 34
defaultConfig {
applicationId = "edu.utsa.cs3443.lakewatch"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
}

View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,26 @@
package edu.utsa.cs3443.lakewatch;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("edu.utsa.cs3443.lakewatch", appContext.getPackageName());
}
}

View File

@ -0,0 +1,43 @@
<?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" />
<application
android:name=".model.userSettings"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LakeWatch"
tools:targetApi="31">
<activity
android:name=".MainRampMenuActivity"
android:exported="false" />
<activity
android:name=".BoatRampActivity"
android:exported="false" />
<activity
android:name=".WaterLevelActivity"
android:exported="false" />
<activity
android:name=".WeatherActivity"
android:exported="false" />
<activity
android:name=".SettingsActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,111 @@
package edu.utsa.cs3443.lakewatch;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import edu.utsa.cs3443.lakewatch.model.BoatRampData;
import edu.utsa.cs3443.lakewatch.model.BoatRampStatus;
public class BoatRampActivity extends AppCompatActivity {
/**
* Drive the view for a single boat ramp page
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_boat_ramp);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
BoatRampData rampData = (BoatRampData) this.getIntent().getExtras().getSerializable("rampData");
((TextView)this.findViewById(R.id.rampName)).setText(rampData.getName());
ImageView rampImage = this.findViewById(R.id.rampImage);
for (Field field : R.drawable.class.getFields()) {
String fieldName = field.getName();
if (fieldName.equals("ramp" + rampData.getRampNumber())) {
rampImage.setImageResource(this.getResources().getIdentifier(field.getName(), "drawable", this.getPackageName()));
}
}
ImageView statusIcon = this.findViewById(R.id.statusIcon);
GradientDrawable statusShape = new GradientDrawable();
statusShape.setStroke(3, Color.parseColor("#000000"));
statusShape.setCornerRadius(8000);
if (rampData.getStatus() == BoatRampStatus.OPEN) {
statusIcon.setImageResource(R.drawable.circle_check);
statusShape.setColor(ContextCompat.getColor(this, R.color.rampStatusOpen));
} else if (rampData.getStatus() == BoatRampStatus.CLOSED) {
statusIcon.setImageResource(R.drawable.circle_x);
statusShape.setColor(ContextCompat.getColor(this, R.color.rampStatusClosed));
} else {
statusIcon.setImageResource(R.drawable.circle_guess);
statusShape.setColor(ContextCompat.getColor(this, R.color.rampStatusUnknown));
}
CardView statusCard = this.findViewById(R.id.statusCard);
statusCard.setBackground(statusShape);
((TextView)this.findViewById(R.id.statusText)).setText(rampData.getStatus().toString());
GradientDrawable cardShape = new GradientDrawable();
cardShape.setColor(ContextCompat.getColor(this, R.color.rampInfoBackground));
cardShape.setStroke(3, Color.parseColor("#000000"));
cardShape.setCornerRadius(8000);
CardView openTimesCard = this.findViewById(R.id.openTimes);
((TextView)openTimesCard.findViewById(R.id.openTimesText)).setText(rampData.getOpenTimes());
openTimesCard.setBackground(cardShape);
CardView addressCard = this.findViewById(R.id.address);
((TextView)addressCard.findViewById(R.id.addressText)).setText(rampData.getAddress());
addressCard.setBackground(cardShape);
addressCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("", rampData.getAddress());
clipboard.setPrimaryClip(clip);
Toast toast = Toast.makeText(view.getContext(), "Address copied to clipboard!", Toast.LENGTH_SHORT);
View toastView = toast.getView();
toastView.findViewById(android.R.id.message).setBackgroundColor(Color.TRANSPARENT);
toastView.getBackground().setTint(ContextCompat.getColor(toastView.getContext(), R.color.buttonBackgroundColor));
toast.show();
}
});
CardView operatorCard = this.findViewById(R.id.operator);
((TextView)operatorCard.findViewById(R.id.operatorText)).setText(rampData.getOperator());
operatorCard.setBackground(cardShape);
CardView lastUpdatedCard = this.findViewById(R.id.lastUpdated);
((TextView)lastUpdatedCard.findViewById(R.id.lastUpdatedText)).setText(DateTimeFormatter.ofPattern("MM/dd/yyyy").format(rampData.getLastUpdated()));
lastUpdatedCard.setBackground(cardShape);
}
}

View File

@ -0,0 +1,92 @@
package edu.utsa.cs3443.lakewatch;
import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
//Button Initialization(s)
Button weatherButton = findViewById(R.id.button); //Weather
Button waterStatusButton = findViewById(R.id.button2); //WaterStatus
Button rampsButton = findViewById(R.id.button3); //Ramps
Button settingsButton = findViewById(R.id.settingsButton); // Settings
//Weather View OnClickListener
weatherButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) { openWeatherActivity(); }
});
//Water Status View OnClickListener
waterStatusButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) { openWaterLevelActivity();}
});
//Boat Ramps View OnClickListener
rampsButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
openMainRampMenuActivity();
}
});
//Settings View OnClickListener
settingsButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
openSettingsActivity();
}
});
}
//This function is used to navigate to the settings menu via the intent object
private void openSettingsActivity()
{
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
}
private void openWeatherActivity()
{
Intent intent = new Intent(this, WeatherActivity.class);
startActivity(intent);
}
private void openWaterLevelActivity()
{
Intent intent = new Intent(this, WaterLevelActivity.class);
startActivity(intent);
}
private void openMainRampMenuActivity()
{
Intent intent = new Intent(this, MainRampMenuActivity.class);
startActivity(intent);
}
}

View File

@ -0,0 +1,166 @@
package edu.utsa.cs3443.lakewatch;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import edu.utsa.cs3443.lakewatch.model.BoatRampData;
import edu.utsa.cs3443.lakewatch.model.BoatRampStatus;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MainRampMenuActivity extends AppCompatActivity {
private ExecutorService executorService;
/**
* The main driver behind the full listing of the boat ramps
*
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main_ramp_menu);
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.main),
(v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
executorService = Executors.newSingleThreadExecutor();
Callable<ArrayList<BoatRampData>> fetchRampDataTask =
() -> {
ArrayList<BoatRampData> fetchedData = BoatRampData.fetchData();
BoatRampData.saveData(this.findViewById(R.id.main).getContext(), fetchedData);
return fetchedData;
};
Future<ArrayList<BoatRampData>> future = executorService.submit(fetchRampDataTask);
new Handler(Looper.getMainLooper())
.post(
() -> {
ArrayList<BoatRampData> allRampData = new ArrayList<>();
try {
allRampData = future.get();
} catch (Exception e) {
Toast toast =
Toast.makeText(
this.findViewById(R.id.main).getContext(),
"API Fetch Failed, failling back to cache.",
Toast.LENGTH_SHORT);
View toastView = toast.getView();
toastView.findViewById(android.R.id.message).setBackgroundColor(Color.TRANSPARENT);
toastView
.getBackground()
.setTint(
ContextCompat.getColor(
toastView.getContext(), R.color.buttonBackgroundColor));
toast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 50);
toast.show();
Toast cacheToast =
Toast.makeText(
this.findViewById(R.id.main).getContext(),
"Failed to load boat ramp data!",
Toast.LENGTH_SHORT);
View cacheToastView = cacheToast.getView();
cacheToastView
.findViewById(android.R.id.message)
.setBackgroundColor(Color.TRANSPARENT);
cacheToastView
.getBackground()
.setTint(
ContextCompat.getColor(
cacheToastView.getContext(), R.color.buttonBackgroundColor));
cacheToast.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 50);
try {
allRampData =
BoatRampData.loadCachedData(this.findViewById(R.id.main).getContext());
} catch (Exception ex) {
cacheToast.show();
}
}
LinearLayout rampListing = this.findViewById(R.id.rampListing);
int ramps_open = 0;
LayoutInflater inflater =
(LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (BoatRampData rampData : allRampData) {
if (rampData.getStatus() == BoatRampStatus.OPEN) {
ramps_open++;
}
View rampView = inflater.inflate(R.layout.ramp_menu_card, rampListing, false);
CardView rampMenuCard = rampView.findViewById(R.id.rampMenuCard);
((TextView) rampMenuCard.findViewById(R.id.rampName)).setText(rampData.getName());
((TextView) rampMenuCard.findViewById(R.id.rampStatus))
.setText(rampData.getStatus().toString());
ImageView statusImage = rampView.findViewById(R.id.statusIcon);
GradientDrawable shape = new GradientDrawable();
if (rampData.getStatus() == BoatRampStatus.OPEN) {
statusImage.setImageResource(R.drawable.circle_check);
shape.setColor(ContextCompat.getColor(this, R.color.rampStatusOpen));
} else if (rampData.getStatus() == BoatRampStatus.CLOSED) {
statusImage.setImageResource(R.drawable.circle_x);
shape.setColor(ContextCompat.getColor(this, R.color.rampStatusClosed));
} else {
statusImage.setImageResource(R.drawable.circle_guess);
shape.setColor(ContextCompat.getColor(this, R.color.rampStatusUnknown));
}
shape.setStroke(3, Color.parseColor("#000000"));
shape.setCornerRadius(80);
rampMenuCard.setBackground(shape);
rampMenuCard.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
launchBoatRampActivity(rampData);
}
});
rampListing.addView(rampView);
}
((TextView) this.findViewById(R.id.rampsOpen))
.setText(String.format("%d/%d Ramps Open", ramps_open, allRampData.size()));
});
}
/**
* Launch a specific page of a boat ramp
*
* @param rampData The ramp data to use for the page
*/
private void launchBoatRampActivity(BoatRampData rampData) {
Intent intent = new Intent(this, BoatRampActivity.class);
intent.putExtra("rampData", (Serializable) rampData);
startActivity(intent);
}
}

View File

@ -0,0 +1,167 @@
package edu.utsa.cs3443.lakewatch;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import edu.utsa.cs3443.lakewatch.model.BoatRampData;
import edu.utsa.cs3443.lakewatch.model.WaterLevelData;
import edu.utsa.cs3443.lakewatch.model.WeatherData;
public class SettingsActivity extends AppCompatActivity {
private ExecutorService executorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_settings);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
//Button Initializations
Button btnToggleDark = findViewById(R.id.button5);
Button dataFetchButton = findViewById(R.id.button6);
Button clearCacheButton = findViewById(R.id.button7);
//Saving state of our app
//using SharedPreferences
//necessary for Dark Mode
SharedPreferences sharedPreferences = getSharedPreferences("sharedPrefs",MODE_PRIVATE);
final SharedPreferences.Editor editor = sharedPreferences.edit();
final boolean isDarkModeOn = sharedPreferences.getBoolean("isDarkModeOn",false);
// When user reopens the app
// after applying a respective
// color mode
if(isDarkModeOn)
{
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
btnToggleDark.setText("DARK MODE ON");
}
else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
btnToggleDark.setText("DARK MODE OFF");
}
//Dark Mode OnClickListener
//contains the logic to toggle
//Dark mode
btnToggleDark.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
// When user taps the enable/disable
// dark mode button
if (isDarkModeOn) {
// if dark mode is on
// it will turn off dark mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
// sets isDarkModeOn
// boolean to false
editor.putBoolean("isDarkModeOn", false);
editor.apply();
}
else {
// if dark mode is off
// it will turn on dark mode
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
// sets isDarkModeOn
// boolean to true
editor.putBoolean("isDarkModeOn", true);
editor.apply();
}
}
});
dataFetchButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast toast = Toast.makeText(view.getContext(), "Data Fetched.", Toast.LENGTH_SHORT);
View toastView = toast.getView();
toastView.findViewById(android.R.id.message).setBackgroundColor(Color.TRANSPARENT);
toastView.getBackground().setTint(ContextCompat.getColor(toastView.getContext(), R.color.buttonBackgroundColor));
toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM,0,50);
executorService = Executors.newSingleThreadExecutor();
Callable<ArrayList<BoatRampData>> fetchRampDataTask =
() -> {
ArrayList<BoatRampData> fetchedData = BoatRampData.fetchData();
BoatRampData.saveData(view.getContext(), fetchedData);
return fetchedData;
};
Future<ArrayList<BoatRampData>> future = executorService.submit(fetchRampDataTask);
new Handler(Looper.getMainLooper()).post(() -> {
try {
BoatRampData.saveData(view.getContext(), future.get());
} catch (Exception e) {
toast.setText("Failed to force a data fetch!");
}
});
// Fetch Water Level Data
toast.show();
WaterLevelData.forceDataFetch(getApplicationContext());
}
});
clearCacheButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast toast = Toast.makeText(view.getContext(), "Cache Cleared.", Toast.LENGTH_SHORT);
View toastView = toast.getView();
toastView.findViewById(android.R.id.message).setBackgroundColor(Color.TRANSPARENT);
toastView.getBackground().setTint(ContextCompat.getColor(toastView.getContext(), R.color.buttonBackgroundColor));
toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM,0,50);
try {
BoatRampData.wipeCache(view.getContext());
} catch (IOException e) {
toast.setText("Failed to wipe ramp data cache!");
}
toast.show();
try {
WeatherData.wipeCache(view.getContext());
} catch (IOException e) {
toast.setText("Failed to wipe weather data cache!");
}
toast.show();
WaterLevelData.clearCache(getApplicationContext());
}
});
}
}

View File

@ -0,0 +1,117 @@
package edu.utsa.cs3443.lakewatch;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import edu.utsa.cs3443.lakewatch.model.WaterLevelData;
public class WaterLevelActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_water);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
new FetchWaterLevelDataTask().execute();
}
private class FetchWaterLevelDataTask extends AsyncTask<Void, Void, WaterLevelData> {
@Override
protected WaterLevelData doInBackground(Void... voids) {
WaterLevelData data = null;
try {
String jsonResponse = WaterLevelData.getJsonResponseFromApi();
data = WaterLevelData._loadWaterLevelData(jsonResponse);
if (data != null) {
data.saveWaterLevelData(WaterLevelActivity.this);
}
} catch (Exception e) {
e.printStackTrace();
}
if (data == null) {
data = WaterLevelData.loadSavedWaterLevelData(WaterLevelActivity.this);
}
return data;
}
@Override
protected void onPostExecute(WaterLevelData currentData) {
updateUI(currentData);
}
}
private void updateUI(WaterLevelData currentData) {
TableLayout tableLayout = findViewById(R.id.tableLayout);
TableRow row1 = (TableRow) tableLayout.getChildAt(0);
TextView row1Column2 = (TextView) row1.getChildAt(1);
if (currentData != null) {
row1Column2.setText(String.format("%.2f%%", currentData.getPercentFull()));
TableRow row2 = (TableRow) tableLayout.getChildAt(1);
TextView row2Column2 = (TextView) row2.getChildAt(1);
row2Column2.setText(String.format("%.2f", currentData.getWaterLevel()));
TableRow row3 = (TableRow) tableLayout.getChildAt(2);
TextView row3Column2 = (TextView) row3.getChildAt(1);
row3Column2.setText(String.format("%.2f", currentData.getSurfaceArea()));
TextView waterLevelValue = findViewById(R.id.waterLevelValue);
TextView dateTime = findViewById(R.id.dateTime);
TextView levelStatus = findViewById(R.id.levelStatus);
waterLevelValue.setText(String.format("%.2f", currentData.getWaterLevel()));
dateTime.setText(currentData.getDate());
levelStatus.setText(String.format("Level is %.2f feet below full pool of 909.00 ft", 909.00 - currentData.getWaterLevel()));
} else {
TextView waterLevelValue = findViewById(R.id.waterLevelValue);
TextView dateTime = findViewById(R.id.dateTime);
TextView levelStatus = findViewById(R.id.levelStatus);
waterLevelValue.setText("0.0");
dateTime.setText("N/A");
levelStatus.setText("No data available");
row1 = (TableRow) tableLayout.getChildAt(0);
row1Column2 = (TextView) row1.getChildAt(1);
row1Column2.setText("0.0%");
TableRow row2 = (TableRow) tableLayout.getChildAt(1);
TextView row2Column2 = (TextView) row2.getChildAt(1);
row2Column2.setText("0.0");
TableRow row3 = (TableRow) tableLayout.getChildAt(2);
TextView row3Column2 = (TextView) row3.getChildAt(1);
row3Column2.setText("0.0");
}
}
}

View File

@ -0,0 +1,131 @@
package edu.utsa.cs3443.lakewatch;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import edu.utsa.cs3443.lakewatch.model.WeatherData;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class WeatherActivity extends AppCompatActivity {
private TextView weatherDescription;
private TextView temperature;
private TextView windDirection;
private TextView windSpeed;
private TextView windGust;
private TextView chancePrecipitation;
private TextView amountPrecipitation;
private ExecutorService executorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_weather);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
weatherDescription = findViewById(R.id.weather_description);
temperature = findViewById(R.id.temperature);
windDirection = findViewById(R.id.wind_direction);
windSpeed = findViewById(R.id.wind_speed);
windGust = findViewById(R.id.wind_gust);
chancePrecipitation = findViewById(R.id.chance_precipitation);
amountPrecipitation = findViewById(R.id.amount_precipitation);
// Initialize the ExecutorService
executorService = Executors.newSingleThreadExecutor();
// Fetch weather data using ExecutorService
fetchWeatherData();
Button weatherButton = findViewById(R.id.weather_button);
weatherButton.setOnClickListener(v -> {
String url = "https://forecast.weather.gov/MapClick.php?lat=29.699301&lon=-98.115109";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
});
}
// Fetch weather data and update UI
private void fetchWeatherData() {
Callable<WeatherData> fetchWeatherTask = () -> {
try {
WeatherData weatherData = new WeatherData();
WeatherData result = weatherData.loadWeatherData();
Log.d("WeatherActivity", "WeatherData loaded: " + result);
return result;
} catch (IOException e) {
e.printStackTrace();
return null;
}
};
Future<WeatherData> future = executorService.submit(fetchWeatherTask);
// Update the UI on the main thread
new Handler(Looper.getMainLooper()).post(() -> {
try {
WeatherData weatherData = future.get();
if (weatherData != null) {
weatherData.saveWeatherData(WeatherActivity.this);
updateUIWithWeatherData(weatherData);
} else {
weatherData = WeatherData.loadSavedWeatherData(WeatherActivity.this);
if (weatherData != null) {
updateUIWithWeatherData(weatherData);
} else {
weatherDescription.setText("No saved weather data available");
}
}
} catch (Exception e) {
e.printStackTrace();
weatherDescription.setText("Error fetching weather data");
}
});
}
private void updateUIWithWeatherData(WeatherData weatherData) {
weatherDescription.setText(weatherData.getWeatherDescription());
temperature.setText(String.format("H:%d°F L:%d°F", weatherData.getTempHigh(), weatherData.getTempLow()));
String windDirectionValue = weatherData.getWindDirection();
if (windDirectionValue.isEmpty()) {
windDirectionValue = "N/A";
}
windDirection.setText(String.format("%s", windDirectionValue));
windSpeed.setText(weatherData.getWindSpeed());
windGust.setText(String.format("%.0f mph", weatherData.getWindGust()));
chancePrecipitation.setText(String.format("%d%% Chance Precipitation", weatherData.getChancePrecipitation()));
amountPrecipitation.setText(String.format("%.1f\u2033 Precipitation Next 24 HR", weatherData.getAmountPrecipitation()));
}
@Override
protected void onDestroy() {
super.onDestroy();
// Shut down the ExecutorService when the activity is destroyed
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
}
}
}

View File

@ -0,0 +1,318 @@
package edu.utsa.cs3443.lakewatch.model;
import android.content.Context;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Model class containing logic and data for all boat ramps
*
*/
public class BoatRampData implements Serializable {
private Integer rampNumber;
private String name;
private BoatRampStatus status;
private String openTimes;
private String address;
private String operator;
private LocalDate lastUpdated;
private static final String CACHE_FILE_NAME = "BoatRampData.json";
/**
* Create a single boat ramp instance
*
* @param rampNumber The official ramp number
* @param name The more commonly known name of the ramp
* @param status The open/closed/unknown status of the ramp
* @param openTimes The times the ramp can be used if its status is "open"
* @param address The approximate address of the ramp
* @param operator The owner of the ramp, like Comal County
* @param lastUpdated The last time the given data was updated
*/
public BoatRampData(
Integer rampNumber,
String name,
BoatRampStatus status,
String openTimes,
String address,
String operator,
LocalDate lastUpdated) {
this.setRampNumber(rampNumber);
this.setName(name);
this.setStatus(status);
this.setOpenTimes(openTimes);
this.setAddress(address);
this.setOperator(operator);
this.setLastUpdated(lastUpdated);
}
/**
* Get the common name of the ramp
*
* @return name of the ramp
*/
public String getName() {
return name;
}
/**
* Set the common name of the ramp
*
* @param name common name of the ramp
*/
public void setName(String name) {
this.name = name;
}
/**
* Get the open/closed/unknown status of the ramp
*
* @return status of the ramp
*/
public BoatRampStatus getStatus() {
return status;
}
/**
* Set the open/closed/unknown status of the ramp
*
* @param status new status for the ramp
*/
public void setStatus(BoatRampStatus status) {
this.status = status;
}
/**
* Get the operating times of the ramp
*
* @return operating times of the ramp
*/
public String getOpenTimes() {
return openTimes;
}
/**
* Set the operating times of the ramp
*
* @param openTimes new operating times for the ramp
*/
public void setOpenTimes(String openTimes) {
this.openTimes = openTimes;
}
/**
* Get the approximate address of the ramp
*
* @return address of the ramp
*/
public String getAddress() {
return address;
}
/**
* Set the address of the ramp
*
* @param address new address for the ramp
*/
public void setAddress(String address) {
this.address = address;
}
/**
* Get the operator of the ramp
*
* @return operator of the ramp
*/
public String getOperator() {
return operator;
}
/**
* Set the operator of the ramp
*
* @param operator new operator for the ramp
*/
public void setOperator(String operator) {
this.operator = operator;
}
/**
* Get the last time the given data set was updated
*
* @return last updated time for the ramp data
*/
public LocalDate getLastUpdated() {
return lastUpdated;
}
/**
* Update the last updated time for the ramp
*
* @param lastUpdated new update time for the ramp's data
*/
public void setLastUpdated(LocalDate lastUpdated) {
this.lastUpdated = lastUpdated;
}
/**
* Create a full listing of all the ramp's data from a JSON Array
*
* @param in The json stream to parse
* @return A full listing of boat ramp data
* @throws IOException when readers cannot be created
* @throws JSONException when the input stream contains invalid json
*/
private static ArrayList<BoatRampData> fromJsonStream(InputStream in)
throws IOException, JSONException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
reader.close();
ArrayList<BoatRampData> rampData = new ArrayList<>();
JSONArray json = new JSONArray(out.toString());
for (int i = 0; i < json.length(); i++) {
JSONObject rampJson = json.getJSONObject(i);
rampData.add(BoatRampData.fromJson(rampJson));
}
rampData.sort(Comparator.comparing(BoatRampData::getStatus));
return rampData;
}
/**
* Fetch the latest ramp data from the API
*
* @return An updated full listing of all boat ramp data
* @throws Exception When the request fails in any shape way or form
*/
public static ArrayList<BoatRampData> fetchData() throws Exception {
HttpURLConnection conn =
(HttpURLConnection)
new URL("https://lakewatch.orion-technologies.io/v1/ramps").openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
return BoatRampData.fromJsonStream(conn.getInputStream());
}
/**
* Load's the data from a cached file on disk if it exists
*
* @param context a given android context, used to lookup common paths
* @return The last cached full listing of all boat ramp data
* @throws IOException If the cache file cannot be read or doesn't exist
* @throws JSONException If the data contained within the file is invalid
*/
public static ArrayList<BoatRampData> loadCachedData(Context context)
throws IOException, JSONException {
File file = new File(context.getCacheDir(), BoatRampData.CACHE_FILE_NAME);
return BoatRampData.fromJsonStream(Files.newInputStream(file.toPath()));
}
/**
* Wipe the cache file on disk
*
* @param context the android context used to look up the cache directory
* @throws IOException If the file cannot be deleted and it exists
*/
public static void wipeCache(Context context) throws IOException {
File file = new File(context.getCacheDir(), BoatRampData.CACHE_FILE_NAME);
if (file.exists()) {
file.delete();
}
}
/**
* Serialize a ramp's data into JSON for export
*
* @return The json representation of the ramp
* @throws JSONException If it's not possible to parse the ramp data into JSON
*/
public JSONObject toJson() throws JSONException {
JSONObject json = new JSONObject();
json.put("number", this.getRampNumber());
json.put("name", this.getName());
json.put("address", this.getAddress());
json.put("operator", this.getOperator());
json.put("status", this.getStatus().toString());
json.put(
"last_updated", this.getLastUpdated().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
json.put("operating_times", this.getOpenTimes());
return json;
}
/**
* Deserialize a given ramp's data from JSON
*
* @param json The json object to deserialize
* @return A single boat ramp's data
* @throws JSONException If the data contains invalid json
*/
public static BoatRampData fromJson(JSONObject json) throws JSONException {
Integer rampNumber = json.getInt("number");
String name = json.getString("name");
String address = json.getString("address");
String operator = json.getString("operator");
BoatRampStatus status = BoatRampStatus.fromString(json.getString("status"));
LocalDate lastUpdated = LocalDate.parse(json.getString("last_updated"));
String openTimes = json.getString("operating_times");
return new BoatRampData(rampNumber, name, status, openTimes, address, operator, lastUpdated);
}
/**
* Save a full listing of ramp data to a cache file on disk
*
* @param context Used to get android paths on the file system
* @param rampData The full listing of ramp data to save
* @throws IOException If the cache file cannot be written to
* @throws JSONException If the ramp data cannot be serialized into JSON
*/
public static void saveData(Context context, ArrayList<BoatRampData> rampData)
throws IOException, JSONException {
File file = new File(context.getCacheDir(), BoatRampData.CACHE_FILE_NAME);
BufferedWriter bw = new BufferedWriter(new FileWriter(file.getAbsoluteFile()));
JSONArray jsonData = new JSONArray();
for (BoatRampData ramp : rampData) {
jsonData.put(ramp.toJson());
}
bw.write(jsonData.toString());
bw.close();
}
/**
* Get the number of the ramp
*
* @return number of the ramp
*/
public Integer getRampNumber() {
return rampNumber;
}
/**
* Set a new number for the ramp
*
* @param rampNumber new number for the ramp
*/
public void setRampNumber(Integer rampNumber) {
this.rampNumber = rampNumber;
}
}

View File

@ -0,0 +1,39 @@
package edu.utsa.cs3443.lakewatch.model;
import java.io.Serializable;
public enum BoatRampStatus implements Serializable {
OPEN,
CLOSED,
UNKNOWN;
/**
* Get the string representation of the current Enum
*/
public String toString() {
switch (this) {
case OPEN:
return "Open";
case CLOSED:
return "Closed";
default:
return "Unknown";
}
}
/**
* Get a boat ramp status from a String
*
* @param status The string to convert to a status enum
*/
public static BoatRampStatus fromString(String status) {
switch (status.toLowerCase()) {
case "open":
return BoatRampStatus.OPEN;
case "closed":
return BoatRampStatus.CLOSED;
default:
return BoatRampStatus.UNKNOWN;
}
}
}

View File

@ -0,0 +1,324 @@
package edu.utsa.cs3443.lakewatch.model;
import android.content.Context;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class WaterLevelData {
private Date date;
private double waterLevel;
private double surfaceArea;
private int reservoirStorage;
private int conservationStorage;
private double percentFull;
private int conservationCapacity;
private int deadPoolCapacity;
private boolean isCurrent;
public WaterLevelData(Date date, double waterLevel, boolean isCurrent) {
this.date = date;
this.waterLevel = waterLevel;
this.isCurrent = isCurrent;
this.surfaceArea = 0.0;
this.reservoirStorage = 0;
this.conservationStorage = 0;
this.percentFull = 0.0;
this.conservationCapacity = 0;
this.deadPoolCapacity = 0;
}
// Getters and Setters
public String getDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
}
public void setDate(Date date) {
this.date = date;
}
public double getWaterLevel() {
return waterLevel;
}
public void setWaterLevel(double waterLevel) {
this.waterLevel = waterLevel;
}
public double getSurfaceArea() {
return surfaceArea;
}
public void setSurfaceArea(double surfaceArea) {
this.surfaceArea = surfaceArea;
}
public int getReservoirStorage() {
return reservoirStorage;
}
public void setReservoirStorage(int reservoirStorage) {
this.reservoirStorage = reservoirStorage;
}
public int getConservationStorage() {
return conservationStorage;
}
public void setConservationStorage(int conservationStorage) {
this.conservationStorage = conservationStorage;
}
public double getPercentFull() {
return percentFull;
}
public void setPercentFull(double percentFull) {
this.percentFull = percentFull;
}
public int getConservationCapacity() {
return conservationCapacity;
}
public void setConservationCapacity(int conservationCapacity) {
this.conservationCapacity = conservationCapacity;
}
public int getDeadPoolCapacity() {
return deadPoolCapacity;
}
public void setDeadPoolCapacity(int deadPoolCapacity) {
this.deadPoolCapacity = deadPoolCapacity;
}
public boolean isCurrent() {
return isCurrent;
}
public void setCurrent(boolean isCurrent) {
this.isCurrent = isCurrent;
}
@Override
public String toString() {
return "WaterLevelData{" +
"date=" + date +
", waterLevel=" + waterLevel +
", surfaceArea=" + surfaceArea +
", reservoirStorage=" + reservoirStorage +
", conservationStorage=" + conservationStorage +
", percentFull=" + percentFull +
", conservationCapacity=" + conservationCapacity +
", deadPoolCapacity=" + deadPoolCapacity +
", isCurrent=" + isCurrent +
'}';
}
public static String getJsonResponseFromApi() {
String urlString = "https://lakewatch.orion-technologies.io/v1/waterdata?start=1900-01-01&end=3000-01-01"; //API URL
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String jsonResponse = null;
try {
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuilder buffer = new StringBuilder();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line).append("\n");
}
if (buffer.length() == 0) {
return null;
}
jsonResponse = buffer.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
}
return jsonResponse;
}
public static WaterLevelData _loadWaterLevelData(String jsonResponse) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
try {
JSONArray jsonArray = new JSONArray(jsonResponse);
if (jsonArray.length() > 0) {
JSONObject jsonObject = jsonArray.getJSONObject(jsonArray.length() - 1); // Get the last entry
Date date;
try {
date = sdf.parse(jsonObject.getString("date"));
} catch (ParseException e) {
e.printStackTrace();
date = new Date(); // Default to current date if parsing fails
}
double waterLevel = jsonObject.optDouble("water_level", 0.0);
WaterLevelData data = new WaterLevelData(date, waterLevel, true);
data.setSurfaceArea(jsonObject.optDouble("surface_area", 0.0));
data.setReservoirStorage(jsonObject.optInt("reservoir_storage", 0));
data.setConservationStorage(jsonObject.optInt("conservation_storage", 0));
data.setPercentFull(jsonObject.optDouble("percent_full", 0.0));
data.setConservationCapacity(jsonObject.optInt("conservation_capacity", 0));
data.setDeadPoolCapacity(jsonObject.optInt("dead_pool_capacity", 0));
return data;
}
} catch (Exception e) {
e.printStackTrace();
}
return null; // Return null if no data is available
}
// Save the data to a JSON file
public void saveWaterLevelData(Context context) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("date", sdf.format(date));
jsonObject.put("water_level", waterLevel);
jsonObject.put("surface_area", surfaceArea);
jsonObject.put("reservoir_storage", reservoirStorage);
jsonObject.put("conservation_storage", conservationStorage);
jsonObject.put("percent_full", percentFull);
jsonObject.put("conservation_capacity", conservationCapacity);
jsonObject.put("dead_pool_capacity", deadPoolCapacity);
File file = new File(context.getFilesDir(), "water_level_data.json");
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(jsonObject.toString());
bufferedWriter.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("WaterLevelData", "Failed to save data", e);
}
}
// Load the data from a JSON file
public static WaterLevelData loadSavedWaterLevelData(Context context) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
File file = new File(context.getFilesDir(), "water_level_data.json");
if (!file.exists()) {
return null;
}
try {
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
StringBuilder jsonBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
jsonBuilder.append(line);
}
bufferedReader.close();
JSONObject jsonObject = new JSONObject(jsonBuilder.toString());
Date date;
try {
date = sdf.parse(jsonObject.getString("date"));
} catch (ParseException e) {
e.printStackTrace();
date = new Date(); // Default to current date if parsing fails
}
double waterLevel = jsonObject.optDouble("water_level", 0.0);
WaterLevelData data = new WaterLevelData(date, waterLevel, true);
data.setSurfaceArea(jsonObject.optDouble("surface_area", 0.0));
data.setReservoirStorage(jsonObject.optInt("reservoir_storage", 0));
data.setConservationStorage(jsonObject.optInt("conservation_storage", 0));
data.setPercentFull(jsonObject.optDouble("percent_full", 0.0));
data.setConservationCapacity(jsonObject.optInt("conservation_capacity", 0));
data.setDeadPoolCapacity(jsonObject.optInt("dead_pool_capacity", 0));
return data;
} catch (Exception e) {
e.printStackTrace();
Log.e("WaterLevelData", "Failed to load data", e);
}
return null; // Return null if loading fails
}
// Clear cached data
public static void clearCache(Context context) {
File file = new File(context.getFilesDir(), "water_level_data.json");
if (file.exists()) {
file.delete();
}
}
// Force data fetch
public static void forceDataFetch(Context context) {
new Thread(() -> {
String jsonResponse = getJsonResponseFromApi();
if (jsonResponse != null) {
WaterLevelData data = _loadWaterLevelData(jsonResponse);
if (data != null) {
data.saveWaterLevelData(context);
}
}
}).start();
}
}

View File

@ -0,0 +1,382 @@
package edu.utsa.cs3443.lakewatch.model;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
/**
* Represents the weather data for a specified location. This class holds various weather attributes
* such as temperature, wind speed, wind direction, and precipitation amounts.
* It provides methods to load weather data from a remote API and populate its fields accordingly.
*
* The weather data includes:
* - Weather description
* - High and low temperatures
* - Wind speed and gust
* - Wind direction
* - Chance of precipitation
* - Amount of precipitation
*
* @author Ethan Grams - bib016
*/
public class WeatherData {
private String weatherDescription;
private int tempHigh;
private int tempLow;
private String windSpeed;
private double windGust;
private String windDirection;
private int chancePrecipitation;
private double amountPrecipitation;
private static final String CACHE_FILE_NAME = "weather_data.json";
// Constructor with all fields
public WeatherData(String weatherDescription, int tempHigh, int tempLow, String windSpeed, double windGust, String windDirection, int chancePrecipitation, double amountPrecipitation) {
this.weatherDescription = weatherDescription;
this.tempHigh = tempHigh;
this.tempLow = tempLow;
this.windSpeed = windSpeed;
this.windGust = windGust;
this.windDirection = windDirection;
this.chancePrecipitation = chancePrecipitation;
this.amountPrecipitation = amountPrecipitation;
}
// Default Constructor
public WeatherData() {}
/**
* Loads weather data from the weather.gov API and creates a WeatherData object.
* This method fetches both hourly and general weather data for a specified weather station,
* populating the fields of the WeatherData object with the retrieved information.
*
* @return a WeatherData object populated with the fetched weather data
* @throws IOException if there is an error during the network connection or data retrieval
*/
public WeatherData loadWeatherData() throws IOException {
WeatherData weatherData = new WeatherData();
String hourlyUrl = "https://api.weather.gov/gridpoints/EWX/136,74/forecast/hourly";
String generalUrl = "https://api.weather.gov/gridpoints/EWX/136,74";
// Fetch hourly weather data
fetchHourlyWeatherData(hourlyUrl, weatherData);
// Fetch general weather data
fetchGeneralWeatherData(generalUrl, weatherData);
return weatherData;
}
/**
* Fetches and processes hourly weather data for a specified weather station.
* Establishes a connection to the given URL, retrieves the weather data in JSON format,
* and extracts the necessary values to populate the provided WeatherData object.
* Handles weather description, wind speed and direction, and chance of precipitation.
*
* @param url the URL to fetch weather data from
* @param weatherData the WeatherData object to populate with the fetched data
* @throws IOException if there is an error during the network connection or data retrieval
*/
private void fetchHourlyWeatherData(String url, WeatherData weatherData) throws IOException {
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
try {
setupConnection(urlConnection);
int responseCode = urlConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String response = readStream(urlConnection.getInputStream());
JSONObject jsonResponse = new JSONObject(response);
JSONArray periods = jsonResponse.getJSONObject("properties").getJSONArray("periods");
JSONObject firstPeriod = periods.getJSONObject(0);
weatherData.setWeatherDescription(firstPeriod.getString("shortForecast"));
weatherData.setWindSpeed(firstPeriod.getString("windSpeed"));
weatherData.setWindDirection(firstPeriod.getString("windDirection"));
weatherData.setChancePrecipitation(firstPeriod.getJSONObject("probabilityOfPrecipitation").optInt("value", 0));
} else {
throw new IOException("HTTP error code: " + responseCode);
}
} catch (JSONException e) {
throw new RuntimeException(e);
} finally {
urlConnection.disconnect();
}
}
/**
* Fetches and processes general weather data for a specified weather station.
* Establishes a connection to the given URL, retrieves the weather data in JSON format,
* and extracts the necessary values to populate the provided WeatherData object.
* Handles high and low temperatures, wind gusts, and precipitation amounts,
* converting units as necessary.
*
* @param url the URL to fetch weather data from
* @param weatherData the WeatherData object to populate with the fetched data
* @throws IOException if there is an error during the network connection or data retrieval
*/
private void fetchGeneralWeatherData(String url, WeatherData weatherData) throws IOException {
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
try {
setupConnection(urlConnection);
int responseCode = urlConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
String response = readStream(urlConnection.getInputStream());
JSONObject jsonResponse = new JSONObject(response);
JSONObject properties = jsonResponse.getJSONObject("properties");
weatherData.setTempHigh(convertToFahrenheit(getMaxTemp(properties.getJSONObject("maxTemperature").getJSONArray("values"))));
weatherData.setTempLow(convertToFahrenheit(getMinTemp(properties.getJSONObject("minTemperature").getJSONArray("values"))));
weatherData.setWindGust(convertKmhToMph(properties.getJSONObject("windGust").getJSONArray("values").getJSONObject(0).optInt("value")));
weatherData.setAmountPrecipitation(convertMmToInches(sumPrecipitation(properties.getJSONObject("quantitativePrecipitation").getJSONArray("values"), 4)));
} else {
throw new IOException("HTTP error code: " + responseCode);
}
} catch (JSONException e) {
throw new RuntimeException(e);
} finally {
urlConnection.disconnect();
}
}
/**
* Configures the given HttpURLConnection with the necessary request properties.
* Sets the request method to GET, and specifies that the response should be in JSON format.
* Also sets the User-Agent to mimic a modern web browser.
*
* @param connection the HttpURLConnection to be configured
* @throws ProtocolException if there is an error in the underlying protocol
*/
private void setupConnection(HttpURLConnection connection) throws ProtocolException {
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
}
// Reads in data and returns it in one String
private String readStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
reader.close();
return out.toString();
}
// Takes two high temperatures within a 24 hour period and returns the maximum
private int getMaxTemp(JSONArray values) throws JSONException {
return Math.max(values.getJSONObject(0).optInt("value", 0), values.getJSONObject(1).optInt("value", 0));
}
// Returns the current low temperature
private int getMinTemp(JSONArray values) throws JSONException {
return values.getJSONObject(0).optInt("value", 0);
}
// Sums precipitation over a 24 hour period
private double sumPrecipitation(JSONArray values, int count) throws JSONException {
double sum = 0.0;
for (int i = 0; i < count; i++) {
sum += values.getJSONObject(i).optInt("value", 0);
}
return sum;
}
// Converts Celsius to Fahrenheit
private int convertToFahrenheit(int celsius) {
return (int) (celsius * (9.0 / 5.0)) + 32;
}
// Converts Kilometers Per Hour to Miles Per Hour
private double convertKmhToMph(double kmh) {
return kmh * 0.621371;
}
// Converts millimeters to inches
private double convertMmToInches(double mm) {
return mm * 0.0393701;
}
// Save the data to a JSON file
public void saveWeatherData(Context context) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("weather_description", weatherDescription);
jsonObject.put("temp_high", tempHigh);
jsonObject.put("temp_low", tempLow);
jsonObject.put("wind_speed", windSpeed);
jsonObject.put("wind_gust", windGust);
jsonObject.put("wind_direction", windDirection);
jsonObject.put("chance_precipitation", chancePrecipitation);
jsonObject.put("amount_precipitation", amountPrecipitation);
File file = new File(context.getFilesDir(), "weather_data.json");
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(jsonObject.toString());
bufferedWriter.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("WaterLevelData", "Failed to save data", e);
}
}
// Load the data from a JSON file
public static WeatherData loadSavedWeatherData(Context context) {
File file = new File(context.getFilesDir(), "weather_data.json");
if (!file.exists()) {
return null;
}
try {
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
StringBuilder jsonBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
jsonBuilder.append(line);
}
bufferedReader.close();
JSONObject jsonObject = new JSONObject(jsonBuilder.toString());
double waterLevel = jsonObject.optDouble("water_level", 0.0);
WeatherData weatherData = new WeatherData();
weatherData.setWeatherDescription(jsonObject.optString("weather_description", ""));
weatherData.setTempHigh(jsonObject.optInt("temp_high", 0));
weatherData.setTempLow(jsonObject.optInt("temp_low", 0));
weatherData.setWindSpeed(jsonObject.optString("wind_speed", ""));
weatherData.setWindGust(jsonObject.optDouble("wind_gust", 0.0));
weatherData.setWindDirection(jsonObject.optString("wind_direction", ""));
weatherData.setChancePrecipitation(jsonObject.optInt("chance_precipitation", 0));
weatherData.setAmountPrecipitation(jsonObject.optDouble("amount_precipitation", 0.0));
return weatherData;
} catch (Exception e) {
e.printStackTrace();
Log.e("WeatherData", "Failed to load data", e);
}
return null; // Return null if loading fails
}
/**
* Wipe the cache file on disk
*
* @param context the android context used to look up the cache directory
* @throws IOException If the file cannot be deleted and it exists
*/
public static void wipeCache(Context context) throws IOException {
File file = new File(context.getCacheDir(), WeatherData.CACHE_FILE_NAME);
if (file.exists()) {
file.delete();
}
}
@NonNull
@Override
public String toString() {
return "WeatherData{" +
"weatherDescription='" + weatherDescription + '\'' +
", tempHigh=" + tempHigh +
", tempLow=" + tempLow +
", windSpeed='" + windSpeed + '\'' +
", windGust=" + windGust +
", windDirection='" + windDirection + '\'' +
", chancePrecipitation=" + chancePrecipitation +
", amountPrecipitation=" + amountPrecipitation +
'}';
}
// Getters and Setters
public String getWeatherDescription() {
return weatherDescription;
}
public void setWeatherDescription(String weatherDescription) {
this.weatherDescription = weatherDescription;
}
public int getTempHigh() {
return tempHigh;
}
public void setTempHigh(int tempHigh) {
this.tempHigh = tempHigh;
}
public int getTempLow() {
return tempLow;
}
public void setTempLow(int tempLow) {
this.tempLow = tempLow;
}
public String getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(String windSpeed) {
this.windSpeed = windSpeed;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public String getWindDirection() {
return windDirection;
}
public void setWindDirection(String windDirection) {
this.windDirection = windDirection;
}
public int getChancePrecipitation() {
return chancePrecipitation;
}
public void setChancePrecipitation(int chancePrecipitation) {
this.chancePrecipitation = chancePrecipitation;
}
public double getAmountPrecipitation() {
return amountPrecipitation;
}
public void setAmountPrecipitation(double amountPrecipitation) {
this.amountPrecipitation = amountPrecipitation;
}
}

View File

@ -0,0 +1,29 @@
package edu.utsa.cs3443.lakewatch.model;
import android.app.Application;
import android.content.SharedPreferences;
import android.graphics.Color;
import androidx.appcompat.app.AppCompatDelegate;
/**
* This class is referenced on line 6
* of the AndroidManifest.XML to implement
* dark mode universally within the app's views
* @author Gavin Diab
*/
public class userSettings extends Application {
@Override
public void onCreate() {
super.onCreate();
// Load the theme setting from SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("sharedPrefs", MODE_PRIVATE);
boolean isDarkModeOn = sharedPreferences.getBoolean("isDarkModeOn", false);
// Apply the theme setting
if (isDarkModeOn) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
}

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="50"
android:viewportHeight="50">
<path
android:pathData="M8.5,7.092l9.565,2.639 5.309,-3.731 1.847,0.455 -5.259,3.742 28.985,8.053 -2.121,7.882 -29.093,-8.031c-11.271,-3.399 -9.216,-11.009 -9.216,-11.009"
android:fillColor="?attr/colorControlNormal"/>
<path
android:pathData="M33.957,27.258c-0.035,-0.658 -0.16,-1.285 -0.375,-1.877l13.281,3.697 -0.426,1.639 -12.48,-3.459zM21.891,23.926c0.358,-0.521 0.782,-0.991 1.264,-1.398l-22.155,-6.12v1.763l20.891,5.755zM27.377,29.762c1.191,0 2.158,-0.969 2.158,-2.16 0,-1.195 -0.967,-2.162 -2.158,-2.162 -1.195,0 -2.161,0.967 -2.161,2.162 0,1.191 0.966,2.16 2.161,2.16zM49,43c-1.051,0 -2.051,-0.238 -2.943,-0.648 -0.928,-0.42 -1.963,-0.672 -3.047,-0.672 -1.08,0 -2.121,0.252 -3.035,0.672 -0.905,0.41 -1.903,0.648 -2.955,0.648 -1.051,0 -2.053,-0.238 -2.955,-0.648 -0.92,-0.42 -1.953,-0.672 -3.035,-0.672 -1.086,0 -2.119,0.252 -3.045,0.672 -0.893,0.41 -1.905,0.648 -2.951,0.648 -1.045,0 -2.051,-0.238 -2.949,-0.648 -0.926,-0.42 -1.967,-0.672 -3.046,-0.672 -1.08,0 -2.12,0.252 -3.035,0.672 -0.898,0.41 -1.909,0.648 -2.956,0.648 -1.045,0 -2.051,-0.238 -2.955,-0.648 -0.916,-0.42 -1.956,-0.672 -3.036,-0.672 -1.079,0 -2.119,0.252 -3.04,0.672 -0.897,0.41 -1.909,0.648 -2.949,0.648l-0.068,-17.605 24.227,6.686c-1.67,-0.807 -2.83,-2.5 -2.83,-4.479 0,-2.754 2.227,-4.983 4.979,-4.983 2.744,0 4.977,2.229 4.977,4.983 0,2.752 -2.232,4.98 -4.977,4.98l-0.49,-0.047 22.078,6.088 0.036,4.377z"
android:fillColor="?attr/colorControlNormal"/>
</vector>

View File

@ -0,0 +1,81 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#f2fbb7"
android:strokeColor="#000000"/>
<path
android:pathData="m92.23,143.09h327.89a10,10 45,0 1,10 10v227.89a10,10 135,0 1,-10 10L92.23,390.98a10,10 45,0 1,-10 -10L82.23,153.09a10,10 135,0 1,10 -10z"
android:strokeLineJoin="round"
android:strokeWidth="2.10845"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M87.39,135.48L424.96,135.48a10,10 45,0 1,10 10v17.57a10,10 135,0 1,-10 10L87.39,173.05a10,10 45,0 1,-10 -10v-17.57a10,10 135,0 1,10 -10z"
android:strokeLineJoin="round"
android:strokeWidth="2.42674"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M107.23,142.67a16.44,26.44 0,1 0,32.89 0a16.44,26.44 0,1 0,-32.89 0z"
android:strokeLineJoin="round"
android:strokeWidth="2.11426"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M372.23,142.67a16.44,26.44 0,1 0,32.89 0a16.44,26.44 0,1 0,-32.89 0z"
android:strokeLineJoin="round"
android:strokeWidth="2.11426"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m139.19,200h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m311.83,200h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m225.51,286.32h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m225.51,200h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m139.19,286.32h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="m311.83,286.32h61.32a4,4 45,0 1,4 4v61.32a4,4 135,0 1,-4 4h-61.32a4,4 45,0 1,-4 -4v-61.32a4,4 135,0 1,4 -4z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#000000"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#72F18A"
android:strokeColor="#000000"/>
<path
android:pathData="m345.65,142.86 l-136.43,136.43 -42.83,-42.83 -44.94,44.94 88.09,88.09 0.35,-0.35 44.59,-44.59h0L390.9,188.11Z"
android:strokeWidth="2"
android:fillColor="#ffffff"
android:strokeColor="#000000"/>
</vector>

View File

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#b7f8fb"
android:strokeColor="#000000"/>
<path
android:pathData="M147.58,131.93l232.62,0l0,232.62l-232.62,0z"
android:strokeLineJoin="round"
android:strokeWidth="7.96"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M132.15,147.8l232.62,0l0,232.62l-232.62,0z"
android:strokeLineJoin="round"
android:strokeWidth="7.96"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#cacaca"
android:strokeColor="#000000"/>
<path
android:pathData="m258.67,119.57q23.63,0 40.54,8.45 17.1,8.45 26.13,22.09 9.03,13.45 9.03,28.63 0,18.44 -6.92,30.16 -6.92,11.53 -17.29,19.6 -10.18,7.88 -20.56,15.56 -10.37,7.49 -17.48,17.68 -6.92,10.18 -6.92,26.13v13.26L232.73,301.13L232.73,285.95q0,-18.64 6.72,-30.93 6.92,-12.3 17.1,-20.94 10.18,-8.65 20.37,-15.95 10.18,-7.49 17.1,-16.14 6.92,-8.65 6.92,-21.33 0,-16.33 -13.06,-25.17 -13.06,-9.03 -32.47,-9.03 -13.64,0 -28.05,6.72 -14.41,6.53 -26.32,21.33l-23.06,-16.91q16.91,-19.79 37.08,-28.82 20.37,-9.22 43.61,-9.22zM249.83,341.29q11.14,0 18.64,7.49 7.49,7.49 7.49,18.06 0,10.76 -7.49,18.44 -7.49,7.49 -18.64,7.49 -10.76,0 -18.06,-7.49 -7.3,-7.69 -7.3,-18.44 0,-10.57 7.3,-18.06 7.3,-7.49 18.06,-7.49z"
android:strokeWidth="2"
android:fillColor="#ffffff"
android:strokeColor="#000000"/>
</vector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/circle_guess"
android:width="40dp"
android:height="40dp"
/>
</layer-list>

View File

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#d0b7fb"
android:strokeColor="#000000"/>
<path
android:pathData="M171.42,85 L213.79,169.85 256.17,254.69 298.55,169.85 340.93,85L256.17,85ZM256.17,257.66 L213.79,342.5 171.42,427.34L256.17,427.34 340.93,427.34l-42.38,-84.84z"
android:strokeLineJoin="round"
android:strokeWidth="6"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#bafbb7"
android:strokeColor="#000000"/>
<path
android:pathData="m159.28,190.03v227.07h65.16l0.41,-1.07L256.17,335.25l31.32,80.78 0.41,1.07h65.16L353.07,190.03Z"
android:strokeLineJoin="round"
android:strokeWidth="6.21387"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
<path
android:pathData="M256.17,192.14m-96.63,0a96.63,96.63 0,1 1,193.27 0a96.63,96.63 0,1 1,-193.27 0"
android:strokeLineJoin="round"
android:strokeWidth="6.73409"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512.35dp"
android:height="512.35dp"
android:viewportWidth="512.35"
android:viewportHeight="512.35">
<path
android:pathData="M256.17,256.17m-255.17,0a255.17,255.17 0,1 1,510.35 0a255.17,255.17 0,1 1,-510.35 0"
android:strokeWidth="2"
android:fillColor="#ff7f7f"
android:strokeColor="#000000"/>
<path
android:pathData="M325.85,129.86L255.11,200.6L185.43,130.92L140.95,175.39l69.68,69.68l-69.04,69.04l44.47,44.47l69.04,-69.04l70.1,70.1l44.47,-44.47l-70.1,-70.1l70.74,-70.75z"
android:strokeWidth="2"
android:fillColor="#ffffff"
android:strokeColor="#000000"/>
</vector>

View File

@ -0,0 +1,59 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M32,41L32,44"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M25.636,38.364L23.515,40.485"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M23,32L20,32"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M25.636,25.636L23.515,23.515"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M32,23L32,20"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M38.364,25.636L40.485,23.515"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M41,32L44,32"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M38.364,38.364L40.485,40.485"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffa500"
android:strokeLineCap="round"/>
<path
android:pathData="M32,32m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"
android:strokeWidth="2"
android:fillColor="#ffa500"
android:strokeColor="#ffa500"/>
</vector>

View File

@ -0,0 +1,170 @@
<?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="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="33.104dp"
android:height="24.037dp"
android:viewportWidth="33.104"
android:viewportHeight="24.037">
<path
android:pathData="M6.043,10.713A6,6 0,0 0,7.492 22.537L23.992,22.537a7.5,7.5 0,1 0,-1.755 -14.793l-2,0.543"
android:strokeLineJoin="round"
android:strokeWidth="3"
android:fillColor="?attr/colorControlNormal"
android:strokeColor="?attr/colorControlNormal"
android:strokeLineCap="round"/>
<path
android:pathData="M22.237,7.744a8.25,8.25 0,0 0,-16.194 2.97,7.142 7.142,0 0,0 0.7,2.073"
android:strokeLineJoin="round"
android:strokeWidth="3"
android:fillColor="?attr/colorControlNormal"
android:strokeColor="?attr/colorControlNormal"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="33dp"
android:height="37.5dp"
android:viewportWidth="33"
android:viewportHeight="37.5">
<path
android:pathData="M15.558,1.165 L5.109,12.661a1.623,1.623 0,0 0,1.2 2.714L8.063,15.375L2.902,20.536A1.591,1.591 0,0 0,4.027 23.25L6.375,23.25L1.13,29.543A1.653,1.653 0,0 0,2.402 32.25L14.25,32.25v2.25a2.25,2.25 0,0 0,4.5 0L18.75,32.25L30.598,32.25a1.653,1.653 0,0 0,1.273 -2.707L26.625,23.25h2.348a1.591,1.591 0,0 0,1.125 -2.714l-5.161,-5.161h1.751A1.625,1.625 0,0 0,28.313 13.75a1.6,1.6 0,0 0,-0.422 -1.09L17.442,1.165a1.277,1.277 0,0 0,-1.884 0Z"
android:strokeWidth="1.5"
android:fillColor="?attr/colorControlNormal"
android:strokeColor="?attr/colorControlNormal"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="360.5dp"
android:height="37.24dp"
android:viewportWidth="360.5"
android:viewportHeight="37.24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M360.14,23.7h0ZM60.38,20.31c21.45,0 25.6,3.39 60.02,3.39 35.15,0 37.67,-3.39 60.02,-3.39 21.45,0 25.6,3.39 60.02,3.39 35.15,0 37.67,-3.39 60.02,-3.39 21.45,0 25.24,3.32 59.66,3.39L360.14,16.93c-21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.67,3.39 -60.02,3.39 -21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.67,3.39 -60.02,3.39 -21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.67,3.39 -60.02,3.39L0,23.7c34.25,0 39.11,-3.39 60.38,-3.39ZM300.48,27.08c-35.15,0 -37.67,3.39 -60.02,3.39 -21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.85,3.39 -60.2,3.39S95.35,27.09 60.2,27.09 22.35,30.47 0,30.47v6.77c35.15,0 38.03,-3.39 60.2,-3.39 22.35,0 24.88,3.39 60.02,3.39s37.85,-3.39 60.2,-3.39c21.45,0 25.6,3.39 60.02,3.39 34.97,0 37.67,-3.39 60.02,-3.39 21.45,0 25.6,3.39 60.02,3.39L360.49,30.47c-22.35,0 -24.88,-3.39 -60.02,-3.39ZM60.38,6.77c21.45,0 25.6,3.39 60.02,3.39 35.15,0 37.67,-3.39 60.02,-3.39 21.45,0 25.6,3.39 60.02,3.39 35.15,0 37.67,-3.39 60.02,-3.39 21.45,0 25.24,3.32 59.66,3.39L360.14,3.39c-21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.67,3.39 -60.02,3.39 -21.45,0 -25.6,-3.39 -60.02,-3.39 -35.15,0 -37.67,3.39 -60.02,3.39 -21.45,0 -25.6,-3.39 -60.02,-3.39C24.88,0 22.35,3.39 0,3.39v6.77C34.25,10.16 39.11,6.77 60.38,6.77Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26.652dp"
android:height="17.46dp"
android:viewportWidth="26.652"
android:viewportHeight="17.46">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M0,12.36A5.1,5.1 0,0 1,3.972 7.392a6.091,6.091 0,0 1,6 -4.8,5.942 5.942,0 0,1 3.792,1.308 5.88,5.88 0,0 1,2.16 3.36h0.324a5.1,5.1 0,0 1,5.112 5.088,5.121 5.121,0 0,1 -5.112,5.112L5.124,17.46a4.836,4.836 0,0 1,-1.98 -0.408,5.328 5.328,0 0,1 -1.644,-1.068 5.333,5.333 0,0 1,-1.092 -1.632,4.933 4.933,0 0,1 -0.408,-1.992ZM1.74,12.36a3.228,3.228 0,0 0,0.984 2.352,3.27 3.27,0 0,0 2.388,0.984L16.248,15.696a3.262,3.262 0,0 0,2.388 -0.984,3.212 3.212,0 0,0 1,-2.352 3.148,3.148 0,0 0,-1 -2.352,3.289 3.289,0 0,0 -2.388,-0.984L14.58,9.024a0.159,0.159 0,0 1,-0.18 -0.18l-0.084,-0.588a4.363,4.363 0,0 0,-4.368 -3.936,4.267 4.267,0 0,0 -2.952,1.128 4.169,4.169 0,0 0,-1.416 2.808l-0.084,0.5c0,0.12 -0.06,0.18 -0.192,0.18l-0.54,0.084A3.228,3.228 0,0 0,2.592 10.092a3.367,3.367 0,0 0,-0.852 2.268ZM12.36,1.896c-0.12,0.108 -0.1,0.192 0.084,0.252a10.7,10.7 0,0 1,1.3 0.66c0.132,0.036 0.228,0.024 0.264,-0.036a3.7,3.7 0,0 1,6.252 2.34l0.108,0.768h1.7a2.747,2.747 0,0 1,2.016 0.84,2.77 2.77,0 0,1 0.1,3.876 2.83,2.83 0,0 1,-1.836 0.924c-0.12,0 -0.18,0.06 -0.18,0.192v1.356c0,0.132 0.06,0.192 0.18,0.192a4.577,4.577 0,0 0,4.308 -4.548,4.589 4.589,0 0,0 -4.584,-4.584h-0.18a5.588,5.588 0,0 0,-5.34 -4.128,5.27 5.27,0 0,0 -4.188,1.9Z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="360dp"
android:height="1dp"
android:viewportWidth="360"
android:viewportHeight="1">
<path
android:pathData="M0,0.5L360,0.5"
android:strokeWidth="1"
android:fillColor="?attr/colorControlNormal"
android:strokeColor="#707070"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="301.68dp"
android:height="82.76dp"
android:viewportWidth="301.68"
android:viewportHeight="82.76">
<path
android:strokeWidth="1"
android:pathData="M10.3,0.5L291.38,0.5A9.8,9.8 0,0 1,301.18 10.3L301.18,72.46A9.8,9.8 0,0 1,291.38 82.26L10.3,82.26A9.8,9.8 0,0 1,0.5 72.46L0.5,10.3A9.8,9.8 0,0 1,10.3 0.5z"
android:fillColor="#fff"
android:strokeColor="#231f20"/>
<path
android:strokeWidth="1"
android:pathData="M33.55,41.38h174.32H33.55Z"
android:fillColor="#00000000"
android:strokeColor="#231f20"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 KiB

View File

@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:fillColor="#FF000000"
android:pathData="M20.33,2a9.72,9.72 0,0 0,-6.12 2.17A5,5 0,0 0,6 7.59a7.08,7.08 0,0 0,-4 6.23v0.08H2v0a7,7 0,0 0,0.56 2.74,2.15 2.15,0 0,0 0.11,0.22A7.11,7.11 0,0 0,9.1 21H21.66a7.05,7.05 0,0 0,6 -3.32A9.38,9.38 0,0 0,30 11.5,9.6 9.6,0 0,0 20.33,2ZM11,5a3,3 0,0 1,1.8 0.6,9.58 9.58,0 0,0 -1.13,1.69 7.43,7.43 0,0 0,-2.48 -0.43,7.93 7.93,0 0,0 -1,0.07A3,3 0,0 1,11 5ZM26.11,16.42a0.71,0.71 0,0 0,-0.1 0.14A5.08,5.08 0,0 1,21.66 19H9.1a5.13,5.13 0,0 1,-4.62 -2.95l-0.05,-0.11 0,-0.1A4.74,4.74 0,0 1,4 14v-0.14a5.15,5.15 0,0 1,5.19 -5,5.27 5.27,0 0,1 2.52,0.64 1,1 0,0 0,0.83 0.05A1,1 0,0 0,13.13 9a7.68,7.68 0,0 1,7.2 -5A7.59,7.59 0,0 1,28 11.5,7.4 7.4,0 0,1 26.11,16.42Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M23.55,6.17a1,1 0,0 0,-1.1 1.66A4.59,4.59 0,0 1,24 12.76,1 1,0 0,0 24.76,14L25,14a1,1 0,0 0,1 -0.76A6.51,6.51 0,0 0,23.55 6.17Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M11,23a1,1 0,0 0,-1 1v5a1,1 0,0 0,2 0V24A1,1 0,0 0,11 23Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M16,23a1,1 0,0 0,-1 1v2.5a1,1 0,0 0,2 0V24A1,1 0,0 0,16 23Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21,23a1,1 0,0 0,-1 1v3.75a1,1 0,0 0,2 0V24A1,1 0,0 0,21 23Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="1920"
android:viewportHeight="1920">
<path
android:pathData="m1739.3,1293.4 l-105.8,180.8 -240.2,-80.2 -24.5,22.3c-69.9,63.6 -150.2,109.7 -238.6,136.8l-32.1,9.9 -49.5,244.1L835.6,1807.1l-49.5,-244.2 -32.1,-9.9c-88.4,-27.1 -168.7,-73.2 -238.6,-136.8l-24.5,-22.3 -240.2,80.2 -105.8,-180.8 189.7,-164.4 -7.5,-33c-10.4,-45.7 -15.6,-91.5 -15.6,-135.9 0,-44.4 5.2,-90.1 15.6,-135.9l7.5,-33 -189.7,-164.4 105.8,-180.8 240.2,80.1 24.5,-22.3c69.9,-63.6 150.2,-109.7 238.6,-136.9l32.1,-9.8 49.5,-244.1h213l49.5,244.2 32.1,9.8c88.4,27.2 168.7,73.2 238.6,136.9l24.5,22.3 240.2,-80.2 105.8,180.8 -189.7,164.4 7.5,33c10.4,45.7 15.6,91.5 15.6,135.9 0,44.4 -5.2,90.1 -15.6,135.9l-7.5,33 189.7,164.6ZM1685.6,960c0,-41.8 -3.8,-84.5 -11.6,-127.3l210.2,-182.1 -199.5,-340.9 -265.2,88.4c-67,-55.6 -143.3,-99.4 -223.9,-128.4L1141,0L743.2,0l-54.7,269.7c-81.4,29.1 -156.4,72.3 -224,128.4L199.5,309.8 0,650.7l210.1,182.1c-7.7,42.8 -11.5,85.5 -11.5,127.3 0,41.8 3.8,84.5 11.5,127.2L0,1269.4 199.5,1610.2l265.2,-88.5c67,55.7 143.3,99.4 223.9,128.5l54.7,269.8h397.8l54.7,-269.7c81.3,-29.3 156.4,-72.3 223.9,-128.5l265.2,88.5 199.5,-340.9 -210.2,-182.2c7.8,-42.8 11.6,-85.5 11.6,-127.3ZM942.1,564.7C724.1,564.7 546.8,742 546.8,960c0,218 177.3,395.3 395.3,395.3 218,0 395.3,-177.3 395.3,-395.3 0,-218 -177.3,-395.3 -395.3,-395.3m0,677.6c-155.6,0 -282.4,-126.7 -282.4,-282.4s126.7,-282.4 282.4,-282.4S1224.4,804.4 1224.4,960s-126.7,282.4 -282.4,282.4"
android:fillColor="?attr/colorControlNormal"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- No fill color -->
<solid android:color="@android:color/transparent"/>
<!-- Border style -->
<stroke android:width="1dp" android:color="#000000"/>
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" /> <!-- Cell background color -->
<stroke android:width="1dp" android:color="#000000" /> <!-- Border color and width -->
</shape>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16,13.385C16,14.609 15.526,15.783 14.682,16.648C14.203,17.14 13.627,17.509 13,17.736M19,13.692C19,7.115 12,2 12,2C12,2 5,7.115 5,13.692C5,15.63 5.738,17.489 7.05,18.86C8.363,20.23 10.144,20.999 12,20.999C13.857,20.999 15.637,20.23 16.95,18.859C18.263,17.489 19,15.63 19,13.692Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/colorControlNormal"
android:strokeLineCap="round"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="196.27dp"
android:height="25.32dp"
android:viewportWidth="196.27"
android:viewportHeight="25.32">
<path
android:strokeWidth="1"
android:pathData="M10.3,0.5L185.97,0.5A9.8,9.8 0,0 1,195.77 10.3L195.77,15.02A9.8,9.8 0,0 1,185.97 24.82L10.3,24.82A9.8,9.8 0,0 1,0.5 15.02L0.5,10.3A9.8,9.8 0,0 1,10.3 0.5z"
android:fillColor="?attr/colorControlNormal"
android:strokeColor="?attr/colorControlNormal"/>
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:pathData="M55.13,261.43c4.61,-4.72 9.61,-9.05 14.93,-12.96C54.27,232.77 44.49,211.05 44.49,187.03c0,-47.84 38.79,-86.63 86.63,-86.63c32.81,0 61.35,18.25 76.05,45.15c11.37,-7.76 23.87,-13.95 37.21,-18.3l0.64,-1.79c0.48,-1.32 0.34,-2.79 -0.35,-4c-0.71,-1.22 -1.91,-2.07 -3.29,-2.31l-32.66,-5.87c-1.96,-0.35 -3.5,-1.89 -3.86,-3.86l-5.87,-32.66c-0.25,-1.38 -1.09,-2.59 -2.31,-3.29c-1.21,-0.71 -2.67,-0.85 -4,-0.36l-31.22,11.21c-1.87,0.68 -3.97,0.12 -5.26,-1.4l-21.44,-25.33c-0.9,-1.07 -2.25,-1.69 -3.64,-1.69c-1.41,0 -2.74,0.62 -3.65,1.69L106.04,82.93c-1.29,1.53 -3.39,2.08 -5.27,1.42L69.55,73.13c-1.32,-0.48 -2.79,-0.35 -4.01,0.35c-1.22,0.7 -2.05,1.91 -2.31,3.29l-5.86,32.66c-0.36,1.97 -1.9,3.5 -3.86,3.86l-32.66,5.86c-1.39,0.25 -2.58,1.1 -3.29,2.31c-0.71,1.22 -0.84,2.68 -0.36,4.01l11.22,31.22c0.67,1.88 0.12,3.97 -1.41,5.27L1.69,183.39C0.62,184.29 0,185.63 0,187.03c0,1.41 0.62,2.74 1.69,3.65l25.33,21.44c1.53,1.29 2.08,3.39 1.41,5.27l-11.22,31.22c-0.48,1.33 -0.34,2.79 0.36,4.01c0.71,1.21 1.9,2.05 3.29,2.31l32.66,5.86C54.1,260.88 54.64,261.13 55.13,261.43z"
android:fillColor="?attr/colorControlNormal"/>
<path
android:pathData="M483.62,290.7c-14.77,-14.78 -34.42,-24.74 -56.25,-27.51c-1.9,-34.17 -16.4,-65.07 -39.1,-87.75c-24.35,-24.37 -58.13,-39.49 -95.31,-39.48c-34.83,-0.01 -66.68,13.26 -90.57,34.97c-20.55,18.65 -35.28,43.64 -41.23,71.84c-5.78,-0.96 -11.69,-1.5 -17.73,-1.5c-29.62,-0.01 -56.55,12.03 -75.95,31.46c-19.42,19.39 -31.46,46.33 -31.46,75.94c0,29.62 12.04,56.56 31.46,75.95c19.4,19.42 46.33,31.46 75.95,31.46H415.12c26.72,0 51.01,-10.86 68.5,-28.38c17.51,-17.49 28.39,-41.79 28.38,-68.5C512.01,332.49 501.14,308.18 483.62,290.7zM465.75,409.83c-13,12.98 -30.82,20.97 -50.63,20.98H143.44c-22.72,-0.01 -43.18,-9.17 -58.08,-24.06c-14.89,-14.9 -24.05,-35.35 -24.06,-58.08c0.01,-22.72 9.17,-43.18 24.06,-58.08c14.9,-14.88 35.36,-24.05 58.08,-24.06c8.48,0 16.62,1.28 24.29,3.66l14.73,4.55l1.58,-15.34c2.82,-27.57 15.88,-52.09 35.34,-69.77c19.48,-17.66 45.22,-28.4 73.59,-28.4c30.27,0 57.58,12.23 77.44,32.08c19.85,19.85 32.07,47.16 32.08,77.44c0,1.07 -0.04,2.31 -0.1,3.77l-0.48,13.59l13.42,-0.52c19.73,0.07 37.47,8.04 50.43,20.97c12.98,13 20.96,30.82 20.98,50.63C486.71,379.02 478.73,396.84 465.75,409.83z"
android:fillColor="?attr/colorControlNormal"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="82.8dp" android:viewportHeight="82.76" android:viewportWidth="301.68" android:width="301.8258dp">
<path android:fillColor="#fff" android:pathData="M10.3,0.5L291.38,0.5A9.8,9.8 0,0 1,301.18 10.3L301.18,72.46A9.8,9.8 0,0 1,291.38 82.26L10.3,82.26A9.8,9.8 0,0 1,0.5 72.46L0.5,10.3A9.8,9.8 0,0 1,10.3 0.5z" android:strokeColor="#231f20" android:strokeWidth="1"/>
<path android:fillColor="#fff" android:pathData="M242.39,41.38m-20.27,0a20.27,20.27 0,1 1,40.54 0a20.27,20.27 0,1 1,-40.54 0" android:strokeColor="#231f20" android:strokeWidth="1"/>
<path android:fillColor="#00000000" android:pathData="M33.55,41.38h174.32H33.55Z" android:strokeColor="#231f20" android:strokeWidth="1"/>
</vector>

View File

@ -0,0 +1,285 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BoatRampActivity">
<TextView
android:id="@+id/rampName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Ramp Name"
android:textColor="@color/textColor"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/rampImage"
android:layout_width="0dp"
android:layout_height="270dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:scaleType="fitXY"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rampName"
app:srcCompat="@mipmap/ic_launcher" />
<ScrollView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rampImage">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:id="@+id/statusCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
app:cardBackgroundColor="#E9E9E9"
app:cardCornerRadius="3000dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:fillViewport="true">
<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FFFFFF"
android:gravity="center"
android:text="Unknown"
android:textColor="@color/rampStatusText"
android:textSize="24sp" />
</HorizontalScrollView>
<ImageView
android:id="@+id/statusIcon"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/circle_guess" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/openTimes"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
app:cardCornerRadius="3000dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:fillViewport="true">
<TextView
android:id="@+id/openTimesText"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00FFFFFF"
android:gravity="center"
android:text="Unknown"
android:textAlignment="gravity"
android:textColor="@color/rampStatusText"
android:textSize="24sp" />
</HorizontalScrollView>
<ImageView
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/circle_hour_glass" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
app:cardCornerRadius="3000dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:fillViewport="true">
<TextView
android:id="@+id/addressText"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00FFFFFF"
android:gravity="center"
android:text="Unknown"
android:textAlignment="gravity"
android:textColor="@color/rampStatusText"
android:textSize="24sp" />
</HorizontalScrollView>
<ImageView
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/circle_copy" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/operator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
app:cardCornerRadius="3000dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:fillViewport="true">
<TextView
android:id="@+id/operatorText"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00FFFFFF"
android:gravity="center"
android:text="Unknown"
android:textAlignment="gravity"
android:textColor="@color/rampStatusText"
android:textSize="24sp" />
</HorizontalScrollView>
<ImageView
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/circle_ops" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/lastUpdated"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
app:cardCornerRadius="3000dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:fillViewport="true">
<TextView
android:id="@+id/lastUpdatedText"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#00FFFFFF"
android:gravity="center"
android:text="Unknown"
android:textAlignment="gravity"
android:textColor="@color/rampStatusText"
android:textSize="24sp" />
</HorizontalScrollView>
<ImageView
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/calendar" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:outlineProvider="none"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-black"
android:text="LAKEWATCH"
android:textSize="34sp"
android:textStyle="bold|italic"
android:textColor="@color/textColor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.125" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-black"
android:text="CANYON LAKE"
android:textSize="34sp"
android:textColor="@color/textColor"
android:textStyle="bold|italic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.177" />
<ImageView
android:id="@+id/imageView"
android:layout_width="45sp"
android:layout_height="48sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.136"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.281"
app:srcCompat="@drawable/icon_fa_solid_tree" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="45sp"
android:layout_height="48sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.89"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.281"
app:srcCompat="@drawable/icon_fa_solid_tree" />
<ImageView
android:id="@+id/imageView3"
android:layout_width="400sp"
android:layout_height="wrap_content"
android:scaleY="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.454"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.318"
app:srcCompat="@drawable/line_1" />
<ImageView
android:id="@+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="1.1"
android:scaleY="1.1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.49"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.981"
app:srcCompat="@drawable/icon_material_sharp_water" />
<ImageView
android:id="@+id/imageView5"
android:layout_width="40sp"
android:layout_height="45sp"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.706"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.023"
app:srcCompat="@drawable/icon_akar_cloud" />
<ImageView
android:id="@+id/imageView6"
android:layout_width="40sp"
android:layout_height="45sp"
android:layout_marginBottom="220sp"
android:rotationY="177"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.148"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.069"
app:srcCompat="@drawable/icon_akar_cloud" />
<ImageView
android:id="@+id/imageView7"
android:layout_width="35sp"
android:layout_height="45sp"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.252"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.018"
app:srcCompat="@drawable/icon_weather_cloudy" />
<ImageView
android:id="@+id/imageView8"
android:layout_width="35sp"
android:layout_height="45sp"
android:rotationY="182"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.617"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.051"
app:srcCompat="@drawable/icon_weather_cloudy" />
<Button
style="@style/BaseButtonStyle"
android:id="@+id/button"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="WEATHER"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.483"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.441"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<Button
android:id="@+id/button2"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="WATER STATUS"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/button"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/button"
app:layout_constraintVertical_bias="0.019"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<Button
android:id="@+id/button3"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="BOAT RAMPS"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="@+id/button2"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/button2"
app:layout_constraintTop_toBottomOf="@+id/button2"
app:layout_constraintVertical_bias="0.032"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<Button
android:id="@+id/settingsButton"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="SETTINGS"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imageView4"
app:layout_constraintEnd_toEndOf="@+id/button3"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/button3"
app:layout_constraintTop_toBottomOf="@+id/button3"
app:layout_constraintVertical_bias="0.049"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<ImageView
android:id="@+id/imageView9"
android:layout_width="75sp"
android:layout_height="100sp"
android:layout_marginTop="540dp"
android:rotationY="177"
app:layout_constraintBottom_toBottomOf="@+id/button3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.235"
app:layout_constraintStart_toEndOf="@+id/button3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="@drawable/boat_ramp_svgrepo_com" />
<ImageView
android:id="@+id/imageView11"
android:layout_width="75sp"
android:layout_height="100sp"
app:layout_constraintBottom_toBottomOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.922"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="@drawable/weather_symbol_4_svgrepo_com" />
<ImageView
android:id="@+id/imageView12"
android:layout_width="75sp"
android:layout_height="100sp"
app:layout_constraintBottom_toBottomOf="@+id/button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.922"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView11"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/water_drop_svgrepo_com" />
<ImageView
android:id="@+id/imageView14"
android:layout_width="75sp"
android:layout_height="100sp"
app:layout_constraintBottom_toBottomOf="@+id/settingsButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.235"
app:layout_constraintStart_toEndOf="@+id/settingsButton"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="@drawable/settings_2_svgrepo_com" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainRampMenuActivity">
<TextView
android:id="@+id/rampsOpen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="\?/\? Ramps Open"
android:textColor="@color/textColor"
android:textSize="34sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:id="@+id/rampListingScrollView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rampsOpen"
app:layout_constraintVertical_bias="0.0">
<LinearLayout
android:id="@+id/rampListing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SettingsActivity">
<ImageView
android:id="@+id/imageView3"
android:layout_width="400sp"
android:layout_height="wrap_content"
android:scaleY="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.454"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.318"
app:srcCompat="@drawable/line_1" />
<ImageView
android:id="@+id/imageView"
android:layout_width="45sp"
android:layout_height="48sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.136"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.281"
app:srcCompat="@drawable/icon_fa_solid_tree" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="45sp"
android:layout_height="48sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.89"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.281"
app:srcCompat="@drawable/icon_fa_solid_tree" />
<ImageView
android:id="@+id/imageView6"
android:layout_width="40sp"
android:layout_height="45sp"
android:layout_marginTop="52dp"
android:rotationY="177"
app:layout_constraintBottom_toTopOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.11"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/icon_akar_cloud" />
<ImageView
android:id="@+id/imageView7"
android:layout_width="35sp"
android:layout_height="45sp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="@+id/imageView6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.252"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/icon_weather_cloudy" />
<ImageView
android:id="@+id/imageView8"
android:layout_width="35sp"
android:layout_height="45sp"
android:rotationY="182"
app:layout_constraintBottom_toBottomOf="@+id/imageView6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.651"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView5"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="@drawable/icon_weather_cloudy" />
<ImageView
android:id="@+id/imageView5"
android:layout_width="40sp"
android:layout_height="45sp"
app:layout_constraintBottom_toTopOf="@+id/imageView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.77"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.08"
app:srcCompat="@drawable/icon_akar_cloud" />
<Button
style="@style/BaseButtonStyle"
android:id="@+id/button5"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="DARK MODE"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/imageView3"
app:layout_constraintVertical_bias="0.084"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-black"
android:text="SETTINGS"
android:textSize="40sp"
android:textStyle="bold|italic"
android:textColor="@color/textColor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.422"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.155" />
<ImageView
android:id="@+id/imageView14"
android:layout_width="75sp"
android:layout_height="100sp"
android:layout_marginTop="112dp"
app:layout_constraintBottom_toTopOf="@+id/imageView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.88"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/settings_2_svgrepo_com" />
<Button
style="@style/BaseButtonStyle"
android:id="@+id/button6"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="FORCE DATA FETCH"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button5"
app:layout_constraintVertical_bias="0.047"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<Button
style="@style/BaseButtonStyle"
android:id="@+id/button7"
android:layout_width="200sp"
android:layout_height="90sp"
android:fontFamily="sans-serif-black"
android:text="CLEAR CACHE"
android:textSize="25sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button6"
app:layout_constraintVertical_bias="0.065"
app:strokeColor="#000000"
app:strokeWidth="7sp" />
<ImageView
android:id="@+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleX="1.1"
android:scaleY="1.1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.49"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.981"
app:srcCompat="@drawable/icon_material_sharp_water" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WaterLevelActivity">
<ImageView
android:id="@+id/imageView10"
android:layout_width="376dp"
android:layout_height="251dp"
android:layout_marginStart="21dp"
android:layout_marginTop="341dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="182dp"
android:background="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.726"
app:srcCompat="@drawable/waterlevelgraph" />
<TableLayout
android:id="@+id/tableLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:background="@android:color/transparent"
android:padding="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TableRow>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:text="Percent Full"
android:textColor="@color/textColor" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:textColor="@color/textColor" />
</TableRow>
<TableRow>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:text="Mean Water Level (ft)"
android:textColor="@color/textColor" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:textColor="@color/textColor" />
</TableRow>
<TableRow>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:text="Surface Area (acres)"
android:textColor="@color/textColor" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/table_border_with_lines"
android:padding="8dp"
android:textColor="@color/textColor" />
</TableRow>
</TableLayout>
<TextView
android:id="@+id/your_text_view_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="92dp"
android:layout_marginTop="300dp"
android:layout_marginEnd="93dp"
android:layout_marginBottom="399dp"
android:text="Historical Water Data"
android:textColor="@color/textColor"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="16dp"
app:cardElevation="4dp"
app:cardBackgroundColor="@android:color/white"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<TextView
android:id="@+id/waterLevelTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WATER LEVEL"
android:textSize="20sp"
android:textColor="@color/textColor"
android:textStyle="bold"
android:gravity="center"/>
<TextView
android:id="@+id/waterLevelValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="36sp"
android:textColor="@color/textColor"
android:gravity="center"/>
<TextView
android:id="@+id/feetMsl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Feet MSL"
android:textSize="16sp"
android:textColor="@color/textColor"
android:gravity="center"/>
<TextView
android:id="@+id/dateTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/textColor"
android:gravity="center"
android:layout_marginTop="16dp"/>
<TextView
android:id="@+id/levelStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/textColor"
android:gravity="center"
android:layout_marginTop="16dp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WeatherActivity">
<ImageView
android:id="@+id/day_svg"
android:layout_width="409dp"
android:layout_height="212dp"
android:src="@drawable/day"
app:layout_constraintBottom_toTopOf="@id/weather_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.723" />
<TextView
android:id="@+id/weather_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:textColor="@color/textColor"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@id/temperature"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="44dp"
android:textColor="@color/textColor"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@id/wind_svg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/wind_svg"
android:layout_width="332dp"
android:layout_height="110dp"
android:src="@drawable/wind_svg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.615" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="16dp"
android:background="@android:color/transparent"
android:text="WIND"
android:textColor="#000000"
android:textSize="10dp"
app:layout_constraintStart_toStartOf="@id/wind_svg"
app:layout_constraintTop_toTopOf="@id/wind_svg" />
<TextView
android:id="@+id/wind_direction"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginStart="216dp"
android:background="@android:color/transparent"
android:gravity="center"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="@id/wind_svg"
app:layout_constraintLeft_toLeftOf="@id/wind_svg"
app:layout_constraintRight_toRightOf="@id/wind_svg"
app:layout_constraintStart_toStartOf="@id/wind_svg"
app:layout_constraintTop_toTopOf="@id/wind_svg"
app:layout_constraintVertical_bias="0.494" />
<TextView
android:id="@+id/wind_speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginTop="36dp"
android:textColor="#000000"
android:background="@android:color/transparent"
app:layout_constraintStart_toStartOf="@id/wind_svg"
app:layout_constraintTop_toTopOf="@id/wind_svg" />
<TextView
android:id="@+id/wind_gust"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="44dp"
android:layout_marginBottom="36dp"
android:background="@android:color/transparent"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="@id/wind_svg"
app:layout_constraintStart_toStartOf="@id/wind_svg" />
<ImageView
android:id="@+id/precipitation_svg"
android:layout_width="334dp"
android:layout_height="119dp"
android:src="@drawable/precipitation_svg"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.493"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/wind_svg"
app:layout_constraintVertical_bias="0.104" />
<ImageView
android:layout_width="55dp"
android:layout_height="49dp"
android:layout_marginStart="240dp"
android:layout_marginTop="36dp"
android:background="@android:color/transparent"
android:src="@drawable/reshot_icon_weather_yrq52ezutw"
app:layout_constraintStart_toStartOf="@id/precipitation_svg"
app:layout_constraintTop_toTopOf="@id/precipitation_svg" />
<TextView
android:id="@+id/chance_precipitation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="36dp"
android:layout_marginTop="40dp"
android:background="@android:color/transparent"
android:textColor="#000000"
app:layout_constraintStart_toStartOf="@id/precipitation_svg"
app:layout_constraintTop_toTopOf="@id/precipitation_svg" />
<TextView
android:id="@+id/amount_precipitation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="36dp"
android:layout_marginBottom="40dp"
android:background="@android:color/transparent"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="@id/precipitation_svg"
app:layout_constraintStart_toStartOf="@id/precipitation_svg" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="20dp"
android:background="@android:color/transparent"
android:text="PRECIPITATION"
android:textSize="10dp"
android:textColor="#000000"
app:layout_constraintStart_toStartOf="@id/precipitation_svg"
app:layout_constraintTop_toTopOf="@id/precipitation_svg" />
<Button
android:id="@+id/weather_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="weather.gov"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/precipitation_svg" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FFFFFF"
android:backgroundTint="#949494"
android:padding="16dp">
<androidx.cardview.widget.CardView
android:id="@+id/rampMenuCard"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:cardBackgroundColor="#E9E9E9"
app:cardCornerRadius="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:background="#00FFFFFF"
android:orientation="horizontal">
<ImageView
android:id="@+id/statusIcon"
android:layout_width="80dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:layout_weight="1"
android:background="#00FFFFFF"
app:srcCompat="@drawable/circle_guess" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:background="#00FFFFFF"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FFFFFF"
android:orientation="horizontal">
<TextView
android:id="@+id/rampName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:text="Unknown Ramp"
android:textAlignment="center"
android:textColor="#7F7F7F"
android:textSize="24sp"
android:textStyle="bold" />
</LinearLayout>
<View
android:id="@+id/divider2"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:background="#7F7F7F" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00FFFFFF"
android:orientation="horizontal">
<TextView
android:id="@+id/rampStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_weight="1"
android:background="#00FFFFFF"
android:text="Unknown Status"
android:textAlignment="center"
android:textColor="#7F7F7F"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,6 @@
<?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" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?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" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#BB86FC</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="backgroundColor">#08446F</color>
<color name="textColor">#FFFFFFFF</color>
<color name="buttonBackgroundColor">#9DCFED</color>
<color name="rampInfoText">#515151</color>
<color name="rampInfoBackground">#DAF0FD</color>
<color name="buttonTextColor">#FFFFFFFF</color>
<color name="rampStatusOpen">#C9FFD9</color>
<color name="rampStatusClosed">#FFCBC9</color>
<color name="rampStatusUnknown">#E9E9E9</color>
</resources>

View File

@ -0,0 +1,13 @@
<resources>
<style name="Theme.LakeWatch" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Other theme attributes -->
<item name="android:background">@color/backgroundColor</item> <!-- Set background color here -->
<item name="buttonStyle">@style/BaseButtonStyle</item>
</style>
<style name="BaseButtonStyle" parent="Widget.AppCompat.Button">
<item name="android:backgroundTint">@color/buttonBackgroundColor</item>
<item name="android:textColor">@color/buttonTextColor</item>
</style>
</resources>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary" >#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<!-- Normal/Light mode -->
<color name="backgroundColor">#ECF7FF</color>
<color name="textColor">#000000</color>
<color name="buttonBackgroundColor">#FFFFFF</color>
<color name="buttonTextColor">#000000</color>
<color name="rampInfoBackground">#FFFFFF</color>
<color name="rampStatusText">#8D8D8D</color>
<color name="rampInfoText">#8D8D8D</color>
<color name="rampStatusOpen">#C9FFD9</color>
<color name="rampStatusClosed">#FFCBC9</color>
<color name="rampStatusUnknown">#E9E9E9</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">LakeWatch</string>
</resources>

View File

@ -0,0 +1,12 @@
<resources>
<style name="Theme.LakeWatch" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Other theme attributes -->
<item name="android:background">@color/backgroundColor</item> <!-- Set background color here -->
<item name="buttonStyle">@style/BaseButtonStyle</item>
</style>
<style name="BaseButtonStyle" parent="Widget.AppCompat.Button">
<item name="android:backgroundTint">@color/buttonBackgroundColor</item>
<item name="android:textColor">@color/buttonTextColor</item>
</style>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,17 @@
package edu.utsa.cs3443.lakewatch;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
}

Some files were not shown because too many files have changed in this diff Show More