+ Made in the dungeons with great pain in PlantUML (Lab3,
+ zfp106)
+
+
+ Some notes on the decisions made here.
+
+
+
Question
+
Answer
+
+
+
Why does the MainActivity class not show it's dependency relationship with AppCompatActivity?
+
Because AppCompatActivity is coming from an external library, and as such not implemented by me.
+
+
+
Why do your concrete property classes (e.g. ResidentialProperty) not have toString() methods?
+
Because they inherit the toString() method from their parent class Property.
+
+
+
+
+
+
The actual UML diagram below:
+
+
+
+
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/.classpath b/Summer-2024/CS-3443/Labs/Lab3/app/.classpath
new file mode 100644
index 0000000..0a3280e
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/.gitignore b/Summer-2024/CS-3443/Labs/Lab3/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/build.gradle.kts b/Summer-2024/CS-3443/Labs/Lab3/app/build.gradle.kts
new file mode 100644
index 0000000..dc43bd9
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/build.gradle.kts
@@ -0,0 +1,43 @@
+plugins {
+ alias(libs.plugins.android.application)
+}
+
+android {
+ namespace = "edu.utsa.cs3443.zfp106_lab3"
+ compileSdk = 34
+
+ defaultConfig {
+ applicationId = "edu.utsa.cs3443.zfp106_lab3"
+ 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)
+}
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/proguard-rules.pro b/Summer-2024/CS-3443/Labs/Lab3/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/proguard-rules.pro
@@ -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
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/androidTest/java/edu/utsa/cs3443/zfp106_lab3/ExampleInstrumentedTest.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/androidTest/java/edu/utsa/cs3443/zfp106_lab3/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..e13fd96
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/androidTest/java/edu/utsa/cs3443/zfp106_lab3/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package edu.utsa.cs3443.zfp106_lab3;
+
+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 Testing documentation
+ */
+@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.zfp106_lab3", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/AndroidManifest.xml b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f67de15
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/assets/listings.csv b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/assets/listings.csv
new file mode 100644
index 0000000..a57f290
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/assets/listings.csv
@@ -0,0 +1,8 @@
+rp12345, 123 River Rd - San Antonio - TX, 350900, 400, 4, 3
+cp54321, 23412 Hill St - San Antonio - TX, 1500000, industrial, 1, 10
+rp67890, 34 Deer Ct - San Antonio - TX, 100000, 0, 1, 1
+rp09876, 109 Medina St - Boerne - TX, 249000, 0, 2, 3
+cp32145, 9867 Bend St - Selma - TX, 190000, office districts, 2, 15
+rp32145, 223 River Rd - San Antonio - TX, 270000, 500, 3, 2.5
+rp87690, 435 Bee Rd - San Antonio - TX, 3505000, 0, 10, 7
+cp90876, 123 Factory Dr - San Antonio - TX, 350000, office districts, 1, 12
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/MainActivity.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/MainActivity.java
new file mode 100644
index 0000000..59e6e83
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/MainActivity.java
@@ -0,0 +1,104 @@
+package edu.utsa.cs3443.zfp106_lab3;
+
+import android.os.Bundle;
+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;
+import edu.utsa.cs3443.zfp106_lab3.model.Listing;
+import edu.utsa.cs3443.zfp106_lab3.model.Property;
+
+/**
+ * The main activity for this Android Application
+ *
+ */
+public class MainActivity extends AppCompatActivity {
+
+ /**
+ * The primary driver for this program, handles the creation of the application
+ *
+ * @param savedInstanceState The saved instance state of the application
+ */
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Listing listing = Listing.loadProperties(this);
+ 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 propertyOneButton = findViewById(R.id.propertyButtonOne);
+ Property propertyOne = listing.getProperties().get(0);
+ propertyOneButton.setText(propertyOne.toString());
+ propertyOneButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast toast =
+ Toast.makeText(
+ view.getContext(),
+ String.valueOf("$" + propertyOne.getPrice()),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
+
+ Button propertyTwoButton = findViewById(R.id.propertyButtonTwo);
+ Property propertyTwo = listing.getProperties().get(1);
+ propertyTwoButton.setText(propertyTwo.toString());
+ propertyTwoButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast toast =
+ Toast.makeText(
+ view.getContext(),
+ String.valueOf("$" + propertyTwo.getPrice()),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
+
+ Button propertyThreeButton = findViewById(R.id.propertyButtonThree);
+ Property propertyThree = listing.getProperties().get(2);
+ propertyThreeButton.setText(propertyThree.toString());
+ propertyThreeButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast toast =
+ Toast.makeText(
+ view.getContext(),
+ String.valueOf("$" + propertyThree.getPrice()),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
+
+ Button propertyFourButton = findViewById(R.id.propertyButtonFour);
+ Property propertyFour = listing.getProperties().get(3);
+ propertyFourButton.setText(propertyFour.toString());
+ propertyFourButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast toast =
+ Toast.makeText(
+ view.getContext(),
+ String.valueOf("$" + propertyFour.getPrice()),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
+ }
+}
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/CommercialProperty.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/CommercialProperty.java
new file mode 100644
index 0000000..08eb15d
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/CommercialProperty.java
@@ -0,0 +1,82 @@
+package edu.utsa.cs3443.zfp106_lab3.model;
+
+/**
+ * A given Commercial Property
+ *
+ *
A commercial property, in addition to a normal property, has a zone, number of units, and number of parking spots
+ *
+ */
+public class CommercialProperty extends Property {
+ public String zone;
+ public Integer units;
+ public Integer parkingSpots;
+
+ /**
+ * Create a new Commercial Property
+ *
+ * @param id ID of the property
+ * @param address Address/location of the property
+ * @param price The price of the property
+ * @param zone The zone of the Commercial property
+ * @param units The number of units within the Commercial property
+ * @param parkingSpots The number of parking spots within the Commercial property
+ */
+ public CommercialProperty(
+ String id, String location, String price, String zone, Integer units, Integer parkingSpots) {
+ super(id, location, price);
+ }
+
+ /**
+ * Set the zone of the property
+ *
+ * @param newZone The new zone for the commercial property
+ */
+ public void setZone(String newZone) {
+ this.zone = newZone;
+ }
+
+ /**
+ * Get the zone of the commercial property
+ *
+ * @return The current zone of the Commercial property
+ */
+ public String getZone() {
+ return this.zone;
+ }
+
+ /**
+ * Set the number of units within the commercial property
+ *
+ * @param newUnits The new number of units for the commercial property
+ */
+ public void setUnits(Integer newUnits) {
+ this.units = newUnits;
+ }
+
+ /**
+ * Get the number of units of the commercial property
+ *
+ * @return The number of units in the commercial property
+ */
+ public Integer getUnits() {
+ return this.units;
+ }
+
+ /**
+ * Set the number of parking spots within the commercial property
+ *
+ * @param newParkingSpots The new number of parking spots for the commercial property
+ */
+ public void setParkingSpots(Integer newParkingSpots) {
+ this.parkingSpots = newParkingSpots;
+ }
+
+ /**
+ * Get the number of parking spots within the commercial property
+ *
+ * @return The number of parking spots within the commercial property
+ */
+ public Integer getParkingSpots() {
+ return this.parkingSpots;
+ }
+}
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Listing.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Listing.java
new file mode 100644
index 0000000..0123488
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Listing.java
@@ -0,0 +1,97 @@
+package edu.utsa.cs3443.zfp106_lab3.model;
+
+import android.content.res.AssetManager;
+import edu.utsa.cs3443.zfp106_lab3.MainActivity;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * A listing of properties with the ability to load them from an external csv file
+ *
+ */
+public class Listing {
+ public ArrayList properties;
+
+ /**
+ * Create a new listing of proeprties
+ *
+ * @param properties The listing of properties
+ */
+ public Listing(ArrayList properties) {
+ this.setProperties(properties);
+ }
+
+ /**
+ * Set the properties for the listing
+ *
+ * @param newProperties The new properties to set for the listing
+ */
+ public void setProperties(ArrayList newProperties) {
+ this.properties = newProperties;
+ }
+
+ /**
+ * Get the properties of the listing
+ *
+ * @return The properties of the listing
+ */
+ public ArrayList getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * Load properties from a "listings.csv" file and return a Listing
+ *
+ * @param activity The activity of the android application
+ * @return A new Listing of properties
+ * @throws throw new RuntimeException(e); If unable to read the properties listing
+ */
+ public static Listing loadProperties(MainActivity activity) {
+ AssetManager manager = activity.getAssets();
+ ArrayList properties = new ArrayList<>();
+ try {
+ InputStream file = manager.open("listings.csv");
+ Scanner scan = new Scanner(file);
+ while (scan.hasNextLine()) {
+ String line = scan.nextLine();
+ String[] propertyInfo = line.split(",");
+ String id = propertyInfo[0].trim();
+ String address = propertyInfo[1].trim();
+ String price = propertyInfo[2].trim();
+ Property property;
+ if (id.startsWith("rp")) {
+ Double hoaFees = Double.parseDouble(propertyInfo[3].trim());
+ Double bedrooms = Double.parseDouble(propertyInfo[4].trim());
+ Double bathrooms = Double.parseDouble(propertyInfo[5].trim());
+ property = new ResidentialProperty(id, address, price, hoaFees, bedrooms, bathrooms);
+ } else {
+ String zone = propertyInfo[3].trim();
+ Integer units = Integer.parseInt(propertyInfo[4].trim());
+ Integer parkingSpots = Integer.parseInt(propertyInfo[5].trim());
+ property = new CommercialProperty(id, address, price, zone, units, parkingSpots);
+ }
+ properties.add(property);
+ }
+ return new Listing(properties);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Return a single property given an address of the property
+ *
+ * @param address The address of the property
+ * @return The associated proprety with the address or null if not found
+ */
+ public Property getProperty(String address) {
+ for (Property property : this.getProperties()) {
+ if (property.getAddress().equals(address)) {
+ return property;
+ }
+ }
+ return null;
+ }
+}
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Property.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Property.java
new file mode 100644
index 0000000..95683c9
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/Property.java
@@ -0,0 +1,90 @@
+package edu.utsa.cs3443.zfp106_lab3.model;
+
+/**
+ * A given Property
+ *
+ *
A property has an id, address, and a price
+ *
+ */
+public abstract class Property {
+ private String id;
+ private String address;
+ private String price;
+
+ /**
+ * Create a new Property
+ *
+ * @param id ID of the property
+ * @param address Address/location of the property
+ * @param price The price of the property
+ */
+ public Property(String id, String address, String price) {
+ this.setId(id);
+ this.setAddress(address);
+ this.setPrice(price);
+ }
+
+
+ /**
+ * Get the string representation of the property
+ *
+ * @return The string representation of the property
+ */
+ public String toString() {
+ return this.getAddress();
+ }
+
+ /**
+ * Set the id of the property
+ *
+ * @param newId The new id to set for the property
+ */
+ public void setId(String newId) {
+ this.id = newId;
+ }
+
+ /**
+ * Get the id of the property
+ *
+ * @return The current id of the property
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Set the address for the property
+ *
+ * @param newAddress The new address for the property
+ */
+ public void setAddress(String newAddress) {
+ this.address = newAddress;
+ }
+
+ /**
+ * Get the address of the property
+ *
+ * @return The current address of the property
+ */
+ public String getAddress() {
+ return this.address;
+ }
+
+ /**
+ * Set the price for the property
+ *
+ * @param price The new price for the property
+ */
+ public void setPrice(String price) {
+ this.price = price;
+ }
+
+ /**
+ * Get the price of the property
+ *
+ * @return The current price of the property
+ */
+ public String getPrice() {
+ return this.price;
+ }
+}
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/ResidentialProperty.java b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/ResidentialProperty.java
new file mode 100644
index 0000000..bd35e4e
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/java/edu/utsa/cs3443/zfp106_lab3/model/ResidentialProperty.java
@@ -0,0 +1,85 @@
+package edu.utsa.cs3443.zfp106_lab3.model;
+
+/**
+ * A given Residential Property
+ *
+ *
A residential property, in addition to a normal property, has HOA fees, a number of bedrooms, and a number of bathrooms
+ *
+ */
+public class ResidentialProperty extends Property {
+ private Double hoaFees;
+ private Double bedrooms;
+ private Double bathrooms;
+
+ /**
+ * Create a new Residential Property
+ *
+ * @param id ID of the property
+ * @param address Address/location of the property
+ * @param price The price of the property
+ * @param hoaFees The annual HOA fees for the property
+ * @param bedrooms The number of bedrooms for the property
+ * @param bathrooms The number of bathrooms for the property
+ */
+ public ResidentialProperty(
+ String id, String location, String price, Double hoaFees, Double bedrooms, Double bathrooms) {
+ super(id, location, price);
+ this.hoaFees = hoaFees;
+ this.bedrooms = bedrooms;
+ this.bathrooms = bathrooms;
+ }
+
+ /**
+ * Get the annual HOA fees owed by the property
+ *
+ * @return The annual HOA fees owed by the property
+ */
+ public Double getHoaFees() {
+ return this.hoaFees;
+ }
+
+ /**
+ * Set the annual HOA fees owed for this property
+ *
+ * @param newHoaFees The annual HOA fees owed for this property
+ */
+ public void setHoaFees(Double newHoaFees) {
+ this.hoaFees = newHoaFees;
+ }
+
+ /**
+ * Get the number of bedrooms of this property
+ *
+ * @return The number of bedrooms of this property
+ */
+ public Double getBedrooms() {
+ return this.bedrooms;
+ }
+
+ /**
+ * Set the number of bedrooms for this property
+ *
+ * @param newBedrooms The number of bedrooms for this property
+ */
+ public void setBedrooms(Double newBedrooms) {
+ this.bedrooms = newBedrooms;
+ }
+
+ /**
+ * Get the number of bathrooms for this property
+ *
+ * @return The number of bathrooms for this property
+ */
+ public Double getBathrooms() {
+ return this.bathrooms;
+ }
+
+ /**
+ * Set the number of bathrooms for this property
+ *
+ * @param newBathrooms The number of bathrooms for this property
+ */
+ public void setBathrooms(Double newBathrooms) {
+ this.bathrooms = newBathrooms;
+ }
+}
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_background.xml b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_foreground.xml b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/logo.jpeg b/Summer-2024/CS-3443/Labs/Lab3/app/src/main/res/drawable/logo.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..60f28fc998e6476400a0f245231816d2e5592e26
GIT binary patch
literal 32737
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